1 krisbash 1.1 #include "once.h"
2 #include "atomic.h"
3 #include "lock.h"
4
5 int __Once_Invoke(
6 _Inout_ Once* self,
7 _In_ OnceWorkerFunction func,
8 _In_ void* data)
9 {
10 volatile ptrdiff_t *state = (volatile ptrdiff_t*)&self->value;
11 ptrdiff_t key = (ptrdiff_t)self;
12 ptrdiff_t swapState;
13 ptrdiff_t oldState;
14
15 start:
16 swapState = Atomic_CompareAndSwap(
17 state,
18 ONCE_STATE_NOTINVOKEDYET,
19 ONCE_STATE_INVOKING);
20
21 if (swapState == ONCE_STATE_NOTINVOKEDYET)
22 krisbash 1.1 {
23 /* This thread changed state to ONCE_STATE_INVOKING. */
24 void* value;
25 int result = (*func)(data, &value);
26 *state = (result == 0) ? (ptrdiff_t)value : ONCE_STATE_NOTINVOKEDYET;
27
28 CondLock_Broadcast(key);
29 return result;
30 }
31
32 for(;;)
33 {
34 oldState = *state;
35 if (oldState == ONCE_STATE_INVOKING)
36 CondLock_Wait(
37 key,
38 state,
39 ONCE_STATE_INVOKING,
40 CONDLOCK_DEFAULT_SPINCOUNT);
41 else if (oldState == ONCE_STATE_NOTINVOKEDYET)
42 goto start;
43 krisbash 1.1 else return 0;
44 }
45 }
|