diff --git a/lib/base/heimbase.c b/lib/base/heimbase.c index 8f5694d27..5642b1cd3 100644 --- a/lib/base/heimbase.c +++ b/lib/base/heimbase.c @@ -369,12 +369,23 @@ void heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *)) { #if defined(WIN32) - if (InterlockedCompareExchange(&once->started, 1L, 0L) == 0L) { - once->running = 1L; + /* + * State 0 means that func() has never executed. + * State 1 means that func() is executing. + * State 2 means that func() has completed execution. + */ + if (InterlockedCompareExchange(&once->state, 1L, 0L) == 0L) { + /* State is now 1 */ (*func)(ctx); - once->running = 0L; + (void)InterlockedExchange(&once->state, 2L); + /* State is now 2 */ } else { - while (once->running) + /* + * The InterlockedCompareExchange is being used to fetch + * the current state under a full memory barrier. As long + * as the current state is 1 continue to spin. + */ + while (InterlockedCompareExchange(&once->state, 2L, 0L) == 1L) SwitchToThread(); } #elif defined(HAVE_DISPATCH_DISPATCH_H) diff --git a/lib/base/heimbase.h b/lib/base/heimbase.h index c617a6344..7a4ec385d 100644 --- a/lib/base/heimbase.h +++ b/lib/base/heimbase.h @@ -58,10 +58,9 @@ typedef heim_object_t heim_bool_t; typedef heim_object_t heim_null_t; #if defined(WIN32) typedef struct { - LONG started; - LONG running; + LONG state; } heim_base_once_t; -# define HEIM_BASE_ONCE_INIT {0L, 0L} +# define HEIM_BASE_ONCE_INIT {0L} #else # define HEIM_BASE_ONCE_INIT 0 typedef long heim_base_once_t; /* XXX arch dependant */