in inc/c_util/async_retry_wrapper.h [383:455]
static void ASYNC_RETRY_WRAPPER_RETRY_FUNC(async_function_name)(void* context) \
{ \
if (context == NULL) \
{ \
LogCriticalAndTerminate("NULL context for " MU_TOSTRING(async_function_name) " do retry function"); \
} \
else \
{ \
ASYNC_RETRY_WRAPPER_CONTEXT(async_function_name)* retry_context = context; \
return_type temp_async_function_result; \
bool timed_out = false; \
do \
{ \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_42_023: [ {async_function_name}_do_retry 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. ]*/ \
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) \
{ \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_02_001: [ Before each retry of the function, if timeout_ms milliseconds have elapsed since the initial call to ASYNC_RETRY_WRAPPER(async_function_name) then {async_function_name}_async_retry_wrapper_with_timeout shall call shall call the user callback specified in ARG_CB(...), passing the context from ARG_CONTEXT(...), the error_value from all of the ARG(type, name, error_value)'s in out_args. and the timeout_error_value for the ENUM(...) argument. ]*/ \
double elapsed_time_ms = timer_global_get_elapsed_ms() - retry_context->start_time; \
LogInfo("elapsed_time_ms=%lf + retry_context->backoff=%" PRIu32 " > retry_context->timeout_ms=%" PRIu32 "", \
elapsed_time_ms, retry_context->backoff, retry_context->timeout_ms); \
if (elapsed_time_ms + retry_context->backoff > retry_context->timeout_ms) \
{ \
timed_out = true; \
LogError("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_045: [ Before each retry of the function, {async_function_name}_do_retry 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_040: [ 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)); \
if (timed_out) \
{ \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_42_041: [ If async_function_name returns a value other than expected_return then: ]*/ \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_42_025: [ {async_function_name}_do_retry shall call the user callback specified in ARG_CB(...), passing the context from ARG_CONTEXT(...), and the error_value from all of the ARG(type, name, error_value)'s in out_args. ]*/ \
retry_context->user_captured_callback(retry_context->user_captured_callback_context ASYNC_RETRY_WRAPPER_CALLBACK_ARGS_FOR_CALL_WITH_TIMEOUT_PROXY(out_args)); \
ASYNC_RETRY_WRAPPER_FREE_FIELDS_PROXY(in_args); \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_11_001: [ on_{async_function_name}_complete shall assign the threadpool to NULL. ]*/ \
THANDLE_ASSIGN(THREADPOOL)(&retry_context->threadpool, NULL); \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_42_028: [ {async_function_name}_do_retry shall free the allocated context. ]*/ \
free(retry_context); \
} \
else \
{ \
if (temp_async_function_result != expected_return) \
{ \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_42_041: [ If async_function_name returns a value other than expected_return then: ]*/ \
LogError(MU_TOSTRING(async_function_name) " failed during retry"); \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_42_025: [ {async_function_name}_do_retry shall call the user callback specified in ARG_CB(...), passing the context from ARG_CONTEXT(...), and the error_value from all of the ARG(type, name, error_value)'s in out_args. ]*/ \
retry_context->user_captured_callback(retry_context->user_captured_callback_context ASYNC_RETRY_WRAPPER_CALLBACK_ARGS_FOR_CALL_WITH_ERROR_PROXY(out_args)); \
ASYNC_RETRY_WRAPPER_FREE_FIELDS_PROXY(in_args); \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_11_001: [ on_{async_function_name}_complete shall assign the threadpool to NULL. ]*/ \
THANDLE_ASSIGN(THREADPOOL)(&retry_context->threadpool, NULL); \
/*Codes_SRS_ASYNC_RETRY_WRAPPER_42_028: [ {async_function_name}_do_retry shall free the allocated context. ]*/ \
free(retry_context); \
} \
else \
{ \
/* Retry attempted, callback will be called */ \
} \
} \
} \
}