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 )