diff --git a/include/pandio/core.h b/include/pandio/core.h index be09bef..b90fba2 100644 --- a/include/pandio/core.h +++ b/include/pandio/core.h @@ -16,9 +16,12 @@ typedef HMODULE pd_dlib_t; typedef CRITICAL_SECTION pd_mutex_t; typedef CONDITION_VARIABLE pd_cond_t; typedef HANDLE pd_thread_t; +typedef INIT_ONCE pd_once_t; typedef DWORD pd_errno_t; // system error type typedef DWORD pd_pid_t; +#define PD_ONCE_INIT INIT_ONCE_STATIC_INIT + #else #include #include @@ -29,8 +32,11 @@ typedef void* pd_dlib_t; typedef pthread_mutex_t pd_mutex_t; typedef pthread_cond_t pd_cond_t; typedef pthread_t pd_thread_t; +typedef pthread_once_t pd_once_t; typedef int pd_errno_t; // system error type typedef pid_t pd_pid_t; + +#define PD_ONCE_INIT PTHREAD_ONCE_INIT #endif int pd_random(void *, size_t); @@ -59,6 +65,9 @@ void pd_thread_create(pd_thread_t*, void* (*)(void*), void *); void pd_thread_join(pd_thread_t*); +/* call specific function only once in multithreaded environment */ +int pd_once(pd_once_t*, void (*)(void)); + struct pd_notifier_s; struct pd_io_s { diff --git a/samples/random.c b/samples/random.c index a4edc1b..c058062 100644 --- a/samples/random.c +++ b/samples/random.c @@ -3,6 +3,13 @@ #define n 16 +void print_bytes(unsigned char *bytes, size_t size) { + for (size_t i = 0; i < size; i++) { + printf("%02x ", bytes[i]); + } + printf("\n"); +} + int main() { unsigned char buf[n]; int status = pd_random(buf, 16); @@ -12,10 +19,15 @@ int main() { return 1; } - for (size_t i = 0; i < n; i++) { - printf("%02x ", buf[i]); + print_bytes(buf, n); + + unsigned char *buf2 = malloc(sizeof(unsigned char) * n); + if ((status = pd_random(buf2, n)) == 0) { + print_bytes(buf2, n); + } else { + printf("error: %s\n", pd_errstr(status)); + return 1; } - printf("\n"); return 0; } diff --git a/src/random.c b/src/random.c index 8760e67..790a90c 100644 --- a/src/random.c +++ b/src/random.c @@ -26,21 +26,14 @@ HCRYPTPROV hProv = 0; -bool initialized = false; -int pd__init_random_once() { - if (initialized) - return 0; - - initialized = true; - if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - return -1; - } - - return 0; +pd_once_t init_control = PD_ONCE_INIT; +void pd__init_random_once(void) { + // TODO: handle this error + CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); } int pd_random(void *bytes, size_t size) { - if (pd__init_random_once() == -1) + if (pd_once(&init_control, pd__init_random_once) == -1) return PD_UNKNOWN; if (size == 0) @@ -60,6 +53,7 @@ int pd_random(void *bytes, size_t size) { if (size == 0) return 0; + // TODO: maybe use pd_once as well to get fd only once? int fd = open("/dev/urandom", O_RDONLY); if (fd == -1) { return pd_errno(); diff --git a/src/sys/thread_unix.c b/src/sys/thread_unix.c index 9b78231..6a6e705 100644 --- a/src/sys/thread_unix.c +++ b/src/sys/thread_unix.c @@ -87,3 +87,11 @@ void pd_thread_create(pd_thread_t *thread, void* (func)(void*), void *args) { void pd_thread_join(pd_thread_t *thread) { pthread_join(*thread, NULL); } + +int pd_once(pd_once_t *once_control, void (*init_routine)(void)) { + int errcode = pthread_once(once_control, init_routine); + if (errcode) + return pd_errmap(errcode); + + return 0; +} diff --git a/src/sys/thread_win32.c b/src/sys/thread_win32.c index 7b4c03e..e31aeac 100644 --- a/src/sys/thread_win32.c +++ b/src/sys/thread_win32.c @@ -20,6 +20,7 @@ */ #include "pandio/core.h" +#include "pandio/err.h" #include @@ -108,3 +109,16 @@ void pd_thread_create(pd_thread_t *thread, void* (func)(void*), void *arg) { void pd_thread_join(pd_thread_t *thread) { WaitForSingleObject(*thread, INFINITE); } + +BOOL pd__init_once(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) { + void (*init_routine)(void) = Parameter; + init_routine(); + return TRUE; +} + +int pd_once(pd_once_t *once_control, void (*init_routine)(void)) { + if (InitOnceExecuteOnce(once_control, pd__init_once, init_routine, NULL)) + return 0; + + return pd_errno(); +}