#define PTHREAD_ONCE_INIT { 0, 0, 0, 0} enum ptw32_once_state { PTW32_ONCE_INIT = 0x0, PTW32_ONCE_STARTED = 0x1, PTW32_ONCE_DONE = 0x2 }; struct pthread_once_t_ { int state; int reserved; int numSemaphoreUsers; HANDLE semaphore; }; static void PTW32_CDECL ptw32_once_init_routine_cleanup(void * arg) { pthread_once_t * once_control = (pthread_once_t *) arg; (void) PTW32_INTERLOCKED_EXCHANGE((LPLONG)&once_control->state, (LONG)PTW32_ONCE_INIT); if (InterlockedExchangeAdd((LPLONG)&once_control->semaphore, 0L)) /* MBR fence */ { ReleaseSemaphore(once_control->semaphore, 1, NULL); } } int pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) { int result; int state; HANDLE sema; if (once_control == NULL || init_routine == NULL) { result = EINVAL; goto FAIL0; } else { result = 0; } while ((state = PTW32_INTERLOCKED_COMPARE_EXCHANGE( (PTW32_INTERLOCKED_LPLONG)&once_control->state, (PTW32_INTERLOCKED_LONG)PTW32_ONCE_STARTED, (PTW32_INTERLOCKED_LONG)PTW32_ONCE_INIT)) != PTW32_ONCE_DONE) { if (PTW32_ONCE_INIT == state) { #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(ptw32_once_init_routine_cleanup, (void *) once_control); (*init_routine)(); pthread_cleanup_pop(0); #ifdef _MSC_VER #pragma inline_depth() #endif (void) PTW32_INTERLOCKED_EXCHANGE((LPLONG)&once_control->state, (LONG)PTW32_ONCE_DONE); /* * we didn't create the semaphore. * it is only there if there is someone waiting. */ if (InterlockedExchangeAdd((LPLONG)&once_control->semaphore, 0L)) /* MBR fence */ { ReleaseSemaphore(once_control->semaphore, once_control->numSemaphoreUsers, NULL); } } else { InterlockedIncrement((LPLONG)&once_control->numSemaphoreUsers); if (!InterlockedExchangeAdd((LPLONG)&once_control->semaphore, 0L)) /* MBR fence */ { sema = CreateSemaphore(NULL, 0, INT_MAX, NULL); if (PTW32_INTERLOCKED_COMPARE_EXCHANGE( (PTW32_INTERLOCKED_LPLONG)&once_control->semaphore, (PTW32_INTERLOCKED_LONG)sema, (PTW32_INTERLOCKED_LONG)0)) { CloseHandle(sema); } } /* * Check 'state' again in case the initting thread has finished or cancelled and left before seeing that there was a semaphore. */ if (InterlockedExchangeAdd((LPLONG)&once_control->state, 0L) == PTW32_ONCE_STARTED) { WaitForSingleObject(once_control->semaphore, INFINITE); } if (0 == InterlockedDecrement((LPLONG)&once_control->numSemaphoreUsers)) { /* we were last */ if ((sema = (HANDLE) PTW32_INTERLOCKED_EXCHANGE( (LPLONG)&once_control->semaphore, (LONG)0))) { CloseHandle(sema); } } } } /* * ------------ * Failure Code * ------------ */ FAIL0: return (result); } /* pthread_once */