in common/src/sm.c [208:294]
static SM_RESULT sm_close_begin_internal(SM_HANDLE sm, ON_SM_CLOSING_COMPLETE_CALLBACK callback, void* callback_context, ON_SM_CLOSING_WHILE_OPENING_CALLBACK close_while_opening_callback, void* close_while_opening_context)
{
SM_RESULT result;
int32_t state;
/*Codes_SRS_SM_02_045: [ sm_close_begin_internal shall set SM_CLOSE_BIT to 1. ]*/
if (((state=interlocked_or(&sm->state, SM_CLOSE_BIT)) & SM_CLOSE_BIT) == SM_CLOSE_BIT)
{
/*Codes_SRS_SM_02_046: [ If SM_CLOSE_BIT was already 1 then sm_close_begin_internal shall return SM_EXEC_REFUSED. ]*/
LogError("sm name=%s. another thread is performing close (state=%" PRI_SM_STATE ")", sm->name, SM_STATE_VALUE(state));
result = SM_EXEC_REFUSED;
}
else
{
bool initial_iteration = true;
do
{
state = interlocked_add(&sm->state, 0);
/*Codes_SRS_SM_02_047: [ If the state is SM_OPENED then sm_close_begin_internal shall switch it to SM_OPENED_DRAINING_TO_CLOSE. ]*/
if ((state & SM_STATE_MASK) == SM_OPENED)
{
if (interlocked_compare_exchange(&sm->state, state - SM_OPENED + SM_OPENED_DRAINING_TO_CLOSE + SM_STATE_INCREMENT, state) != state)
{
/*go and retry*/
}
else
{
if (callback == NULL)
{
/* Codes_SRS_SM_28_007: [ callback shall be allowed to be NULL. ] */
}
else
{
/* Codes_SRS_SM_28_008: [ If callback is not NULL, sm_close_begin_internal shall invoke callback function with callback_context as argument. ] */
callback(callback_context);
}
/*Codes_SRS_SM_02_048: [ sm_close_begin_internal shall wait for n to reach 0. ]*/
if (InterlockedHL_WaitForValue(&sm->non_barrier_call_count, 0, UINT32_MAX) != INTERLOCKED_HL_OK)
{
/*Codes_SRS_SM_02_071: [ If there are any failures then sm_close_begin_internal shall fail and return SM_ERROR. ]*/
LogError("sm name=%s. failure in InterlockedHL_WaitForValue(&sm->non_barrier_call_count=%p, 0, UINT32_MAX), state was %" PRI_SM_STATE "", sm->name, &sm->non_barrier_call_count, SM_STATE_VALUE(state));
(void)interlocked_add(&sm->state, -SM_OPENED_DRAINING_TO_CLOSE + SM_OPENED + SM_STATE_INCREMENT); /*undo state to SM_OPENED...*/
result = SM_ERROR;
break;
}
/*Codes_SRS_SM_02_049: [ sm_close_begin_internal shall switch the state to SM_CLOSING and return SM_EXEC_GRANTED. ]*/
(void)interlocked_add(&sm->state, -SM_OPENED_DRAINING_TO_CLOSE + SM_CLOSING + SM_STATE_INCREMENT);
result = SM_EXEC_GRANTED;
break;
}
}
else if (
/*Codes_SRS_SM_02_050: [ If the state is SM_OPENED_BARRIER then sm_close_begin_internal shall re-evaluate the state. ]*/
((state & SM_STATE_MASK) == SM_OPENED_BARRIER) ||
/*Codes_SRS_SM_02_051: [ If the state is SM_OPENED_DRAINING_TO_BARRIER then sm_close_begin_internal shall re-evaluate the state. ]*/
((state & SM_STATE_MASK) == SM_OPENED_DRAINING_TO_BARRIER)
)
{
ThreadAPI_Sleep(1);
}
else if (
// Codes_SRS_SM_11_002: [ If the state is SM_OPENING, the close_while_opening_callback is non-NULL and this is the first evaluation of the close then ... ]
((state & SM_STATE_MASK) == SM_OPENING) &&
(close_while_opening_callback != NULL) &&
(initial_iteration)
)
{
// Codes_SRS_SM_11_003: [ ... sm_close_begin_internal shall call the close_while_opening_callback and then re-evaluate the state. ]
close_while_opening_callback(close_while_opening_context);
initial_iteration = false;
}
else
{
/*Codes_SRS_SM_02_052: [ If the state is any other value then sm_close_begin_internal shall return SM_EXEC_REFUSED. ]*/
result = SM_EXEC_REFUSED;
break;
}
} while (1);
/*Codes_SRS_SM_02_053: [ sm_close_begin_internal shall set SM_CLOSE_BIT to 0. ]*/
(void)interlocked_and(&sm->state, ~(uint32_t)SM_CLOSE_BIT);
}
return result;
}