c-pal/common/devdoc/callonce_requirements.md

3.0 KiB

call_once requirements

================

Overview

call_once is a module that provides a pair of functions callonce_begin/callonce_end to be used to have some code executed just once.

Typical usage is:


call_once_t wasInit = CALL_ONCE_NOT_CALLED;

...

void initialize(...)
{
    /*one time attempt*/
    if(call_once_begin(&wasInit) == CALL_ONCE_PROCEED)
    {
        /*here is user code called from 1 thread, this one*/
        call_once_end(&wasInit, true); /*or call_once_end(&wasInit, false)*/
    }
}

or

void initialize(...)
{
    /*with retries.. */
    while(call_once_begin(&wasInit) == CALL_ONCE_PROCEED)
    {
        /*here is user code called from 1 thread, this one*/
        call_once_end(&wasInit, true); /*or call_once_end(&wasInit, false)*/
    }
}

References

Exposed API

#define CALL_ONCE_NOT_CALLED 0 /*to only be used in static initialization, rest of initializations need to use interlocked_exchange*/

#define CALL_ONCE_RESULT_VALUES \
    CALL_ONCE_PROCEED, \
    CALL_ONCE_ALREADY_CALLED \

    MOCKABLE_FUNCTION(, CALL_ONCE_RESULT, call_once_begin, call_once_t*, state);
    MOCKABLE_FUNCTION(, void, call_once_end, call_once_t*, state, bool, success);

call_once_begin, call_once_t*, state);

MOCKABLE_FUNCTION(, CALL_ONCE_RESULT, call_once_begin, call_once_t*, state);

call_once_begin returns CALL_ONCE_PROCEED when the user is allowed to call the "execute once" code.

SRS_CALL_ONCE_02_001: [ call_once_begin shall use interlocked_compare_exchange(state, 1, 0) to determine if user has alredy indicated that the init code was executed with success. ]

SRS_CALL_ONCE_02_002: [ If interlocked_compare_exchange returns 2 then call_once_begin shall return CALL_ONCE_ALREADY_CALLED. ]

SRS_CALL_ONCE_02_003: [ If interlocked_compare_exchange returns 1 then call_once_begin shall call wait_on_address(state) with timeout UINT32_MAX and call again interlocked_compare_exchange(state, 1, 0). ]

SRS_CALL_ONCE_02_004: [ If interlocked_compare_exchange returns 0 then call_once_begin shall return CALL_ONCE_PROCEED. ]

call_once_end

MOCKABLE_FUNCTION(, void, call_once_end, call_once_t*, state, bool, success);

call_once_end is called by the user to signal a succesful or failure of the call once code. If success is false then state is reset to its initialized state thus allowing another attempt. If success is true then all ongoing and all further calls to call_once_begin return CALL_ONCE_ALREADY_CALLED.

SRS_CALL_ONCE_02_005: [ If success is true then call_once_end shall call interlocked_exchange setting state to CALL_ONCE_CALLED and shall call wake_by_address_all(state). ]

SRS_CALL_ONCE_02_006: [ If success is false then call_once_end shall call interlocked_exchange setting state to CALL_ONCE_NOT_CALLED and shall call wake_by_address_all(state). ]