void sm_exec_end()

in common/src/sm.c [430:483]


void sm_exec_end(SM_HANDLE sm)
{
    /*Codes_SRS_SM_02_024: [ If sm is NULL then sm_exec_end shall return. ]*/
    if (sm == NULL)
    {
        LogError("invalid arg SM_HANDLE sm=%p", sm);
    }
    else
    {
        int32_t state = interlocked_add(&sm->state, 0);
        /*Codes_SRS_SM_42_013: [ sm_exec_end may be called when SM_FAULTED_BIT is 1. ]*/
        if (
            /*Codes_SRS_SM_02_059: [ If state is not SM_OPENED then sm_exec_end shall return. ]*/
            ((state & SM_STATE_MASK) != SM_OPENED) &&
            /*Codes_SRS_SM_02_060: [ If state is not SM_OPENED_DRAINING_TO_BARRIER then sm_exec_end shall return. ]*/
            ((state & SM_STATE_MASK) != SM_OPENED_DRAINING_TO_BARRIER) &&
            /*Codes_SRS_SM_02_061: [ If state is not SM_OPENED_DRAINING_TO_CLOSE then sm_exec_end shall return. ]*/
            ((state & SM_STATE_MASK) != SM_OPENED_DRAINING_TO_CLOSE)
            )
        {
            LogError("sm name=%s. cannot execute exec end when state is %" PRI_SM_STATE "", sm->name, SM_STATE_VALUE(state));
        }
        else
        {
            /*Codes_SRS_SM_02_062: [ sm_exec_end shall decrement n with saturation at 0. ]*/
            do /*a rather convoluted loop to make _end be idempotent (too many _end will be ignored)*/
            {
                int32_t n = interlocked_add(&sm->non_barrier_call_count, 0);
                if (n <= 0)
                {
                    /*Codes_SRS_SM_42_010: [ If n would decrement below 0, then sm_exec_end shall terminate the process. ]*/
                    LogCriticalAndTerminate("Unmatched call to sm_exec_end detected!!! Pending call count is invalid");
                    break;
                }
                else
                {
                    if (interlocked_compare_exchange(&sm->non_barrier_call_count, n - 1, n) != n)
                    {
                        /*well - retry sort of...*/
                    }
                    else
                    {
                        /*Codes_SRS_SM_02_063: [ If n reaches 0 then sm_exec_end shall signal that. ]*/
                        if (n - 1 == 0)
                        {
                            wake_by_address_single(&sm->non_barrier_call_count);
                        }
                        break;
                    }
                }
            } while (1);
        }
    }
}