static ASYNC_RETRY_WRAPPER_RESULT MU_C2()

in inc/c_util/async_retry_wrapper.h [532:642]


    static ASYNC_RETRY_WRAPPER_RESULT MU_C2(ASYNC_RETRY_WRAPPER(async_function_name), _internal)(async_handle_type async_handle, THANDLE(THREADPOOL) threadpool, uint32_t timeout_ms ASYNC_RETRY_WRAPPER_ARGS_IN_STATIC_DECLARATION(in_args), return_type* async_function_result) \
    { \
        ASYNC_RETRY_WRAPPER_RESULT async_retry_wrapper_result; \
        if (async_handle == NULL) \
        { \
            /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_003: [ If async_handle is NULL, the asynchronous retry wrapper shall fail and return ASYNC_RETRY_WRAPPER_INVALID_ARGS. ]*/ \
            LogError("NULL " MU_TOSTRING(async_handle_type) " async_handle for " MU_TOSTRING(async_function_name)); \
            async_retry_wrapper_result = ASYNC_RETRY_WRAPPER_INVALID_ARGS; \
        } \
        else if (async_function_result == NULL) \
        { \
            /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_042: [ If async_function_result is NULL, the asynchronous retry wrapper shall fail and return ASYNC_RETRY_WRAPPER_INVALID_ARGS. ]*/ \
            LogError("NULL " MU_TOSTRING(return_type) "* async_function_result for " MU_TOSTRING(async_function_name)); \
            async_retry_wrapper_result = ASYNC_RETRY_WRAPPER_INVALID_ARGS; \
        } \
        else if (threadpool == NULL) \
        { \
            /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_037: [ If threadpool is NULL, the asynchronous retry wrapper shall fail and return ASYNC_RETRY_WRAPPER_INVALID_ARGS. ]*/ \
            LogError("NULL THANDLE(THREADPOOL) threadpool for " MU_TOSTRING(async_function_name)); \
            async_retry_wrapper_result = ASYNC_RETRY_WRAPPER_INVALID_ARGS; \
        } \
        ASYNC_RETRY_WRAPPER_CHECK_ARG_PTRS(in_args) \
        else \
        { \
            /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_005: [ The asynchronous retry wrapper shall allocate a context for the asynchronous call. ]*/ \
            ASYNC_RETRY_WRAPPER_CONTEXT(async_function_name)* retry_context = malloc(sizeof(ASYNC_RETRY_WRAPPER_CONTEXT(async_function_name))); \
            if (retry_context == NULL) \
            { \
                LogError("Failed to create context for " MU_TOSTRING(async_function_name)); \
                async_retry_wrapper_result = ASYNC_RETRY_WRAPPER_ERROR; \
            } \
            else \
            { \
                if (timeout_ms < UINT32_MAX) \
                { \
                    /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_048: [ {async_function_name}_async_retry_wrapper_with_timeout shall get the current time by calling timer_global_get_elapsed_ms. ]*/ \
                    retry_context->start_time = timer_global_get_elapsed_ms(); \
                } \
                retry_context->timeout_ms = timeout_ms; \
                bool error_copying_args = false; \
                ASYNC_RETRY_WRAPPER_COPY_ARGS_PROXY(in_args) \
                if (error_copying_args) \
                { \
                    /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_010: [ If there are any failures when copying the input arguments then the asynchronous retry wrapper shall fail and return ASYNC_RETRY_WRAPPER_COPY_ARG_ERROR. ]*/ \
                    async_retry_wrapper_result = ASYNC_RETRY_WRAPPER_COPY_ARG_ERROR; \
                } \
                else \
                { \
                    retry_context->handle = async_handle; \
                    THANDLE_INITIALIZE(THREADPOOL)(&retry_context->threadpool, threadpool); \
                    return_type temp_async_function_result; \
                    retry_context->backoff = 1; \
                    bool timed_out = false; \
                    do \
                    { \
                        /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_011: [ The asynchronous retry wrapper shall call the function async_function_name, passing the in_args that have been copied to the retry context with the exception of ARG_CB(...) and ARG_CONTEXT(...) which are instead passed as the generated callback handler and the allocated context. ]*/ \
                        /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_043: [ The asynchronous retry wrapper shall store the result of async_function_name in async_function_result. ]*/ \
                        temp_async_function_result = async_function_name(retry_context->handle ASYNC_RETRY_WRAPPER_ARGS_IN_CALL(in_args), ASYNC_RETRY_WRAPPER_CALLBACK(async_function_name), retry_context); \
                        if (ASYNC_RETRY_WRAPPER_RETRY_CONDITIONS_PROXY(retry_sync_enums)) \
                        { \
                            if (retry_context->timeout_ms < UINT32_MAX) \
                            { \
                                double elapsed_time_ms = timer_global_get_elapsed_ms() - retry_context->start_time; \
                                if (elapsed_time_ms + retry_context->backoff > retry_context->timeout_ms) \
                                { \
                                    /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_049: [ Before each retry of the function, If timeout_ms milliseconds have elapsed then {async_function_name}_async_retry_wrapper_with_timeout shall fail and return ASYNC_RETRY_WRAPPER_TIMEOUT. ]*/ \
                                    timed_out = true; \
                                    LogWarning("Retries for " MU_TOSTRING(async_function_name) " timed out after %lf ms (including %" PRIu32 " ms of backoff) (timeout time was %" PRIu32 " ms)", \
                                        elapsed_time_ms, retry_context->backoff, retry_context->timeout_ms); \
                                    break; \
                                } \
                            } \
                            /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_044: [ Before each retry of the function, the asynchronous retry wrapper shall yield execution by a call to ThreadAPI_Sleep. ]*/ \
                            ThreadAPI_Sleep(retry_context->backoff); \
                            retry_context->backoff *= 2; \
                            if (retry_context->backoff > ASYNC_RETRY_WRAPPER_MAX_BACKOFF_MS) \
                            { \
                                retry_context->backoff = ASYNC_RETRY_WRAPPER_MAX_BACKOFF_MS; \
                            } \
                        } \
                        /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_038: [ While async_function_name returns one of the values from RETRY_ON_SYNC(...), it shall be called again in a loop. ]*/ \
                    } while (ASYNC_RETRY_WRAPPER_RETRY_CONDITIONS_PROXY(retry_sync_enums)); \
                    *async_function_result = temp_async_function_result; \
                    if (timed_out) \
                    { \
                        async_retry_wrapper_result = ASYNC_RETRY_WRAPPER_TIMEOUT; \
                    } \
                    else \
                    { \
                        if (temp_async_function_result != expected_return) \
                        { \
                            /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_039: [ If async_function_name returns a value other than expected_return then the asynchronous retry wrapper shall fail and return ASYNC_RETRY_WRAPPER_CALL_ERROR. ]*/ \
                            LogInfo(MU_TOSTRING(async_function_name) " failed"); \
                            async_retry_wrapper_result = ASYNC_RETRY_WRAPPER_CALL_ERROR; \
                        } \
                        else \
                        { \
                            /*Codes_SRS_ASYNC_RETRY_WRAPPER_42_013: [ On success, the asynchronous retry wrapper shall return ASYNC_RETRY_WRAPPER_OK. ]*/ \
                            async_retry_wrapper_result = ASYNC_RETRY_WRAPPER_OK; \
                            goto all_ok; \
                        } \
                    } \
                    THANDLE_ASSIGN(THREADPOOL)(&retry_context->threadpool, NULL); \
                } \
                ASYNC_RETRY_WRAPPER_FREE_FAILED_PROXY(in_args); \
                free(retry_context); \
            } \
        } \
    all_ok: \
        return async_retry_wrapper_result; \
    } \