Crypt-SecretBuffer
view release on metacpan or search on metacpan
secret_buffer_async_write.c view on Meta::CPAN
secret_buffer_async_result *result= (secret_buffer_async_result *)
malloc(sizeof(secret_buffer_async_result) + count);
Zero(((char*)result), sizeof(secret_buffer_async_result) + count, char);
result->fd= fd >= 0? dup(fd) : -1;
if (result->fd < 0) {
free(result);
croak_with_syserror("dup", errno);
}
pthread_mutex_init(&result->mutex, NULL);
pthread_cond_init(&result->cond, NULL);
#endif
result->ready= result->started= false;
if (count)
memcpy(buf->data + ofs, result->secret, count);
result->secret_len= count;
result->refcount= 1;
return result;
}
/* One refcount is held by the main thread, and one by the worker thread */
static void secret_buffer_async_result_release(secret_buffer_async_result *result, bool from_thread) {
bool destroy= false, cleanup_thread_half= false, cleanup_perl_half= false;
ASYNC_RESULT_MUTEX_LOCK(result);
if (from_thread) {
cleanup_thread_half= true;
destroy= --result->refcount == 0;
} else {
/* check whether thread exited without cleaning up, and dec refcount if so */
if (!result->ready && !ASYNC_RESULT_IS_THREAD_ALIVE(result)) {
dTHX;
warn("writer thread died without cleaning up");
cleanup_thread_half= true;
result->ready= true;
--result->refcount;
}
destroy= --result->refcount == 0;
cleanup_perl_half= destroy || (!result->ready && result->refcount == 1);
}
if (cleanup_thread_half) {
result->ready= true;
secret_buffer_wipe(result->secret, result->secret_len);
#ifdef WIN32
if (result->fd != INVALID_HANDLE_VALUE)
CloseHandle(result->fd);
result->fd= INVALID_HANDLE_VALUE;
#else
if (result->fd >= 0)
close(result->fd);
result->fd= -1;
#endif
}
if (cleanup_perl_half) {
/* Detach so resources are freed on exit */
#ifdef WIN32
CloseHandle(result->threadHandle);
#else /* POSIX */
pthread_detach(result->threadHandle); /* Parent continues without waiting for child */
#endif
}
ASYNC_RESULT_MUTEX_UNLOCK(result);
/* can't destroy mutexes while locked */
if (destroy) {
#ifdef WIN32
DeleteCriticalSection(&result->cs);
CloseHandle(result->startEvent);
CloseHandle(result->readyEvent);
if (result->fd != INVALID_HANDLE_VALUE)
CloseHandle(result->fd);
GlobalFree(result);
#else
pthread_mutex_destroy(&result->mutex);
pthread_cond_destroy(&result->cond);
free(result);
#endif
}
}
static void secret_buffer_async_result_acquire(secret_buffer_async_result *result) {
ASYNC_RESULT_MUTEX_LOCK(result);
++result->refcount;
ASYNC_RESULT_MUTEX_UNLOCK(result);
}
static int secret_buffer_async_result_magic_free(pTHX_ SV *sv, MAGIC *mg) {
secret_buffer_async_result_release((secret_buffer_async_result *) mg->mg_ptr, false);
return 0;
}
#ifdef USE_ITHREADS
int secret_buffer_async_result_magic_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *p) {
secret_buffer_async_result_acquire((secret_buffer_async_result *) mg->mg_ptr);
return 0;
}
#endif
void secret_buffer_async_result_send(secret_buffer_async_result *result, IV os_err) {
ASYNC_RESULT_MUTEX_LOCK(result);
result->os_err= os_err;
result->ready= true;
#ifdef WIN32
SetEvent(result->readyEvent);
#else
pthread_cond_signal(&result->cond);
#endif
ASYNC_RESULT_MUTEX_UNLOCK(result);
}
bool secret_buffer_async_result_recv(secret_buffer_async_result *result, IV timeout_msec, IV *total_written, IV *os_err) {
bool ready= false;
#ifdef WIN32
DWORD ret = WaitForSingleObject(result->readyEvent, timeout_msec < 0? INFINITE : timeout_msec);
if (ret == WAIT_TIMEOUT)
return false;
if (ret != WAIT_OBJECT_0)
croak_with_syserror("WaitForSingleObject", GetLastError());
ready= true;
ASYNC_RESULT_MUTEX_LOCK(result);
#else
struct timespec ts;
/* timedwait operates on absolute wallclock time
* This is sort of dangerous since wallclock time can change... but the only
* alternative I see would be to play with the alarm signal.
( run in 1.703 second using v1.01-cache-2.11-cpan-39bf76dae61 )