(file) Return to once.c CVS log (file) (dir) Up to [OMI] / omi / pal

File: [OMI] / omi / pal / once.c (download)
Revision: 1.1, Mon Apr 20 17:19:55 2015 UTC (9 years ago) by krisbash
Branch: MAIN
CVS Tags: OMI_1_0_8_2, OMI_1_0_8_1, HEAD
OMI 1.0.8-1

#include "once.h"
#include "atomic.h"
#include "lock.h"

int __Once_Invoke(
    _Inout_ Once* self,
    _In_ OnceWorkerFunction func,
    _In_ void* data)
{
    volatile ptrdiff_t *state = (volatile ptrdiff_t*)&self->value;
    ptrdiff_t key = (ptrdiff_t)self;
    ptrdiff_t swapState;
    ptrdiff_t oldState;

start:
    swapState = Atomic_CompareAndSwap(
        state,
        ONCE_STATE_NOTINVOKEDYET,
        ONCE_STATE_INVOKING);

    if (swapState == ONCE_STATE_NOTINVOKEDYET)
    {
        /* This thread changed state to ONCE_STATE_INVOKING. */
        void* value;
        int result = (*func)(data, &value);
        *state = (result == 0) ? (ptrdiff_t)value : ONCE_STATE_NOTINVOKEDYET;
            
        CondLock_Broadcast(key);
        return result;
    }

    for(;;)
    {
        oldState = *state;
        if (oldState == ONCE_STATE_INVOKING)
            CondLock_Wait(
                    key,
                    state,
                    ONCE_STATE_INVOKING,
                    CONDLOCK_DEFAULT_SPINCOUNT);
        else if (oldState == ONCE_STATE_NOTINVOKEDYET)
            goto start;
        else return 0;
    }
}

ViewCVS 0.9.2