base: correct Windows heim_base_once_f semantics
As implemented by Jeffrey Altman heim_base_once_f() is a variant of the "double-checked gate lock pattern". Full memory barriers must be used when determining whether or not to call SwitchToThread(). Change-Id: I2f8446a56c50a37c921d6e993433c9a3f7488f50
This commit is contained in:

committed by
Jeffrey Altman

parent
4735faba59
commit
cc0e92a3c3
@@ -369,12 +369,23 @@ void
|
|||||||
heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *))
|
heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *))
|
||||||
{
|
{
|
||||||
#if defined(WIN32)
|
#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);
|
(*func)(ctx);
|
||||||
once->running = 0L;
|
(void)InterlockedExchange(&once->state, 2L);
|
||||||
|
/* State is now 2 */
|
||||||
} else {
|
} 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();
|
SwitchToThread();
|
||||||
}
|
}
|
||||||
#elif defined(HAVE_DISPATCH_DISPATCH_H)
|
#elif defined(HAVE_DISPATCH_DISPATCH_H)
|
||||||
|
@@ -58,10 +58,9 @@ typedef heim_object_t heim_bool_t;
|
|||||||
typedef heim_object_t heim_null_t;
|
typedef heim_object_t heim_null_t;
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
LONG started;
|
LONG state;
|
||||||
LONG running;
|
|
||||||
} heim_base_once_t;
|
} heim_base_once_t;
|
||||||
# define HEIM_BASE_ONCE_INIT {0L, 0L}
|
# define HEIM_BASE_ONCE_INIT {0L}
|
||||||
#else
|
#else
|
||||||
# define HEIM_BASE_ONCE_INIT 0
|
# define HEIM_BASE_ONCE_INIT 0
|
||||||
typedef long heim_base_once_t; /* XXX arch dependant */
|
typedef long heim_base_once_t; /* XXX arch dependant */
|
||||||
|
Reference in New Issue
Block a user