diff --git a/.clang-format b/.clang-format index fd05e11..2d632af 100644 --- a/.clang-format +++ b/.clang-format @@ -1,16 +1,96 @@ ---- -BasedOnStyle: WebKit -SortIncludes: 'false' -ColumnLimit: 100 -IndentWidth: 4 -TabWidth: 4 -ContinuationIndentWidth: 8 -UseTab: ForContinuationAndIndentation -PointerAlignment: Right -IndentCaseLabels: true -AlignConsecutiveAssignments: false -AlignEscapedNewlines: DontAlign -AllowShortFunctionsOnASingleLine: false -SpaceAfterCStyleCast: true -AlignOperands: false -... \ No newline at end of file +# PHP Clang-Format Configuration +# Based on WebKit style with PHP coding standards compliance +# References: PHP CODING_STANDARDS.md, K&R style, Linux Kernel standards + +# Core formatting foundation +BasedOnStyle: WebKit # K&R style foundation (PHP standard requirement) +SortIncludes: 'false' # Preserve PHP include organization structure +ColumnLimit: 120 # Reasonable line length for readability +IndentWidth: 4 # PHP standard: 4-space indentation +TabWidth: 4 # PHP standard: tabs represent 4 spaces +ContinuationIndentWidth: 8 # Double indentation for line continuations +UseTab: ForContinuationAndIndentation # PHP standard: use tabs for indentation + +# Pointer and alignment settings +PointerAlignment: Right # Common C convention: int *ptr (not int* ptr) +IndentCaseLabels: true # Standard practice for switch statements +AlignConsecutiveAssignments: false # Avoid artificial alignment per PHP standards +AlignEscapedNewlines: DontAlign # Natural positioning of escaped newlines +AllowShortFunctionsOnASingleLine: false # PHP standard: always use braces and proper formatting +SpaceAfterCStyleCast: true # Standard C practice: (int) value +AlignOperands: false # Natural operator positioning + +# Brace placement - K&R style compliance (PHP CODING_STANDARDS.md) +BraceWrapping: + AfterFunction: true # K&R: function braces on new line + AfterClass: true # Consistent with function style + AfterStruct: true # C standard practice + AfterUnion: true # C standard practice + AfterEnum: true # C standard practice + AfterControlStatement: Never # K&R: if/for/while braces on same line + BeforeElse: false # K&R: } else { pattern + IndentBraces: false # Braces at same level as statement +BreakBeforeBraces: Custom # Enable custom brace wrapping + +# Spacing and whitespace (PHP standards compliance) +SpaceBeforeParens: ControlStatements # Space before if/for/while parentheses +InsertTrailingCommas: None # Clean, minimal comma usage +MaxEmptyLinesToKeep: 2 # PHP standard: generous whitespace between functions +KeepEmptyLinesAtTheStartOfBlocks: true # PHP standard: empty line after variable declarations + +# Short statement prevention (PHP standard: "always use braces") +AllowShortIfStatementsOnASingleLine: Never # PHP requirement: always use braces +AllowShortLoopsOnASingleLine: false # PHP requirement: always use braces +AllowShortBlocksOnASingleLine: Never # PHP requirement: always use braces + +# Basic spacing rules +SpaceInEmptyParentheses: false # Clean: func() not func( ) +SpaceBeforeAssignmentOperators: true # Standard: a = b not a=b +SpaceBeforeSquareBrackets: false # Clean: array[0] not array [0] + +# Preprocessor handling (PHP standard compliance) +IndentPPDirectives: None # Keep #include at column 1, manual indentation for conditionals only + +# Advanced formatting for code quality (based on Linux Kernel and GNU standards) +AlignAfterOpenBracket: Align # GNU standard: align function arguments nicely +AlignConsecutiveDeclarations: false # Avoid artificial alignment (PHP philosophy) +AlignConsecutiveMacros: false # Natural macro positioning +AlignTrailingComments: true # Linux Kernel practice: align end-of-line comments +BinPackArguments: false # Google/GNU standard: one argument per line for clarity +BinPackParameters: false # Google/GNU standard: one parameter per line for clarity + +# Line breaking preferences +BreakBeforeBinaryOperators: None # Standard practice: operators at end of line +BreakBeforeTernaryOperators: true # Better readability for ternary expressions +BreakStringLiterals: true # MISRA-C compliance: break long string literals +CompactNamespaces: false # Not applicable to C, but consistent spacing +FixNamespaceComments: false # Not applicable to C +IncludeBlocks: Preserve # Maintain PHP's careful include organization + +# Line breaking penalties (optimization for readability) +PenaltyBreakAssignment: 2 # Slight penalty for breaking assignments +PenaltyBreakBeforeFirstCallParameter: 19 # Prefer keeping first parameter on same line +PenaltyBreakComment: 300 # High penalty for breaking comments +PenaltyBreakFirstLessLess: 120 # Stream operator handling +PenaltyBreakString: 1000 # High penalty for string breaks +PenaltyExcessCharacter: 1000000 # Very high penalty for exceeding column limit +PenaltyReturnTypeOnItsOwnLine: 60 # Moderate penalty for return type breaks + +# Comment and documentation handling +ReflowComments: true # GNU standard: reformat comments for consistency +SeparateDefinitionBlocks: Always # PHP standard: empty lines between functions +SortUsingDeclarations: false # Preserve manual include ordering + +# Detailed spacing control (MISRA-C and industry best practices) +SpaceAfterLogicalNot: false # Standard: !condition not ! condition +SpaceAroundPointerQualifiers: Default # Standard C pointer qualifier spacing +SpaceBeforeCpp11BracedList: false # Clean braced list formatting +SpaceBeforeRangeBasedForLoopColon: true # Readability in range-based loops +SpaceInEmptyBlock: false # Clean empty blocks: {} not { } +SpacesBeforeTrailingComments: 1 # Standard: single space before comment +SpacesInAngles: false # Clean template/generic syntax +SpacesInConditionalStatement: false # Clean: if (condition) not if ( condition ) +SpacesInContainerLiterals: false # Clean array/container literals +SpacesInCStyleCastParentheses: false # Clean: (int)value not ( int )value +SpacesInParentheses: false # Clean: func(arg) not func( arg ) +SpacesInSquareBrackets: false # Clean: array[0] not array[ 0 ] \ No newline at end of file diff --git a/async.c b/async.c index 02048cf..6f2de71 100644 --- a/async.c +++ b/async.c @@ -33,8 +33,8 @@ #include "libuv_reactor.h" #endif -zend_class_entry * async_ce_awaitable = NULL; -zend_class_entry * async_ce_timeout = NULL; +zend_class_entry *async_ce_awaitable = NULL; +zend_class_entry *async_ce_timeout = NULL; /////////////////////////////////////////////////////////////// /// Module functions @@ -42,21 +42,24 @@ zend_class_entry * async_ce_timeout = NULL; static zend_object *async_timeout_create(zend_ulong ms, bool is_periodic); -#define THROW_IF_SCHEDULER_CONTEXT if (UNEXPECTED(ZEND_ASYNC_IS_SCHEDULER_CONTEXT)) { \ - async_throw_error("The operation cannot be executed in the scheduler context"); \ - RETURN_THROWS(); \ +#define THROW_IF_SCHEDULER_CONTEXT \ + if (UNEXPECTED(ZEND_ASYNC_IS_SCHEDULER_CONTEXT)) { \ + async_throw_error("The operation cannot be executed in the scheduler context"); \ + RETURN_THROWS(); \ } -#define THROW_IF_ASYNC_OFF if (UNEXPECTED(ZEND_ASYNC_OFF)) { \ - async_throw_error("The operation cannot be executed while async is off"); \ - RETURN_THROWS(); \ +#define THROW_IF_ASYNC_OFF \ + if (UNEXPECTED(ZEND_ASYNC_OFF)) { \ + async_throw_error("The operation cannot be executed while async is off"); \ + RETURN_THROWS(); \ } -#define SCHEDULER_LAUNCH if (UNEXPECTED(ZEND_ASYNC_CURRENT_COROUTINE == NULL)) { \ - async_scheduler_launch(); \ - if (UNEXPECTED(EG(exception) != NULL)) { \ - RETURN_THROWS(); \ - } \ +#define SCHEDULER_LAUNCH \ + if (UNEXPECTED(ZEND_ASYNC_CURRENT_COROUTINE == NULL)) { \ + async_scheduler_launch(); \ + if (UNEXPECTED(EG(exception) != NULL)) { \ + RETURN_THROWS(); \ + } \ } PHP_FUNCTION(Async_spawn) @@ -72,11 +75,11 @@ PHP_FUNCTION(Async_spawn) zend_fcall_info_cache fcc; ZEND_PARSE_PARAMETERS_START(1, -1) - Z_PARAM_FUNC(fci, fcc); - Z_PARAM_VARIADIC_WITH_NAMED(args, args_count, named_args); + Z_PARAM_FUNC(fci, fcc); + Z_PARAM_VARIADIC_WITH_NAMED(args, args_count, named_args); ZEND_PARSE_PARAMETERS_END(); - async_coroutine_t * coroutine = (async_coroutine_t *) ZEND_ASYNC_SPAWN(); + async_coroutine_t *coroutine = (async_coroutine_t *) ZEND_ASYNC_SPAWN(); if (UNEXPECTED(EG(exception))) { return; @@ -98,24 +101,25 @@ PHP_FUNCTION(Async_spawnWith) int args_count = 0; HashTable *named_args = NULL; - zend_async_scope_t * scope = NULL; - zend_object * scope_provider = NULL; + zend_async_scope_t *scope = NULL; + zend_object *scope_provider = NULL; zend_fcall_info fci; zend_fcall_info_cache fcc; ZEND_PARSE_PARAMETERS_START(2, -1) - Z_PARAM_OBJ_OF_CLASS(scope_provider, async_ce_scope_provider) - Z_PARAM_FUNC(fci, fcc); - Z_PARAM_VARIADIC_WITH_NAMED(args, args_count, named_args); + Z_PARAM_OBJ_OF_CLASS(scope_provider, async_ce_scope_provider) + Z_PARAM_FUNC(fci, fcc); + Z_PARAM_VARIADIC_WITH_NAMED(args, args_count, named_args); ZEND_PARSE_PARAMETERS_END(); // If scope_provider is an instance of async_ce_scope if (instanceof_function(scope_provider->ce, async_ce_scope)) { - scope = &((async_scope_object_t *)scope_provider)->scope->scope; + scope = &((async_scope_object_t *) scope_provider)->scope->scope; } - async_coroutine_t * coroutine = (async_coroutine_t *)(scope_provider ? ZEND_ASYNC_SPAWN_WITH_PROVIDER(scope_provider) - : ZEND_ASYNC_SPAWN_WITH(scope)); + async_coroutine_t *coroutine = + (async_coroutine_t *) (scope_provider ? ZEND_ASYNC_SPAWN_WITH_PROVIDER(scope_provider) + : ZEND_ASYNC_SPAWN_WITH(scope)); if (UNEXPECTED(EG(exception) != NULL)) { RETURN_THROWS(); @@ -146,13 +150,14 @@ PHP_FUNCTION(Async_protect) zend_object *closure; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJ_OF_CLASS(closure, zend_ce_closure) + Z_PARAM_OBJ_OF_CLASS(closure, zend_ce_closure) ZEND_PARSE_PARAMETERS_END(); zend_coroutine_t *coroutine = ZEND_ASYNC_CURRENT_COROUTINE; bool do_bailout = false; - zend_try { + zend_try + { if (coroutine != NULL) { ZEND_COROUTINE_SET_PROTECTED(coroutine); } @@ -171,10 +176,12 @@ PHP_FUNCTION(Async_protect) // If the closure did not return a value, we return NULL. ZVAL_NULL(return_value); } - - } zend_catch { + } + zend_catch + { do_bailout = true; - } zend_end_try(); + } + zend_end_try(); if (coroutine != NULL) { ZEND_COROUTINE_CLR_PROTECTED(coroutine); @@ -199,13 +206,13 @@ PHP_FUNCTION(Async_protect) PHP_FUNCTION(Async_await) { - zend_object * awaitable = NULL; - zend_object * cancellation = NULL; + zend_object *awaitable = NULL; + zend_object *cancellation = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_OBJ_OF_CLASS(awaitable, async_ce_awaitable); - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); + Z_PARAM_OBJ_OF_CLASS(awaitable, async_ce_awaitable); + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); ZEND_PARSE_PARAMETERS_END(); SCHEDULER_LAUNCH; @@ -255,26 +262,14 @@ PHP_FUNCTION(Async_await) RETURN_THROWS(); } - zend_async_resume_when( - coroutine, - awaitable_event, - false, - zend_async_waker_callback_resolve, - NULL - ); + zend_async_resume_when(coroutine, awaitable_event, false, zend_async_waker_callback_resolve, NULL); if (UNEXPECTED(EG(exception) != NULL)) { RETURN_THROWS(); } if (cancellation_event != NULL) { - zend_async_resume_when( - coroutine, - cancellation_event, - false, - zend_async_waker_callback_cancel, - NULL - ); + zend_async_resume_when(coroutine, cancellation_event, false, zend_async_waker_callback_cancel, NULL); if (UNEXPECTED(EG(exception) != NULL)) { RETURN_THROWS(); @@ -300,31 +295,30 @@ PHP_FUNCTION(Async_await) PHP_FUNCTION(Async_awaitAnyOrFail) { - zval * futures; - zend_object * cancellation = NULL; + zval *futures; + zend_object *cancellation = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ZVAL(futures); - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); + Z_PARAM_ZVAL(futures); + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); ZEND_PARSE_PARAMETERS_END(); SCHEDULER_LAUNCH; - HashTable * results = zend_new_array(8); + HashTable *results = zend_new_array(8); async_await_futures(futures, - 1, - false, - cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, - 0, - 0, - results, - NULL, - false, - false, - false - ); + 1, + false, + cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, + 0, + 0, + results, + NULL, + false, + false, + false); if (EG(exception)) { zend_array_release(results); @@ -337,10 +331,12 @@ PHP_FUNCTION(Async_awaitAnyOrFail) } zval result; - ZEND_HASH_FOREACH_VAL(results, zval *item) { + ZEND_HASH_FOREACH_VAL(results, zval * item) + { ZVAL_COPY(&result, item); break; - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); zend_array_release(results); @@ -349,32 +345,31 @@ PHP_FUNCTION(Async_awaitAnyOrFail) PHP_FUNCTION(Async_awaitFirstSuccess) { - zval * futures; - zend_object * cancellation = NULL; + zval *futures; + zend_object *cancellation = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ZVAL(futures); - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); + Z_PARAM_ZVAL(futures); + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); ZEND_PARSE_PARAMETERS_END(); SCHEDULER_LAUNCH; - HashTable * results = zend_new_array(8); - HashTable * errors = zend_new_array(8); + HashTable *results = zend_new_array(8); + HashTable *errors = zend_new_array(8); async_await_futures(futures, - 1, - true, - cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, - 0, - 0, - results, - errors, - false, - false, - true - ); + 1, + true, + cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, + 0, + 0, + results, + errors, + false, + false, + true); if (EG(exception)) { zend_array_release(results); @@ -382,15 +377,17 @@ PHP_FUNCTION(Async_awaitFirstSuccess) RETURN_THROWS(); } - HashTable * return_array = zend_new_array(2); + HashTable *return_array = zend_new_array(2); zval val; ZVAL_NULL(&val); - ZEND_HASH_FOREACH_VAL(results, zval *item) { + ZEND_HASH_FOREACH_VAL(results, zval * item) + { ZVAL_COPY(&val, item); break; - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); zend_hash_next_index_insert_new(return_array, &val); @@ -404,35 +401,34 @@ PHP_FUNCTION(Async_awaitFirstSuccess) PHP_FUNCTION(Async_awaitAllOrFail) { - zval * futures; - zend_object * cancellation = NULL; + zval *futures; + zend_object *cancellation = NULL; bool preserve_key_order = true; ZEND_PARSE_PARAMETERS_START(1, 3) - Z_PARAM_ZVAL(futures); - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); - Z_PARAM_BOOL(preserve_key_order); + Z_PARAM_ZVAL(futures); + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); + Z_PARAM_BOOL(preserve_key_order); ZEND_PARSE_PARAMETERS_END(); SCHEDULER_LAUNCH; - HashTable * results = zend_new_array(8); + HashTable *results = zend_new_array(8); async_await_futures(futures, - 0, - false, - cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, - 0, - 0, - results, - NULL, - // For awaitAll, it’s always necessary to fill the result with NULL, - // because the order of keys matters. - true, - preserve_key_order, - true - ); + 0, + false, + cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, + 0, + 0, + results, + NULL, + // For awaitAll, it’s always necessary to fill the result with NULL, + // because the order of keys matters. + true, + preserve_key_order, + true); if (EG(exception)) { zend_array_release(results); @@ -444,36 +440,35 @@ PHP_FUNCTION(Async_awaitAllOrFail) PHP_FUNCTION(Async_awaitAll) { - zval * futures; - zend_object * cancellation = NULL; + zval *futures; + zend_object *cancellation = NULL; bool preserve_key_order = true; bool fill_null = false; ZEND_PARSE_PARAMETERS_START(1, 4) - Z_PARAM_ZVAL(futures); - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); - Z_PARAM_BOOL(preserve_key_order); - Z_PARAM_BOOL(fill_null); + Z_PARAM_ZVAL(futures); + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); + Z_PARAM_BOOL(preserve_key_order); + Z_PARAM_BOOL(fill_null); ZEND_PARSE_PARAMETERS_END(); SCHEDULER_LAUNCH; - HashTable * results = zend_new_array(8); - HashTable * errors = zend_new_array(8); + HashTable *results = zend_new_array(8); + HashTable *errors = zend_new_array(8); async_await_futures(futures, - 0, - true, - cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, - 0, - 0, - results, - errors, - fill_null, - preserve_key_order, - true - ); + 0, + true, + cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, + 0, + 0, + results, + errors, + fill_null, + preserve_key_order, + true); if (EG(exception)) { zend_array_release(results); @@ -481,7 +476,7 @@ PHP_FUNCTION(Async_awaitAll) RETURN_THROWS(); } - HashTable * return_array = zend_new_array(2); + HashTable *return_array = zend_new_array(2); zval val; ZVAL_ARR(&val, results); @@ -495,39 +490,38 @@ PHP_FUNCTION(Async_awaitAll) PHP_FUNCTION(Async_awaitAnyOfOrFail) { - zval * futures; - zend_object * cancellation = NULL; + zval *futures; + zend_object *cancellation = NULL; zend_long count = 0; bool preserve_key_order = true; ZEND_PARSE_PARAMETERS_START(2, 4) - Z_PARAM_LONG(count) - Z_PARAM_ITERABLE(futures); - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); - Z_PARAM_BOOL(preserve_key_order); + Z_PARAM_LONG(count) + Z_PARAM_ITERABLE(futures); + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); + Z_PARAM_BOOL(preserve_key_order); ZEND_PARSE_PARAMETERS_END(); SCHEDULER_LAUNCH; - HashTable * results = zend_new_array(8); + HashTable *results = zend_new_array(8); if (count == 0) { RETURN_ARR(results); } async_await_futures(futures, - (int)count, - false, - cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, - 0, - 0, - results, - NULL, - false, - preserve_key_order, - false - ); + (int) count, + false, + cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, + 0, + 0, + results, + NULL, + false, + preserve_key_order, + false); if (EG(exception)) { zend_array_release(results); @@ -539,38 +533,37 @@ PHP_FUNCTION(Async_awaitAnyOfOrFail) PHP_FUNCTION(Async_awaitAnyOf) { - zval * futures; - zend_object * cancellation = NULL; + zval *futures; + zend_object *cancellation = NULL; zend_long count = 0; bool preserve_key_order = true; bool fill_null = false; ZEND_PARSE_PARAMETERS_START(2, 5) - Z_PARAM_LONG(count) - Z_PARAM_ZVAL(futures); - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); - Z_PARAM_BOOL(preserve_key_order); - Z_PARAM_BOOL(fill_null); + Z_PARAM_LONG(count) + Z_PARAM_ZVAL(futures); + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_awaitable); + Z_PARAM_BOOL(preserve_key_order); + Z_PARAM_BOOL(fill_null); ZEND_PARSE_PARAMETERS_END(); - HashTable * results = zend_new_array(8); - HashTable * errors = zend_new_array(8); + HashTable *results = zend_new_array(8); + HashTable *errors = zend_new_array(8); SCHEDULER_LAUNCH; async_await_futures(futures, - (int)count, - true, - cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, - 0, - 0, - results, - errors, - fill_null, - preserve_key_order, - true - ); + (int) count, + true, + cancellation != NULL ? ZEND_ASYNC_OBJECT_TO_EVENT(cancellation) : NULL, + 0, + 0, + results, + errors, + fill_null, + preserve_key_order, + true); if (EG(exception)) { zend_array_release(results); @@ -578,7 +571,7 @@ PHP_FUNCTION(Async_awaitAnyOf) RETURN_THROWS(); } - HashTable * return_array = zend_new_array(2); + HashTable *return_array = zend_new_array(2); zval val; ZVAL_ARR(&val, results); @@ -595,7 +588,7 @@ PHP_FUNCTION(Async_delay) zend_long ms = 0; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_LONG(ms) + Z_PARAM_LONG(ms) ZEND_PARSE_PARAMETERS_END(); SCHEDULER_LAUNCH; @@ -626,7 +619,7 @@ PHP_FUNCTION(Async_timeout) zend_long ms = 0; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_LONG(ms) + Z_PARAM_LONG(ms) ZEND_PARSE_PARAMETERS_END(); if (ms <= 0) { @@ -634,7 +627,7 @@ PHP_FUNCTION(Async_timeout) RETURN_THROWS(); } - zend_object * zend_object = async_timeout_create(ms, false); + zend_object *zend_object = async_timeout_create(ms, false); if (UNEXPECTED(EG(exception) != NULL)) { RETURN_THROWS(); @@ -708,10 +701,7 @@ PHP_FUNCTION(Async_currentCoroutine) async_coroutine_t *coroutine = (async_coroutine_t *) ZEND_ASYNC_CURRENT_COROUTINE; if (UNEXPECTED(coroutine == NULL)) { - zend_async_throw( - ZEND_ASYNC_EXCEPTION_DEFAULT, - "The current coroutine is not defined" - ); + zend_async_throw(ZEND_ASYNC_EXCEPTION_DEFAULT, "The current coroutine is not defined"); RETURN_THROWS(); } @@ -727,10 +717,10 @@ PHP_FUNCTION(Async_rootContext) THROW_IF_SCHEDULER_CONTEXT; if (ASYNC_G(root_context) == NULL) { - ASYNC_G(root_context) = (zend_async_context_t *)async_context_new(); + ASYNC_G(root_context) = (zend_async_context_t *) async_context_new(); } - async_context_t *context = (async_context_t *)ASYNC_G(root_context); + async_context_t *context = (async_context_t *) ASYNC_G(root_context); RETURN_OBJ_COPY(&context->std); } @@ -744,10 +734,12 @@ PHP_FUNCTION(Async_getCoroutines) array_init(return_value); async_coroutine_t *coroutine; - ZEND_HASH_FOREACH_PTR(&ASYNC_G(coroutines), coroutine) { + ZEND_HASH_FOREACH_PTR(&ASYNC_G(coroutines), coroutine) + { add_next_index_object(return_value, &coroutine->std); GC_ADDREF(&coroutine->std); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } PHP_FUNCTION(Async_gracefulShutdown) @@ -755,8 +747,8 @@ PHP_FUNCTION(Async_gracefulShutdown) zend_object *cancellation = NULL; ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_cancellation_exception) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(cancellation, async_ce_cancellation_exception) ZEND_PARSE_PARAMETERS_END(); THROW_IF_ASYNC_OFF; @@ -792,10 +784,10 @@ static zend_object_handlers async_timeout_handlers; static void async_timeout_destroy_object(zend_object *object) { - async_timeout_object_t * timeout = ASYNC_TIMEOUT_FROM_OBJ(object); + async_timeout_object_t *timeout = ASYNC_TIMEOUT_FROM_OBJ(object); if (timeout->event != NULL) { - zend_async_timer_event_t * timer_event = timeout->event; + zend_async_timer_event_t *timer_event = timeout->event; async_timeout_ext_t *timeout_ext = ASYNC_TIMEOUT_FROM_EVENT(&timer_event->base); timeout_ext->std = NULL; timeout->event = NULL; @@ -811,8 +803,8 @@ static void async_timeout_event_dispose(zend_async_event_t *event) if (timeout->std) { zend_object *object = timeout->std; async_timeout_object_t *timeout_object = ASYNC_TIMEOUT_FROM_OBJ(object); - ZEND_ASSERT((timeout_object->event == NULL || timeout_object->event == (zend_async_timer_event_t *) event) - && "Event object mismatch"); + ZEND_ASSERT((timeout_object->event == NULL || timeout_object->event == (zend_async_timer_event_t *) event) && + "Event object mismatch"); timeout_object->event = NULL; timeout->std = NULL; OBJ_RELEASE(object); @@ -831,11 +823,9 @@ static void timeout_before_notify_handler(zend_async_event_t *event, void *resul } // Here we override the exception value with a timeout exception. - zend_object * timeout_exception = async_new_exception( - async_ce_timeout_exception, - "Timeout occurred after %lu milliseconds", - ((zend_async_timer_event_t * )event)->timeout - ); + zend_object *timeout_exception = async_new_exception(async_ce_timeout_exception, + "Timeout occurred after %lu milliseconds", + ((zend_async_timer_event_t *) event)->timeout); ZEND_ASYNC_CALLBACKS_NOTIFY_FROM_HANDLER(event, result, timeout_exception); OBJ_RELEASE(timeout_exception); @@ -855,16 +845,15 @@ static zend_object *async_timeout_create(const zend_ulong ms, const bool is_peri object->std.handlers = &async_timeout_handlers; - zend_async_event_t *event = (zend_async_event_t *) ZEND_ASYNC_NEW_TIMER_EVENT_EX( - ms, is_periodic, sizeof(async_timeout_ext_t) - ); + zend_async_event_t *event = + (zend_async_event_t *) ZEND_ASYNC_NEW_TIMER_EVENT_EX(ms, is_periodic, sizeof(async_timeout_ext_t)); if (UNEXPECTED(event == NULL)) { efree(object); return NULL; } - ZEND_ASYNC_EVENT_REF_SET(object, XtOffsetOf(async_timeout_object_t, std), (zend_async_timer_event_t *)event); + ZEND_ASYNC_EVENT_REF_SET(object, XtOffsetOf(async_timeout_object_t, std), (zend_async_timer_event_t *) event); // A special flag is set to indicate that the event will contain a reference to a Zend object. ZEND_ASYNC_EVENT_WITH_OBJECT_REF(event); @@ -889,7 +878,7 @@ void async_register_timeout_ce(void) async_timeout_handlers = std_object_handlers; - async_timeout_handlers.offset = XtOffsetOf(async_timeout_object_t, std); + async_timeout_handlers.offset = XtOffsetOf(async_timeout_object_t, std); async_timeout_handlers.dtor_obj = async_timeout_destroy_object; } @@ -921,12 +910,10 @@ static PHP_GINIT_FUNCTION(async) } /* {{{ PHP_GSHUTDOWN_FUNCTION */ -static PHP_GSHUTDOWN_FUNCTION(async) -{ +static PHP_GSHUTDOWN_FUNCTION(async){ #ifdef PHP_WIN32 #endif -} -/* }}} */ +} /* }}} */ /* Module registration */ @@ -938,11 +925,11 @@ ZEND_MINIT_FUNCTION(async) async_register_coroutine_ce(); async_register_context_ce(); async_register_exceptions_ce(); - //async_register_notifier_ce(); - //async_register_handlers_ce(); - //async_register_channel_ce(); - //async_register_iterator_ce(); - //async_register_future_ce(); + // async_register_notifier_ce(); + // async_register_handlers_ce(); + // async_register_channel_ce(); + // async_register_iterator_ce(); + // async_register_future_ce(); async_scheduler_startup(); @@ -957,16 +944,17 @@ ZEND_MINIT_FUNCTION(async) ZEND_MSHUTDOWN_FUNCTION(async) { - //async_scheduler_shutdown(); + // async_scheduler_shutdown(); #ifdef PHP_ASYNC_LIBUV - //async_libuv_shutdown(); + // async_libuv_shutdown(); #endif return SUCCESS; } -PHP_MINFO_FUNCTION(async) { +PHP_MINFO_FUNCTION(async) +{ php_info_print_table_start(); php_info_print_table_header(2, "Module", PHP_ASYNC_NAME); php_info_print_table_row(2, "Version", PHP_ASYNC_VERSION); @@ -981,7 +969,7 @@ PHP_MINFO_FUNCTION(async) { PHP_RINIT_FUNCTION(async) /* {{{ */ { - //async_host_name_list_ctor(); + // async_host_name_list_ctor(); ZEND_ASYNC_INITIALIZE; circular_buffer_ctor(&ASYNC_G(microtasks), 64, sizeof(zend_async_microtask_t *), &zend_std_allocator); circular_buffer_ctor(&ASYNC_G(coroutine_queue), 128, sizeof(zend_coroutine_t *), &zend_std_allocator); @@ -992,22 +980,20 @@ PHP_RINIT_FUNCTION(async) /* {{{ */ return SUCCESS; } /* }}} */ -zend_module_entry async_module_entry = { - STANDARD_MODULE_HEADER, - PHP_ASYNC_NAME, - ext_functions, - PHP_MINIT(async), - PHP_MSHUTDOWN(async), - PHP_RINIT(async), - NULL, - PHP_MINFO(async), - PHP_ASYNC_VERSION, - PHP_MODULE_GLOBALS(async), - PHP_GINIT(async), - PHP_GSHUTDOWN(async), - NULL, - STANDARD_MODULE_PROPERTIES_EX -}; +zend_module_entry async_module_entry = { STANDARD_MODULE_HEADER, + PHP_ASYNC_NAME, + ext_functions, + PHP_MINIT(async), + PHP_MSHUTDOWN(async), + PHP_RINIT(async), + NULL, + PHP_MINFO(async), + PHP_ASYNC_VERSION, + PHP_MODULE_GLOBALS(async), + PHP_GINIT(async), + PHP_GSHUTDOWN(async), + NULL, + STANDARD_MODULE_PROPERTIES_EX }; #ifdef COMPILE_DL_ASYNC ZEND_GET_MODULE(async) diff --git a/async_API.c b/async_API.c index f877ca5..d3f1448 100644 --- a/async_API.c +++ b/async_API.c @@ -23,7 +23,7 @@ #include "scope.h" #include "zend_common.h" -zend_async_scope_t * async_provide_scope(zend_object *scope_provider) +zend_async_scope_t *async_provide_scope(zend_object *scope_provider) { zval retval; @@ -32,7 +32,7 @@ zend_async_scope_t * async_provide_scope(zend_object *scope_provider) } if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), async_ce_scope)) { - zend_async_scope_t *scope = &((async_scope_object_t *)Z_OBJ(retval))->scope->scope; + zend_async_scope_t *scope = &((async_scope_object_t *) Z_OBJ(retval))->scope->scope; zval_ptr_dtor(&retval); return scope; } @@ -47,15 +47,12 @@ zend_async_scope_t * async_provide_scope(zend_object *scope_provider) return NULL; } - zend_async_throw( - ZEND_ASYNC_EXCEPTION_DEFAULT, - "Scope provider must return an instance of Async\\Scope" - ); + zend_async_throw(ZEND_ASYNC_EXCEPTION_DEFAULT, "Scope provider must return an instance of Async\\Scope"); return NULL; } -zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object * scope_provider, int32_t priority) +zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object *scope_provider, int32_t priority) { if (UNEXPECTED(ZEND_ASYNC_IS_OFF)) { async_throw_error("Cannot spawn a coroutine when async is disabled"); @@ -119,8 +116,8 @@ zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object * scope_provider, return NULL; } - const bool is_spawn_strategy = scope_provider != NULL - && instanceof_function(scope_provider->ce, async_ce_spawn_strategy); + const bool is_spawn_strategy = + scope_provider != NULL && instanceof_function(scope_provider->ce, async_ce_spawn_strategy); // call SpawnStrategy::beforeCoroutineEnqueue if (is_spawn_strategy) { @@ -128,14 +125,13 @@ zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object * scope_provider, ZVAL_OBJ(&coroutine_zval, &coroutine->std); ZVAL_OBJ(&scope_zval, scope->scope_object); - if (zend_call_method_with_2_params( - scope_provider, - scope_provider->ce, - NULL, - "beforeCoroutineEnqueue", - &options, - &coroutine_zval, - &scope_zval) == NULL) { + if (zend_call_method_with_2_params(scope_provider, + scope_provider->ce, + NULL, + "beforeCoroutineEnqueue", + &options, + &coroutine_zval, + &scope_zval) == NULL) { coroutine->coroutine.event.dispose(&coroutine->coroutine.event); return NULL; @@ -161,7 +157,7 @@ zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object * scope_provider, // Normal or low priority: add to back of queue enqueue_result = circular_buffer_push(&ASYNC_G(coroutine_queue), &coroutine, true); } - + if (UNEXPECTED(enqueue_result == FAILURE)) { coroutine->coroutine.event.dispose(&coroutine->coroutine.event); async_throw_error("Failed to enqueue coroutine"); @@ -180,18 +176,17 @@ zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object * scope_provider, ZVAL_OBJ(&coroutine_zval, &coroutine->std); ZVAL_OBJ(&scope_zval, scope->scope_object); - if (zend_call_method_with_2_params( - scope_provider, - scope_provider->ce, - NULL, - "afterCoroutineEnqueue", - &options, - &coroutine_zval, - &scope_zval) == NULL) { + if (zend_call_method_with_2_params(scope_provider, + scope_provider->ce, + NULL, + "afterCoroutineEnqueue", + &options, + &coroutine_zval, + &scope_zval) == NULL) { - waker->status = ZEND_ASYNC_WAKER_IGNORED; - return NULL; - } + waker->status = ZEND_ASYNC_WAKER_IGNORED; + return NULL; + } zval_dtor(&options); } @@ -216,15 +211,15 @@ static void engine_shutdown(void) zend_hash_destroy(&ASYNC_G(coroutines)); if (ASYNC_G(root_context) != NULL) { - async_context_t * root_context = (async_context_t *) ASYNC_G(root_context); + async_context_t *root_context = (async_context_t *) ASYNC_G(root_context); ASYNC_G(root_context) = NULL; OBJ_RELEASE(&root_context->std); } - //async_host_name_list_dtor(); + // async_host_name_list_dtor(); } -zend_array * get_coroutines(void) +zend_array *get_coroutines(void) { return &ASYNC_G(coroutines); } @@ -249,7 +244,7 @@ zend_array *get_awaiting_info(zend_coroutine_t *coroutine) return NULL; } -static zend_class_entry* async_get_class_ce(zend_async_class type) +static zend_class_entry *async_get_class_ce(zend_async_class type) { switch (type) { case ZEND_ASYNC_CLASS_COROUTINE: @@ -279,22 +274,21 @@ static zend_class_entry* async_get_class_ce(zend_async_class type) /// async_await_futures //////////////////////////////////////////////////////////////////// -#define AWAIT_ALL(await_context) ((await_context)->waiting_count == 0 || (await_context)->waiting_count == (await_context)->total) +#define AWAIT_ALL(await_context) \ + ((await_context)->waiting_count == 0 || (await_context)->waiting_count == (await_context)->total) #define AWAIT_ITERATOR_IS_FINISHED(await_context) \ - ((await_context->waiting_count > 0 \ - && (await_context->ignore_errors ? await_context->success_count : await_context->resolved_count) \ - >= await_context->waiting_count) || \ - (await_context->total != 0 && await_context->resolved_count >= await_context->total) \ - ) + ((await_context->waiting_count > 0 && \ + (await_context->ignore_errors ? await_context->success_count : await_context->resolved_count) >= \ + await_context->waiting_count) || \ + (await_context->total != 0 && await_context->resolved_count >= await_context->total)) -static zend_always_inline zend_async_event_t * zval_to_event(const zval * current) +static zend_always_inline zend_async_event_t *zval_to_event(const zval *current) { // An array element can be either an object implementing // the Awaitable interface // or an internal structure zend_async_event_t. - if (Z_TYPE_P(current) == IS_OBJECT - && instanceof_function(Z_OBJCE_P(current), async_ce_awaitable)) { + if (Z_TYPE_P(current) == IS_OBJECT && instanceof_function(Z_OBJCE_P(current), async_ce_awaitable)) { return ZEND_ASYNC_OBJECT_TO_EVENT(Z_OBJ_P(current)); } else if (Z_TYPE_P(current) == IS_PTR) { return (zend_async_event_t *) Z_PTR_P(current); @@ -312,10 +306,10 @@ static zend_always_inline zend_async_event_t * zval_to_event(const zval * curren * @param callback * @param event */ -static void async_waiting_callback_dispose(zend_async_event_callback_t *callback, zend_async_event_t * event) +static void async_waiting_callback_dispose(zend_async_event_callback_t *callback, zend_async_event_t *event) { - async_await_callback_t * await_callback = (async_await_callback_t *) callback; - async_await_context_t * await_context = await_callback->await_context; + async_await_callback_t *await_callback = (async_await_callback_t *) callback; + async_await_context_t *await_context = await_callback->await_context; await_callback->await_context = NULL; @@ -342,15 +336,13 @@ static void async_waiting_callback_dispose(zend_async_event_callback_t *callback * @param result * @param exception */ -static void async_waiting_callback( - zend_async_event_t *event, - zend_async_event_callback_t *callback, - void *result, - zend_object *exception -) +static void async_waiting_callback(zend_async_event_t *event, + zend_async_event_callback_t *callback, + void *result, + zend_object *exception) { - async_await_callback_t * await_callback = (async_await_callback_t *) callback; - async_await_context_t * await_context = await_callback->await_context; + async_await_callback_t *await_callback = (async_await_callback_t *) callback; + async_await_context_t *await_context = await_callback->await_context; await_context->resolved_count++; @@ -387,11 +379,7 @@ static void async_waiting_callback( } if (exception != NULL && false == await_context->ignore_errors) { - ZEND_ASYNC_RESUME_WITH_ERROR( - await_callback->callback.coroutine, - exception, - false - ); + ZEND_ASYNC_RESUME_WITH_ERROR(await_callback->callback.coroutine, exception, false); callback->dispose(callback, NULL); return; @@ -408,7 +396,8 @@ static void async_waiting_callback( return; } - if (exception == NULL && await_context->results != NULL && ZEND_ASYNC_EVENT_WILL_ZVAL_RESULT(event) && result != NULL) { + if (exception == NULL && await_context->results != NULL && ZEND_ASYNC_EVENT_WILL_ZVAL_RESULT(event) && + result != NULL) { const zval *success = NULL; await_context->success_count++; @@ -446,14 +435,13 @@ static void async_waiting_callback( * @param result * @param exception */ -static void async_waiting_cancellation_callback( - zend_async_event_t *event, - zend_async_event_callback_t *callback, - void *result, - zend_object *exception -) { - async_await_callback_t * await_callback = (async_await_callback_t *) callback; - async_await_context_t * await_context = await_callback->await_context; +static void async_waiting_cancellation_callback(zend_async_event_t *event, + zend_async_event_callback_t *callback, + void *result, + zend_object *exception) +{ + async_await_callback_t *await_callback = (async_await_callback_t *) callback; + async_await_context_t *await_context = await_callback->await_context; await_context->resolved_count++; ZEND_ASYNC_EVENT_CALLBACK_ADD_REF(callback); @@ -502,13 +490,13 @@ static void async_waiting_cancellation_callback( */ static zend_result await_iterator_handler(async_iterator_t *iterator, zval *current, zval *key) { - async_await_iterator_t * await_iterator = ((async_await_iterator_iterator_t *) iterator)->await_iterator; + async_await_iterator_t *await_iterator = ((async_await_iterator_iterator_t *) iterator)->await_iterator; // An array element can be either an object implementing // the Awaitable interface // or an internal structure zend_async_event_t. - zend_async_event_t* awaitable = zval_to_event(current); + zend_async_event_t *awaitable = zval_to_event(current); if (UNEXPECTED(EG(exception))) { return FAILURE; @@ -518,15 +506,15 @@ static zend_result await_iterator_handler(async_iterator_t *iterator, zval *curr return SUCCESS; } - if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_LONG - && Z_TYPE_P(key) != IS_NULL && Z_TYPE_P(key) != IS_UNDEF) { + if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_NULL && + Z_TYPE_P(key) != IS_UNDEF) { async_throw_error("Invalid key type: must be string, long or null"); return FAILURE; } - async_await_callback_t * callback = ecalloc(1, sizeof(async_await_callback_t)); + async_await_callback_t *callback = ecalloc(1, sizeof(async_await_callback_t)); callback->callback.base.callback = async_waiting_callback; - async_await_context_t * await_context = await_iterator->await_context; + async_await_context_t *await_context = await_iterator->await_context; callback->await_context = await_context; await_context->ref_count++; @@ -606,7 +594,7 @@ static zend_result await_iterator_handler(async_iterator_t *iterator, zval *curr * @param iterator * @param concurrent_iterator */ -static void await_iterator_dispose(async_await_iterator_t * iterator, async_iterator_t *concurrent_iterator) +static void await_iterator_dispose(async_await_iterator_t *iterator, async_iterator_t *concurrent_iterator) { // If the iterator was completed with an exception, // pass that exception to the coroutine that is waiting. @@ -625,9 +613,9 @@ static void await_iterator_dispose(async_await_iterator_t * iterator, async_iter // Scenario: the iterator has already finished, and there’s nothing left to await. // In that case, the coroutine needs to be terminated. - if ((AWAIT_ITERATOR_IS_FINISHED(iterator->await_context) || iterator->await_context->total == 0) - && iterator->waiting_coroutine != NULL - && false == ZEND_ASYNC_WAKER_IN_QUEUE(iterator->waiting_coroutine->waker)) { + if ((AWAIT_ITERATOR_IS_FINISHED(iterator->await_context) || iterator->await_context->total == 0) && + iterator->waiting_coroutine != NULL && + false == ZEND_ASYNC_WAKER_IN_QUEUE(iterator->waiting_coroutine->waker)) { ZEND_ASYNC_RESUME(iterator->waiting_coroutine); } @@ -648,9 +636,9 @@ static void await_iterator_dispose(async_await_iterator_t * iterator, async_iter */ static void await_iterator_finish_callback(zend_async_iterator_t *internal_iterator) { - async_await_iterator_iterator_t * iterator = (async_await_iterator_iterator_t *) internal_iterator; + async_await_iterator_iterator_t *iterator = (async_await_iterator_iterator_t *) internal_iterator; - async_await_iterator_t * await_iterator = iterator->await_iterator; + async_await_iterator_t *await_iterator = iterator->await_iterator; iterator->await_iterator = NULL; await_iterator_dispose(await_iterator, &iterator->iterator); @@ -671,7 +659,7 @@ static void iterator_coroutine_first_entry(void) return; } - async_await_iterator_t * await_iterator = coroutine->extended_data; + async_await_iterator_t *await_iterator = coroutine->extended_data; coroutine->extended_data = NULL; ZEND_ASSERT(await_iterator != NULL && "The async_await_iterator_t should not be NULL"); @@ -680,23 +668,22 @@ static void iterator_coroutine_first_entry(void) return; } - async_await_context_t * await_context = await_iterator->await_context; + async_await_context_t *await_context = await_iterator->await_context; if (UNEXPECTED(await_context == NULL)) { await_iterator_dispose(await_iterator, NULL); return; } - async_await_iterator_iterator_t * iterator = (async_await_iterator_iterator_t *) async_iterator_new( - NULL, - await_iterator->zend_iterator, - NULL, - await_iterator_handler, - ZEND_ASYNC_CURRENT_SCOPE, - await_context->concurrency, - ZEND_COROUTINE_NORMAL, - sizeof(async_await_iterator_iterator_t) - ); + async_await_iterator_iterator_t *iterator = + (async_await_iterator_iterator_t *) async_iterator_new(NULL, + await_iterator->zend_iterator, + NULL, + await_iterator_handler, + ZEND_ASYNC_CURRENT_SCOPE, + await_context->concurrency, + ZEND_COROUTINE_NORMAL, + sizeof(async_await_iterator_iterator_t)); iterator->await_iterator = await_iterator; iterator->iterator.extended_dtor = await_iterator_finish_callback; @@ -720,14 +707,12 @@ static void iterator_coroutine_first_entry(void) * @param result * @param exception */ -static void iterator_coroutine_finish_callback( - zend_async_event_t *event, - zend_async_event_callback_t *callback, - void * result, - zend_object *exception -) +static void iterator_coroutine_finish_callback(zend_async_event_t *event, + zend_async_event_callback_t *callback, + void *result, + zend_object *exception) { - async_await_iterator_t * iterator = (async_await_iterator_t *) ((zend_coroutine_t*) event)->extended_data; + async_await_iterator_t *iterator = (async_await_iterator_t *) ((zend_coroutine_t *) event)->extended_data; if (iterator == NULL) { return; @@ -735,11 +720,7 @@ static void iterator_coroutine_finish_callback( if (exception != NULL) { // Resume the waiting coroutine with the exception - ZEND_ASYNC_RESUME_WITH_ERROR( - iterator->waiting_coroutine, - exception, - false - ); + ZEND_ASYNC_RESUME_WITH_ERROR(iterator->waiting_coroutine, exception, false); } else if (AWAIT_ITERATOR_IS_FINISHED(iterator->await_context)) { // If iteration is finished, resume the waiting coroutine ZEND_ASYNC_RESUME(iterator->waiting_coroutine); @@ -752,7 +733,7 @@ static void async_await_iterator_coroutine_dispose(zend_coroutine_t *coroutine) return; } - async_await_iterator_t * await_iterator = (async_await_iterator_t *) coroutine->extended_data; + async_await_iterator_t *await_iterator = (async_await_iterator_t *) coroutine->extended_data; coroutine->extended_data = NULL; await_iterator_dispose(await_iterator, NULL); @@ -772,7 +753,7 @@ static void await_context_dtor(async_await_context_t *context) efree(context); } -static void async_cancel_awaited_futures(async_await_context_t * await_context, HashTable *futures) +static void async_cancel_awaited_futures(async_await_context_t *await_context, HashTable *futures) { zend_coroutine_t *this_coroutine = ZEND_ASYNC_CURRENT_COROUTINE; @@ -787,19 +768,19 @@ static void async_cancel_awaited_futures(async_await_context_t * await_context, zend_ulong index; zend_string *key; - zval * current; + zval *current; bool not_need_wait = true; - ZEND_HASH_FOREACH_KEY_VAL(futures, index, key, current) { + ZEND_HASH_FOREACH_KEY_VAL(futures, index, key, current) + { // Handle only the Coroutine objects - if (Z_TYPE_P(current) != IS_OBJECT - || false == instanceof_function(Z_OBJCE_P(current), async_ce_coroutine)) { + if (Z_TYPE_P(current) != IS_OBJECT || false == instanceof_function(Z_OBJCE_P(current), async_ce_coroutine)) { continue; } - zend_async_event_t* awaitable = zval_to_event(current); + zend_async_event_t *awaitable = zval_to_event(current); if (UNEXPECTED(EG(exception))) { return; @@ -809,7 +790,7 @@ static void async_cancel_awaited_futures(async_await_context_t * await_context, continue; } - async_await_callback_t * callback = ecalloc(1, sizeof(async_await_callback_t)); + async_await_callback_t *callback = ecalloc(1, sizeof(async_await_callback_t)); callback->callback.base.callback = async_waiting_cancellation_callback; callback->await_context = await_context; @@ -835,8 +816,8 @@ static void async_cancel_awaited_futures(async_await_context_t * await_context, callback->prev_dispose = callback->callback.base.dispose; callback->callback.base.dispose = async_waiting_callback_dispose; await_context->ref_count++; - - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); if (not_need_wait) { return; @@ -862,19 +843,17 @@ static void async_cancel_awaited_futures(async_await_context_t * await_context, * @param preserve_key_order Whether to preserve the order of keys in results. * @param cancel_on_exit Whether to cancel awaiting on exit. */ -void async_await_futures( - zval *iterable, - int count, - bool ignore_errors, - zend_async_event_t *cancellation, - zend_ulong timeout, - unsigned int concurrency, - HashTable *results, - HashTable *errors, - bool fill_missing_with_null, - bool preserve_key_order, - bool cancel_on_exit -) +void async_await_futures(zval *iterable, + int count, + bool ignore_errors, + zend_async_event_t *cancellation, + zend_ulong timeout, + unsigned int concurrency, + HashTable *results, + HashTable *errors, + bool fill_missing_with_null, + bool preserve_key_order, + bool cancel_on_exit) { HashTable *futures = NULL; zend_object_iterator *zend_iterator = NULL; @@ -889,9 +868,9 @@ void async_await_futures( async_throw_error("Failed to create iterator"); } - } else { - async_throw_error("Expected parameter 'iterable' to be an array or an object implementing Traversable"); - } + } else { + async_throw_error("Expected parameter 'iterable' to be an array or an object implementing Traversable"); + } if (UNEXPECTED(EG(exception))) { return; @@ -899,7 +878,7 @@ void async_await_futures( zend_ulong index; zend_string *key; - zval * current; + zval *current; async_await_context_t *await_context = NULL; @@ -951,19 +930,19 @@ void async_await_futures( await_context->dtor = await_context_dtor; await_context->ref_count = 1; - if (futures != NULL) - { + if (futures != NULL) { zval undef_val; // The PRT NULL type is used to fill the array with empty elements that will later be removed. ZVAL_PTR(&undef_val, NULL); - ZEND_HASH_FOREACH_KEY_VAL(futures, index, key, current) { + ZEND_HASH_FOREACH_KEY_VAL(futures, index, key, current) + { // An array element can be either an object implementing // the Awaitable interface // or an internal structure zend_async_event_t. - zend_async_event_t* awaitable = zval_to_event(current); + zend_async_event_t *awaitable = zval_to_event(current); if (UNEXPECTED(EG(exception))) { await_context->dtor(await_context); @@ -974,7 +953,7 @@ void async_await_futures( continue; } - async_await_callback_t * callback = ecalloc(1, sizeof(async_await_callback_t)); + async_await_callback_t *callback = ecalloc(1, sizeof(async_await_callback_t)); callback->callback.base.callback = async_waiting_callback; callback->await_context = await_context; @@ -1016,8 +995,8 @@ void async_await_futures( callback->prev_dispose = callback->callback.base.dispose; callback->callback.base.dispose = async_waiting_callback_dispose; await_context->ref_count++; - - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } else { // To launch the concurrent iterator, @@ -1025,7 +1004,7 @@ void async_await_futures( // Coroutines associated with concurrent iteration are created in a child Scope, // which ensures that all child tasks are stopped if the main task is cancelled. - zend_async_scope_t * scope = ZEND_ASYNC_NEW_SCOPE(ZEND_ASYNC_CURRENT_SCOPE); + zend_async_scope_t *scope = ZEND_ASYNC_NEW_SCOPE(ZEND_ASYNC_CURRENT_SCOPE); if (UNEXPECTED(scope == NULL || EG(exception))) { zend_iterator_dtor(zend_iterator); @@ -1033,7 +1012,7 @@ void async_await_futures( return; } - zend_coroutine_t * iterator_coroutine = ZEND_ASYNC_SPAWN_WITH_SCOPE_EX(scope, ZEND_COROUTINE_NORMAL); + zend_coroutine_t *iterator_coroutine = ZEND_ASYNC_SPAWN_WITH_SCOPE_EX(scope, ZEND_COROUTINE_NORMAL); if (UNEXPECTED(iterator_coroutine == NULL || EG(exception))) { zend_iterator_dtor(zend_iterator); @@ -1045,7 +1024,7 @@ void async_await_futures( await_context->scope = scope; iterator_coroutine->internal_entry = iterator_coroutine_first_entry; - async_await_iterator_t * iterator = ecalloc(1, sizeof(async_await_iterator_t)); + async_await_iterator_t *iterator = ecalloc(1, sizeof(async_await_iterator_t)); iterator->zend_iterator = zend_iterator; iterator->waiting_coroutine = coroutine; iterator->iterator_coroutine = iterator_coroutine; @@ -1054,9 +1033,7 @@ void async_await_futures( iterator_coroutine->extended_data = iterator; iterator_coroutine->extended_dispose = async_await_iterator_coroutine_dispose; - zend_async_resume_when( - coroutine, &iterator_coroutine->event, false, iterator_coroutine_finish_callback, NULL - ); + zend_async_resume_when(coroutine, &iterator_coroutine->event, false, iterator_coroutine_finish_callback, NULL); if (UNEXPECTED(EG(exception))) { // At this point, we don’t free the iterator @@ -1081,7 +1058,8 @@ void async_await_futures( // foreach results as key => value // if value is PTR then continue - ZEND_HASH_FOREACH_KEY_VAL(tmp_results, index, key, current) { + ZEND_HASH_FOREACH_KEY_VAL(tmp_results, index, key, current) + { if (Z_TYPE_P(current) == IS_PTR && Z_PTR_P(current) == NULL) { continue; } @@ -1095,7 +1073,8 @@ void async_await_futures( zval_add_ref(current); } } - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); await_context->results = NULL; zend_array_release(tmp_results); @@ -1104,56 +1083,55 @@ void async_await_futures( await_context->dtor(await_context); } -static zend_future_t* async_new_future_stub(bool thread_safe, size_t extra_size) +static zend_future_t *async_new_future_stub(bool thread_safe, size_t extra_size) { return NULL; } -static zend_async_channel_t* async_new_channel_stub(size_t buffer_size, bool resizable, bool thread_safe, size_t extra_size) +static zend_async_channel_t * +async_new_channel_stub(size_t buffer_size, bool resizable, bool thread_safe, size_t extra_size) { return NULL; } -static zend_object* async_new_future_obj_stub(zend_future_t *future) +static zend_object *async_new_future_obj_stub(zend_future_t *future) { return NULL; } -static zend_object* async_new_channel_obj_stub(zend_async_channel_t *channel) +static zend_object *async_new_channel_obj_stub(zend_async_channel_t *channel) { return NULL; } -static zend_async_group_t* async_new_group_stub(size_t extra_size) +static zend_async_group_t *async_new_group_stub(size_t extra_size) { return NULL; } void async_api_register(void) { - zend_async_scheduler_register( - PHP_ASYNC_NAME_VERSION, - false, - async_new_coroutine, - async_new_scope, - (zend_async_new_context_t)async_context_new, - spawn, - async_coroutine_suspend, - async_scheduler_coroutine_enqueue, - async_coroutine_resume, - async_coroutine_cancel, - async_spawn_and_throw, - start_graceful_shutdown, - get_coroutines, - add_microtask, - get_awaiting_info, - async_get_class_ce, - (zend_async_new_iterator_t)async_iterator_new, - async_new_future_stub, - async_new_channel_stub, - async_new_future_obj_stub, - async_new_channel_obj_stub, - async_new_group_stub, - engine_shutdown - ); + zend_async_scheduler_register(PHP_ASYNC_NAME_VERSION, + false, + async_new_coroutine, + async_new_scope, + (zend_async_new_context_t) async_context_new, + spawn, + async_coroutine_suspend, + async_scheduler_coroutine_enqueue, + async_coroutine_resume, + async_coroutine_cancel, + async_spawn_and_throw, + start_graceful_shutdown, + get_coroutines, + add_microtask, + get_awaiting_info, + async_get_class_ce, + (zend_async_new_iterator_t) async_iterator_new, + async_new_future_stub, + async_new_channel_stub, + async_new_future_obj_stub, + async_new_channel_obj_stub, + async_new_group_stub, + engine_shutdown); } \ No newline at end of file diff --git a/async_API.h b/async_API.h index 45be9ca..ad4a419 100644 --- a/async_API.h +++ b/async_API.h @@ -22,7 +22,7 @@ #include typedef struct _async_await_context_t async_await_context_t; -typedef void (*async_await_context_dtor_t) (async_await_context_t *context); +typedef void (*async_await_context_dtor_t)(async_await_context_t *context); struct _async_await_context_t { @@ -54,7 +54,7 @@ struct _async_await_context_t async_await_context_dtor_t dtor; HashTable *futures; // Scope for the new coroutines - zend_async_scope_t * scope; + zend_async_scope_t *scope; HashTable *results; HashTable *errors; }; @@ -70,33 +70,31 @@ typedef struct typedef struct { - zend_object_iterator * zend_iterator; - HashTable * futures; - zend_coroutine_t * iterator_coroutine; - zend_coroutine_t * waiting_coroutine; - async_await_context_t * await_context; + zend_object_iterator *zend_iterator; + HashTable *futures; + zend_coroutine_t *iterator_coroutine; + zend_coroutine_t *waiting_coroutine; + async_await_context_t *await_context; } async_await_iterator_t; typedef struct { async_iterator_t iterator; - async_await_iterator_t * await_iterator; + async_await_iterator_t *await_iterator; } async_await_iterator_iterator_t; void async_api_register(void); -void async_await_futures( - zval *iterable, - int count, - bool ignore_errors, - zend_async_event_t *cancellation, - zend_ulong timeout, - unsigned int concurrency, - HashTable *results, - HashTable *errors, - bool fill_missing_with_null, - bool preserve_key_order, - bool cancel_on_exit -); +void async_await_futures(zval *iterable, + int count, + bool ignore_errors, + zend_async_event_t *cancellation, + zend_ulong timeout, + unsigned int concurrency, + HashTable *results, + HashTable *errors, + bool fill_missing_with_null, + bool preserve_key_order, + bool cancel_on_exit); -#endif //ASYNC_API_H +#endif // ASYNC_API_H diff --git a/async_arginfo.h b/async_arginfo.h index a3ca625..fd3ebe1 100644 --- a/async_arginfo.h +++ b/async_arginfo.h @@ -2,69 +2,69 @@ * Stub hash: d217fc8dbb5aa518add60c4d99d3e7a356fbd41f */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_Async_spawn, 0, 1, Async\\Coroutine, 0) - ZEND_ARG_TYPE_INFO(0, task, IS_CALLABLE, 0) - ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) +ZEND_ARG_TYPE_INFO(0, task, IS_CALLABLE, 0) +ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_Async_spawnWith, 0, 2, Async\\Coroutine, 0) - ZEND_ARG_OBJ_INFO(0, provider, Async\\ScopeProvider, 0) - ZEND_ARG_TYPE_INFO(0, task, IS_CALLABLE, 0) - ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) +ZEND_ARG_OBJ_INFO(0, provider, Async\\ScopeProvider, 0) +ZEND_ARG_TYPE_INFO(0, task, IS_CALLABLE, 0) +ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_suspend, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_protect, 0, 1, IS_MIXED, 0) - ZEND_ARG_OBJ_INFO(0, closure, Closure, 0) +ZEND_ARG_OBJ_INFO(0, closure, Closure, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_await, 0, 1, IS_MIXED, 0) - ZEND_ARG_OBJ_INFO(0, awaitable, Async\\Awaitable, 0) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") +ZEND_ARG_OBJ_INFO(0, awaitable, Async\\Awaitable, 0) +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_awaitAnyOrFail, 0, 1, IS_MIXED, 0) - ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") +ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") ZEND_END_ARG_INFO() #define arginfo_Async_awaitFirstSuccess arginfo_Async_awaitAnyOrFail ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_awaitAllOrFail, 0, 1, IS_ARRAY, 0) - ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, preserveKeyOrder, _IS_BOOL, 0, "true") +ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") +ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, preserveKeyOrder, _IS_BOOL, 0, "true") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_awaitAll, 0, 1, IS_ARRAY, 0) - ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, preserveKeyOrder, _IS_BOOL, 0, "true") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, fillNull, _IS_BOOL, 0, "false") +ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") +ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, preserveKeyOrder, _IS_BOOL, 0, "true") +ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, fillNull, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_awaitAnyOfOrFail, 0, 2, IS_ARRAY, 0) - ZEND_ARG_TYPE_INFO(0, count, IS_LONG, 0) - ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, preserveKeyOrder, _IS_BOOL, 0, "true") +ZEND_ARG_TYPE_INFO(0, count, IS_LONG, 0) +ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") +ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, preserveKeyOrder, _IS_BOOL, 0, "true") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_awaitAnyOf, 0, 2, IS_ARRAY, 0) - ZEND_ARG_TYPE_INFO(0, count, IS_LONG, 0) - ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, preserveKeyOrder, _IS_BOOL, 0, "true") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, fillNull, _IS_BOOL, 0, "false") +ZEND_ARG_TYPE_INFO(0, count, IS_LONG, 0) +ZEND_ARG_OBJ_TYPE_MASK(0, triggers, Traversable, MAY_BE_ARRAY, NULL) +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") +ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, preserveKeyOrder, _IS_BOOL, 0, "true") +ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, fillNull, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_delay, 0, 1, IS_VOID, 0) - ZEND_ARG_TYPE_INFO(0, ms, IS_LONG, 0) +ZEND_ARG_TYPE_INFO(0, ms, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_Async_timeout, 0, 1, Async\\Awaitable, 0) - ZEND_ARG_TYPE_INFO(0, ms, IS_LONG, 0) +ZEND_ARG_TYPE_INFO(0, ms, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_Async_currentContext, 0, 0, Async\\Context, 0) @@ -81,7 +81,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_getCoroutines, 0, 0, IS_AR ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Async_gracefulShutdown, 0, 0, IS_VOID, 0) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellationException, Async\\CancellationException, 1, "null") +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellationException, Async\\CancellationException, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Async_Timeout___construct, 0, 0, 0) @@ -109,32 +109,112 @@ ZEND_FUNCTION(Async_gracefulShutdown); ZEND_METHOD(Async_Timeout, __construct); static const zend_function_entry ext_functions[] = { - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "spawn"), zif_Async_spawn, arginfo_Async_spawn, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "spawnWith"), zif_Async_spawnWith, arginfo_Async_spawnWith, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "suspend"), zif_Async_suspend, arginfo_Async_suspend, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "protect"), zif_Async_protect, arginfo_Async_protect, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "await"), zif_Async_await, arginfo_Async_await, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitAnyOrFail"), zif_Async_awaitAnyOrFail, arginfo_Async_awaitAnyOrFail, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitFirstSuccess"), zif_Async_awaitFirstSuccess, arginfo_Async_awaitFirstSuccess, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitAllOrFail"), zif_Async_awaitAllOrFail, arginfo_Async_awaitAllOrFail, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitAll"), zif_Async_awaitAll, arginfo_Async_awaitAll, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitAnyOfOrFail"), zif_Async_awaitAnyOfOrFail, arginfo_Async_awaitAnyOfOrFail, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitAnyOf"), zif_Async_awaitAnyOf, arginfo_Async_awaitAnyOf, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "delay"), zif_Async_delay, arginfo_Async_delay, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "timeout"), zif_Async_timeout, arginfo_Async_timeout, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "currentContext"), zif_Async_currentContext, arginfo_Async_currentContext, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "coroutineContext"), zif_Async_coroutineContext, arginfo_Async_coroutineContext, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "currentCoroutine"), zif_Async_currentCoroutine, arginfo_Async_currentCoroutine, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "rootContext"), zif_Async_rootContext, arginfo_Async_rootContext, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "getCoroutines"), zif_Async_getCoroutines, arginfo_Async_getCoroutines, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "gracefulShutdown"), zif_Async_gracefulShutdown, arginfo_Async_gracefulShutdown, 0, NULL, NULL) - ZEND_FE_END + ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "spawn"), + zif_Async_spawn, + arginfo_Async_spawn, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "spawnWith"), + zif_Async_spawnWith, + arginfo_Async_spawnWith, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "suspend"), + zif_Async_suspend, + arginfo_Async_suspend, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "protect"), + zif_Async_protect, + arginfo_Async_protect, + 0, + NULL, + NULL) + ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "await"), zif_Async_await, arginfo_Async_await, 0, NULL, NULL) + ZEND_RAW_FENTRY( + ZEND_NS_NAME("Async", "awaitAnyOrFail"), + zif_Async_awaitAnyOrFail, + arginfo_Async_awaitAnyOrFail, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitFirstSuccess"), + zif_Async_awaitFirstSuccess, + arginfo_Async_awaitFirstSuccess, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitAllOrFail"), + zif_Async_awaitAllOrFail, + arginfo_Async_awaitAllOrFail, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", + "awaitAll"), + zif_Async_awaitAll, + arginfo_Async_awaitAll, + 0, + NULL, + NULL) + ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitAnyOfOrFail"), + zif_Async_awaitAnyOfOrFail, + arginfo_Async_awaitAnyOfOrFail, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "awaitAnyOf"), + zif_Async_awaitAnyOf, + arginfo_Async_awaitAnyOf, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "delay"), + zif_Async_delay, + arginfo_Async_delay, + 0, + NULL, + NULL) + ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "timeout"), + zif_Async_timeout, + arginfo_Async_timeout, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "currentContext"), + zif_Async_currentContext, + arginfo_Async_currentContext, + 0, + NULL, + NULL) + ZEND_RAW_FENTRY( + ZEND_NS_NAME("Async", "coroutineContext"), + zif_Async_coroutineContext, + arginfo_Async_coroutineContext, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "currentCoroutine"), + zif_Async_currentCoroutine, + arginfo_Async_currentCoroutine, + 0, + NULL, + NULL) + ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "rootContext"), + zif_Async_rootContext, + arginfo_Async_rootContext, + 0, + NULL, + NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", + "getCoroutines"), + zif_Async_getCoroutines, + arginfo_Async_getCoroutines, + 0, + NULL, + NULL) + ZEND_RAW_FENTRY(ZEND_NS_NAME("Async", "gracefulShutdown"), + zif_Async_gracefulShutdown, + arginfo_Async_gracefulShutdown, + 0, + NULL, + NULL) ZEND_FE_END }; -static const zend_function_entry class_Async_Timeout_methods[] = { - ZEND_ME(Async_Timeout, __construct, arginfo_class_Async_Timeout___construct, ZEND_ACC_PRIVATE) - ZEND_FE_END -}; +static const zend_function_entry class_Async_Timeout_methods[] = { ZEND_ME( + Async_Timeout, __construct, arginfo_class_Async_Timeout___construct, ZEND_ACC_PRIVATE) ZEND_FE_END }; static zend_class_entry *register_class_Async_Awaitable(void) { diff --git a/context.c b/context.c index b2f67a7..197a3e1 100644 --- a/context.c +++ b/context.c @@ -22,7 +22,7 @@ /// Context API Implementation ////////////////////////////////////////////////////////////////////// -bool async_context_find(async_context_t * context, zval *key, zval *result, bool include_parent) +bool async_context_find(async_context_t *context, zval *key, zval *result, bool include_parent) { // First try to find in current context if (async_context_find_local(context, key, result)) { @@ -67,7 +67,7 @@ bool async_context_find(async_context_t * context, zval *key, zval *result, bool return false; } -void async_context_set(async_context_t * context, zval *key, zval *value) +void async_context_set(async_context_t *context, zval *key, zval *value) { if (Z_TYPE_P(key) == IS_STRING) { // String key @@ -86,12 +86,12 @@ void async_context_set(async_context_t * context, zval *key, zval *value) } } -bool async_context_has(async_context_t * context, zval *key, bool include_parent) +bool async_context_has(async_context_t *context, zval *key, bool include_parent) { return async_context_find(context, key, NULL, include_parent); } -bool async_context_unset(async_context_t * context, zval *key) +bool async_context_unset(async_context_t *context, zval *key) { bool deleted = false; @@ -114,7 +114,7 @@ bool async_context_unset(async_context_t * context, zval *key) return deleted; } -bool async_context_find_local(async_context_t * context, zval *key, zval *result) +bool async_context_find_local(async_context_t *context, zval *key, zval *result) { zval *found = NULL; @@ -147,7 +147,7 @@ bool async_context_find_local(async_context_t * context, zval *key, zval *result return false; } -bool async_context_has_local(async_context_t * context, zval *key) +bool async_context_has_local(async_context_t *context, zval *key) { if (Z_TYPE_P(key) == IS_STRING) { // String key @@ -164,14 +164,14 @@ bool async_context_has_local(async_context_t * context, zval *key) async_context_t *async_context_new(void) { async_context_t *context = zend_object_alloc(sizeof(async_context_t), async_ce_context); - + // Initialize hash tables directly zend_hash_init(&context->values, 8, NULL, ZVAL_PTR_DTOR, 0); zend_hash_init(&context->keys, 8, NULL, ZVAL_PTR_DTOR, 0); - + // Initialize scope reference as NULL (weak reference) context->scope = NULL; - + // Initialize base context function pointers context->base.find = (zend_async_context_find_t) async_context_find; context->base.set = (zend_async_context_set_t) async_context_set; @@ -199,20 +199,20 @@ void async_context_dispose(async_context_t *context) zend_class_entry *async_ce_context = NULL; #define METHOD(name) ZEND_METHOD(Async_Context, name) -#define ZEND_OBJECT_TO_CONTEXT(obj) ((async_context_t *)((char *)(obj) - (obj)->handlers->offset)) +#define ZEND_OBJECT_TO_CONTEXT(obj) ((async_context_t *) ((char *) (obj) - (obj)->handlers->offset)) #define THIS_CONTEXT ZEND_OBJECT_TO_CONTEXT(Z_OBJ_P(ZEND_THIS)) METHOD(find) { zval *key; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(key) + Z_PARAM_ZVAL(key) ZEND_PARSE_PARAMETERS_END(); if (async_context_find(THIS_CONTEXT, key, return_value, true)) { return; } - + RETURN_NULL(); } @@ -220,13 +220,13 @@ METHOD(get) { zval *key; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(key) + Z_PARAM_ZVAL(key) ZEND_PARSE_PARAMETERS_END(); if (async_context_find(THIS_CONTEXT, key, return_value, true)) { return; } - + RETURN_NULL(); } @@ -234,7 +234,7 @@ METHOD(has) { zval *key; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(key) + Z_PARAM_ZVAL(key) ZEND_PARSE_PARAMETERS_END(); RETURN_BOOL(async_context_find(THIS_CONTEXT, key, NULL, true)); @@ -244,13 +244,13 @@ METHOD(findLocal) { zval *key; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(key) + Z_PARAM_ZVAL(key) ZEND_PARSE_PARAMETERS_END(); if (async_context_find_local(THIS_CONTEXT, key, return_value)) { return; } - + RETURN_NULL(); } @@ -258,13 +258,13 @@ METHOD(getLocal) { zval *key; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(key) + Z_PARAM_ZVAL(key) ZEND_PARSE_PARAMETERS_END(); if (async_context_find_local(THIS_CONTEXT, key, return_value)) { return; } - + RETURN_NULL(); } @@ -272,7 +272,7 @@ METHOD(hasLocal) { zval *key; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(key) + Z_PARAM_ZVAL(key) ZEND_PARSE_PARAMETERS_END(); RETURN_BOOL(async_context_has_local(THIS_CONTEXT, key)); @@ -282,12 +282,12 @@ METHOD(set) { zval *key, *value; bool replace = false; - + ZEND_PARSE_PARAMETERS_START(2, 3) - Z_PARAM_ZVAL(key) - Z_PARAM_ZVAL(value) - Z_PARAM_OPTIONAL - Z_PARAM_BOOL(replace) + Z_PARAM_ZVAL(key) + Z_PARAM_ZVAL(value) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(replace) ZEND_PARSE_PARAMETERS_END(); async_context_t *context = THIS_CONTEXT; @@ -297,9 +297,9 @@ METHOD(set) async_throw_error("Context key already exists and replace is false"); RETURN_THROWS(); } - + async_context_set(context, key, value); - + RETURN_OBJ_COPY(&context->std); } @@ -307,13 +307,13 @@ METHOD(unset) { zval *key; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(key) + Z_PARAM_ZVAL(key) ZEND_PARSE_PARAMETERS_END(); async_context_t *context = THIS_CONTEXT; async_context_unset(context, key); - + RETURN_OBJ_COPY(&context->std); } @@ -326,7 +326,7 @@ static zend_object *context_object_create(zend_class_entry *class_entry) static void context_object_destroy(zend_object *object) { async_context_t *context = ZEND_OBJECT_TO_CONTEXT(object); - + // Destroy hash tables zend_hash_destroy(&context->values); zend_hash_destroy(&context->keys); @@ -340,9 +340,9 @@ static void context_free(zend_object *object) void async_register_context_ce(void) { async_ce_context = register_class_Async_Context(); - + async_ce_context->create_object = context_object_create; - + // Set up object handlers static zend_object_handlers context_handlers; context_handlers = std_object_handlers; @@ -350,6 +350,6 @@ void async_register_context_ce(void) context_handlers.clone_obj = NULL; context_handlers.dtor_obj = context_object_destroy; context_handlers.free_obj = context_free; - + async_ce_context->default_object_handlers = &context_handlers; } \ No newline at end of file diff --git a/context.h b/context.h index bd17e5c..767bb91 100644 --- a/context.h +++ b/context.h @@ -20,20 +20,21 @@ typedef struct _async_context_s async_context_t; -struct _async_context_s { +struct _async_context_s +{ zend_async_context_t base; HashTable values; HashTable keys; - zend_async_scope_t *scope; /* Associated scope - weak reference */ + zend_async_scope_t *scope; /* Associated scope - weak reference */ zend_object std; }; -bool async_context_find(async_context_t * context, zval *key, zval *result, bool include_parent); -bool async_context_find_local(async_context_t * context, zval *key, zval *result); -void async_context_set(async_context_t * context, zval *key, zval *value); -bool async_context_has(async_context_t * context, zval *key, bool include_parent); -bool async_context_has_local(async_context_t * context, zval *key); -bool async_context_unset(async_context_t * context, zval *key); +bool async_context_find(async_context_t *context, zval *key, zval *result, bool include_parent); +bool async_context_find_local(async_context_t *context, zval *key, zval *result); +void async_context_set(async_context_t *context, zval *key, zval *value); +bool async_context_has(async_context_t *context, zval *key, bool include_parent); +bool async_context_has_local(async_context_t *context, zval *key); +bool async_context_unset(async_context_t *context, zval *key); async_context_t *async_context_new(void); void async_context_dispose(async_context_t *context); @@ -43,4 +44,4 @@ extern zend_class_entry *async_ce_context; void async_register_context_ce(void); -#endif //CONTEXT_H \ No newline at end of file +#endif // CONTEXT_H \ No newline at end of file diff --git a/context_arginfo.h b/context_arginfo.h index 16b0958..112f62d 100644 --- a/context_arginfo.h +++ b/context_arginfo.h @@ -2,13 +2,13 @@ * Stub hash: bb8f3ff840be0001815129aa778f2c91b5701873 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Context_find, 0, 1, IS_MIXED, 0) - ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_OBJECT, NULL) +ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING | MAY_BE_OBJECT, NULL) ZEND_END_ARG_INFO() #define arginfo_class_Async_Context_get arginfo_class_Async_Context_find ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Context_has, 0, 1, _IS_BOOL, 0) - ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_OBJECT, NULL) +ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING | MAY_BE_OBJECT, NULL) ZEND_END_ARG_INFO() #define arginfo_class_Async_Context_findLocal arginfo_class_Async_Context_find @@ -18,13 +18,13 @@ ZEND_END_ARG_INFO() #define arginfo_class_Async_Context_hasLocal arginfo_class_Async_Context_has ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Async_Context_set, 0, 2, Async\\Context, 0) - ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_OBJECT, NULL) - ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, replace, _IS_BOOL, 0, "false") +ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING | MAY_BE_OBJECT, NULL) +ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) +ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, replace, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Async_Context_unset, 0, 1, Async\\Context, 0) - ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_OBJECT, NULL) +ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING | MAY_BE_OBJECT, NULL) ZEND_END_ARG_INFO() ZEND_METHOD(Async_Context, find); @@ -37,15 +37,15 @@ ZEND_METHOD(Async_Context, set); ZEND_METHOD(Async_Context, unset); static const zend_function_entry class_Async_Context_methods[] = { - ZEND_ME(Async_Context, find, arginfo_class_Async_Context_find, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Context, get, arginfo_class_Async_Context_get, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Context, has, arginfo_class_Async_Context_has, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Context, findLocal, arginfo_class_Async_Context_findLocal, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Context, getLocal, arginfo_class_Async_Context_getLocal, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Context, hasLocal, arginfo_class_Async_Context_hasLocal, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Context, set, arginfo_class_Async_Context_set, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Context, unset, arginfo_class_Async_Context_unset, ZEND_ACC_PUBLIC) - ZEND_FE_END + ZEND_ME(Async_Context, find, arginfo_class_Async_Context_find, ZEND_ACC_PUBLIC) ZEND_ME( + Async_Context, get, arginfo_class_Async_Context_get, ZEND_ACC_PUBLIC) + ZEND_ME(Async_Context, has, arginfo_class_Async_Context_has, ZEND_ACC_PUBLIC) ZEND_ME( + Async_Context, findLocal, arginfo_class_Async_Context_findLocal, ZEND_ACC_PUBLIC) + ZEND_ME(Async_Context, getLocal, arginfo_class_Async_Context_getLocal, ZEND_ACC_PUBLIC) ZEND_ME( + Async_Context, hasLocal, arginfo_class_Async_Context_hasLocal, ZEND_ACC_PUBLIC) + ZEND_ME(Async_Context, set, arginfo_class_Async_Context_set, ZEND_ACC_PUBLIC) + ZEND_ME(Async_Context, unset, arginfo_class_Async_Context_unset, ZEND_ACC_PUBLIC) + ZEND_FE_END }; static zend_class_entry *register_class_Async_Context(void) @@ -53,7 +53,8 @@ static zend_class_entry *register_class_Async_Context(void) zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "Async", "Context", class_Async_Context_methods); - class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + class_entry = zend_register_internal_class_with_flags( + &ce, NULL, ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES | ZEND_ACC_NOT_SERIALIZABLE); return class_entry; } diff --git a/coroutine.c b/coroutine.c index 07c3529..722f5cf 100644 --- a/coroutine.c +++ b/coroutine.c @@ -30,7 +30,7 @@ #define METHOD(name) PHP_METHOD(Async_Coroutine, name) -zend_class_entry * async_ce_coroutine = NULL; +zend_class_entry *async_ce_coroutine = NULL; static zend_function coroutine_root_function = { ZEND_INTERNAL_FUNCTION }; @@ -61,7 +61,7 @@ METHOD(getContext) async_coroutine_t *coroutine = THIS_COROUTINE; if (coroutine->coroutine.context == NULL) { - async_context_t * context = async_context_new(); + async_context_t *context = async_context_new(); if (UNEXPECTED(context == NULL)) { RETURN_THROWS(); } @@ -138,9 +138,7 @@ METHOD(getSpawnLocation) async_coroutine_t *coroutine = THIS_COROUTINE; if (coroutine->coroutine.filename) { - RETURN_STR(zend_strpprintf(0, "%s:%d", - ZSTR_VAL(coroutine->coroutine.filename), - coroutine->coroutine.lineno)); + RETURN_STR(zend_strpprintf(0, "%s:%d", ZSTR_VAL(coroutine->coroutine.filename), coroutine->coroutine.lineno)); } else { RETURN_STRING("unknown"); } @@ -170,9 +168,8 @@ METHOD(getSuspendLocation) async_coroutine_t *coroutine = THIS_COROUTINE; if (coroutine->coroutine.waker && coroutine->coroutine.waker->filename) { - RETURN_STR(zend_strpprintf(0, "%s:%d", - ZSTR_VAL(coroutine->coroutine.waker->filename), - coroutine->coroutine.waker->lineno)); + RETURN_STR(zend_strpprintf( + 0, "%s:%d", ZSTR_VAL(coroutine->coroutine.waker->filename), coroutine->coroutine.waker->lineno)); } else { RETURN_STRING("unknown"); } @@ -204,8 +201,8 @@ METHOD(isRunning) async_coroutine_t *coroutine = THIS_COROUTINE; // Coroutine is running if it's the current one and is started but not finished - RETURN_BOOL(ZEND_COROUTINE_IS_STARTED(&coroutine->coroutine) - && false == ZEND_COROUTINE_IS_FINISHED(&coroutine->coroutine)); + RETURN_BOOL(ZEND_COROUTINE_IS_STARTED(&coroutine->coroutine) && + false == ZEND_COROUTINE_IS_FINISHED(&coroutine->coroutine)); } METHOD(isSuspended) @@ -219,8 +216,8 @@ METHOD(isCancelled) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_BOOL(ZEND_COROUTINE_IS_CANCELLED(&THIS_COROUTINE->coroutine) - && ZEND_COROUTINE_IS_FINISHED(&THIS_COROUTINE->coroutine)); + RETURN_BOOL(ZEND_COROUTINE_IS_CANCELLED(&THIS_COROUTINE->coroutine) && + ZEND_COROUTINE_IS_FINISHED(&THIS_COROUTINE->coroutine)); } METHOD(isCancellationRequested) @@ -229,9 +226,9 @@ METHOD(isCancellationRequested) async_coroutine_t *coroutine = THIS_COROUTINE; - RETURN_BOOL((ZEND_COROUTINE_IS_CANCELLED(&coroutine->coroutine) - && !ZEND_COROUTINE_IS_FINISHED(&coroutine->coroutine)) - || coroutine->deferred_cancellation != NULL); + RETURN_BOOL((ZEND_COROUTINE_IS_CANCELLED(&coroutine->coroutine) && + !ZEND_COROUTINE_IS_FINISHED(&coroutine->coroutine)) || + coroutine->deferred_cancellation != NULL); } METHOD(isFinished) @@ -259,8 +256,8 @@ METHOD(cancel) zend_object *exception = NULL; ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL; - Z_PARAM_OBJ_OF_CLASS_OR_NULL(exception, zend_ce_cancellation_exception) + Z_PARAM_OPTIONAL; + Z_PARAM_OBJ_OF_CLASS_OR_NULL(exception, zend_ce_cancellation_exception) ZEND_PARSE_PARAMETERS_END(); ZEND_ASYNC_CANCEL(&THIS_COROUTINE->coroutine, exception, false); @@ -271,7 +268,7 @@ METHOD(onFinally) zval *callable; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(callable) + Z_PARAM_ZVAL(callable) ZEND_PARSE_PARAMETERS_END(); if (UNEXPECTED(false == zend_is_callable(callable, 0, NULL))) { @@ -351,7 +348,7 @@ static zend_result finally_handlers_iterator_handler(async_iterator_t *iterator, context->composite_exception = current_exception; } else if (!instanceof_function(context->composite_exception->ce, async_ce_composite_exception)) { // Create CompositeException and add first exception - zend_object * composite_exception = async_new_composite_exception(); + zend_object *composite_exception = async_new_composite_exception(); if (UNEXPECTED(composite_exception == NULL)) { // If we can't create CompositeException, throw the current one async_rethrow_exception(current_exception); @@ -372,7 +369,7 @@ static zend_result finally_handlers_iterator_handler(async_iterator_t *iterator, static void finally_handlers_iterator_dtor(zend_async_iterator_t *zend_iterator) { - async_iterator_t * iterator = (async_iterator_t *) zend_iterator; + async_iterator_t *iterator = (async_iterator_t *) zend_iterator; if (UNEXPECTED(iterator->extended_data == NULL)) { return; @@ -384,20 +381,18 @@ static void finally_handlers_iterator_dtor(zend_async_iterator_t *zend_iterator) // Throw CompositeException if any exceptions were collected if (context->composite_exception != NULL) { - if (ZEND_ASYNC_SCOPE_CATCH( - &scope->scope, - &context->coroutine->coroutine, - NULL, - context->composite_exception, - false, - ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(&scope->scope) - )) { + if (ZEND_ASYNC_SCOPE_CATCH(&scope->scope, + &context->coroutine->coroutine, + NULL, + context->composite_exception, + false, + ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(&scope->scope))) { OBJ_RELEASE(context->composite_exception); context->composite_exception = NULL; } } - zend_object * composite_exception = context->composite_exception; + zend_object *composite_exception = context->composite_exception; context->composite_exception = NULL; if (context->dtor != NULL) { @@ -443,16 +438,8 @@ bool async_call_finally_handlers(HashTable *finally_handlers, finally_handlers_c zval handlers; ZVAL_ARR(&handlers, finally_handlers); - async_iterator_t * iterator = async_iterator_new( - &handlers, - NULL, - NULL, - finally_handlers_iterator_handler, - child_scope, - 0, - priority, - 0 - ); + async_iterator_t *iterator = + async_iterator_new(&handlers, NULL, NULL, finally_handlers_iterator_handler, child_scope, 0, priority, 0); zval_ptr_dtor(&handlers); @@ -488,7 +475,7 @@ static zend_always_inline async_coroutine_t *coroutine_from_context(zend_fiber_c { ZEND_ASSERT(context->kind == async_ce_coroutine && "Fiber context does not belong to a Coroutine fiber"); - return (async_coroutine_t *)(((char *) context) - XtOffsetOf(async_coroutine_t, context)); + return (async_coroutine_t *) (((char *) context) - XtOffsetOf(async_coroutine_t, context)); } void async_coroutine_cleanup(zend_fiber_context *context) @@ -513,7 +500,7 @@ static void finally_context_dtor(finally_handlers_context_t *context) } } -static zend_always_inline void coroutine_call_finally_handlers(async_coroutine_t * coroutine) +static zend_always_inline void coroutine_call_finally_handlers(async_coroutine_t *coroutine) { HashTable *finally_handlers = coroutine->finally_handlers; coroutine->finally_handlers = NULL; @@ -532,7 +519,7 @@ static zend_always_inline void coroutine_call_finally_handlers(async_coroutine_t } } -void async_coroutine_finalize(zend_fiber_transfer *transfer, async_coroutine_t * coroutine) +void async_coroutine_finalize(zend_fiber_transfer *transfer, async_coroutine_t *coroutine) { // Before finalizing the coroutine // we check that we’re properly finishing the coroutine’s execution. @@ -550,13 +537,14 @@ void async_coroutine_finalize(zend_fiber_transfer *transfer, async_coroutine_t * bool do_bailout = false; - zend_try { + zend_try + { /* Cleanup switch handlers */ zend_coroutine_switch_handlers_destroy(&coroutine->coroutine); // call coroutines handlers - zend_object * exception = NULL; + zend_object *exception = NULL; if (EG(exception)) { if (EG(prev_exception)) { @@ -621,23 +609,22 @@ void async_coroutine_finalize(zend_fiber_transfer *transfer, async_coroutine_t * // If the exception was handled by any handler, we do not propagate it further. // Cancellation-type exceptions are considered handled in all cases and are not propagated further. - if (exception != NULL - && (ZEND_COROUTINE_IS_EXCEPTION_HANDLED(&coroutine->coroutine) - || instanceof_function(exception->ce, zend_ce_cancellation_exception))) { + if (exception != NULL && + (ZEND_COROUTINE_IS_EXCEPTION_HANDLED(&coroutine->coroutine) || + instanceof_function(exception->ce, zend_ce_cancellation_exception))) { OBJ_RELEASE(exception); exception = NULL; } // Before the exception leads to graceful termination, // we give one last chance to handle it using Scope handlers. - if (exception != NULL && ZEND_ASYNC_SCOPE_CATCH( - coroutine->coroutine.scope, - &coroutine->coroutine, - NULL, - exception, - false, - ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(coroutine->coroutine.scope) - )) { + if (exception != NULL && + ZEND_ASYNC_SCOPE_CATCH(coroutine->coroutine.scope, + &coroutine->coroutine, + NULL, + exception, + false, + ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(coroutine->coroutine.scope))) { OBJ_RELEASE(exception); exception = NULL; } @@ -653,15 +640,16 @@ void async_coroutine_finalize(zend_fiber_transfer *transfer, async_coroutine_t * if (exception != NULL) { async_rethrow_exception(exception); } - - } zend_catch { + } + zend_catch + { do_bailout = true; - } zend_end_try(); + } + zend_end_try(); if (UNEXPECTED(EG(exception))) { - if (!(coroutine->flags & ZEND_FIBER_FLAG_DESTROYED) - || !(zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception))) - ) { + if (!(coroutine->flags & ZEND_FIBER_FLAG_DESTROYED) || + !(zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception)))) { coroutine->flags |= ZEND_FIBER_FLAG_THREW; transfer->flags = ZEND_FIBER_TRANSFER_FLAG_ERROR; @@ -697,14 +685,14 @@ void async_coroutine_finalize(zend_fiber_transfer *transfer, async_coroutine_t * * * @param coroutine The coroutine to finalize. */ -void async_coroutine_finalize_from_scheduler(async_coroutine_t * coroutine) +void async_coroutine_finalize_from_scheduler(async_coroutine_t *coroutine) { - zend_async_waker_t * waker = coroutine->coroutine.waker; + zend_async_waker_t *waker = coroutine->coroutine.waker; ZEND_ASSERT(waker != NULL && "Waker must not be NULL when finalizing coroutine from scheduler"); // Save EG(exception) state - zend_object * prev_exception = EG(prev_exception); - zend_object * exception = EG(exception); + zend_object *prev_exception = EG(prev_exception); + zend_object *exception = EG(exception); EG(exception) = waker->error; EG(prev_exception) = NULL; @@ -714,15 +702,19 @@ void async_coroutine_finalize_from_scheduler(async_coroutine_t * coroutine) bool do_bailout = false; - zend_try { + zend_try + { async_coroutine_finalize(NULL, coroutine); - } zend_catch { + } + zend_catch + { do_bailout = true; - } zend_end_try(); + } + zend_end_try(); // If an exception occurs during finalization, we need to restore the previous exception state - zend_object * new_exception = EG(exception); - zend_object * new_prev_exception = EG(prev_exception); + zend_object *new_exception = EG(exception); + zend_object *new_prev_exception = EG(prev_exception); EG(exception) = exception; EG(prev_exception) = prev_exception; @@ -762,7 +754,8 @@ ZEND_STACK_ALIGNED void async_coroutine_execute(zend_fiber_transfer *transfer) EG(vm_stack) = NULL; bool should_start_graceful_shutdown = false; - zend_first_try { + zend_first_try + { zend_vm_stack stack = zend_vm_stack_new_page(ZEND_FIBER_VM_STACK_SIZE, NULL); EG(vm_stack) = stack; EG(vm_stack_top) = stack->top + ZEND_CALL_FRAME_SLOT; @@ -784,8 +777,7 @@ ZEND_STACK_ALIGNED void async_coroutine_execute(zend_fiber_transfer *transfer) EG(stack_limit) = zend_fiber_stack_limit(coroutine->context.stack); #endif - if (EXPECTED(coroutine->coroutine.internal_entry == NULL)) - { + if (EXPECTED(coroutine->coroutine.internal_entry == NULL)) { ZEND_ASSERT(coroutine->coroutine.fcall != NULL && "Coroutine function call is not set"); coroutine->coroutine.fcall->fci.retval = &coroutine->coroutine.result; @@ -796,30 +788,41 @@ ZEND_STACK_ALIGNED void async_coroutine_execute(zend_fiber_transfer *transfer) } else { coroutine->coroutine.internal_entry(); } - - } zend_catch { + } + zend_catch + { coroutine->flags |= ZEND_FIBER_FLAG_BAILOUT; transfer->flags = ZEND_FIBER_TRANSFER_FLAG_BAILOUT; should_start_graceful_shutdown = true; - } zend_end_try(); + } + zend_end_try(); - zend_first_try { + zend_first_try + { async_coroutine_finalize(transfer, coroutine); - } zend_catch { + } + zend_catch + { coroutine->flags |= ZEND_FIBER_FLAG_BAILOUT; transfer->flags = ZEND_FIBER_TRANSFER_FLAG_BAILOUT; should_start_graceful_shutdown = true; - } zend_end_try(); + } + zend_end_try(); coroutine->context.cleanup = &async_coroutine_cleanup; coroutine->vm_stack = EG(vm_stack); if (UNEXPECTED(should_start_graceful_shutdown)) { - zend_first_try { + zend_first_try + { ZEND_ASYNC_SHUTDOWN(); - } zend_catch { - zend_error(E_CORE_WARNING, "A critical error was detected during the initiation of the graceful shutdown mode."); - } zend_end_try(); + } + zend_catch + { + zend_error(E_CORE_WARNING, + "A critical error was detected during the initiation of the graceful shutdown mode."); + } + zend_end_try(); } // @@ -832,9 +835,11 @@ ZEND_STACK_ALIGNED void async_coroutine_execute(zend_fiber_transfer *transfer) if (transfer != ASYNC_G(main_transfer)) { if (UNEXPECTED(Z_TYPE(transfer->value) == IS_OBJECT)) { - zend_first_try { + zend_first_try + { zval_ptr_dtor(&transfer->value); - } zend_end_try(); + } + zend_end_try(); zend_error(E_CORE_WARNING, "The transfer value must be NULL when the main coroutine is resumed"); } @@ -879,7 +884,10 @@ static void coroutine_del_callback(zend_async_event_t *event, zend_async_event_c * @param result The result to copy into, if not NULL. * @param exception The exception to set, if not NULL. */ -static bool coroutine_replay(zend_async_event_t *event, zend_async_event_callback_t *callback, zval *result, zend_object **exception) +static bool coroutine_replay(zend_async_event_t *event, + zend_async_event_callback_t *callback, + zval *result, + zend_object **exception) { async_coroutine_t *coroutine = (async_coroutine_t *) event; @@ -908,30 +916,29 @@ static bool coroutine_replay(zend_async_event_t *event, zend_async_event_callbac return coroutine->coroutine.exception != NULL || Z_TYPE(coroutine->coroutine.result) != IS_UNDEF; } -static zend_string* coroutine_info(zend_async_event_t *event) +static zend_string *coroutine_info(zend_async_event_t *event) { async_coroutine_t *coroutine = (async_coroutine_t *) event; - zend_string * zend_coroutine_name = zend_coroutine_callable_name(&coroutine->coroutine); + zend_string *zend_coroutine_name = zend_coroutine_callable_name(&coroutine->coroutine); if (ZEND_COROUTINE_SUSPENDED(&coroutine->coroutine)) { return zend_strpprintf(0, - "Coroutine %d spawned at %s:%d, suspended at %s:%d (%s)", - coroutine->std.handle, - coroutine->coroutine.filename ? ZSTR_VAL(coroutine->coroutine.filename) : "", - coroutine->coroutine.lineno, - coroutine->coroutine.waker->filename ? ZSTR_VAL(coroutine->coroutine.waker->filename) : "", - coroutine->coroutine.waker->lineno, - ZSTR_VAL(zend_coroutine_name) - ); + "Coroutine %d spawned at %s:%d, suspended at %s:%d (%s)", + coroutine->std.handle, + coroutine->coroutine.filename ? ZSTR_VAL(coroutine->coroutine.filename) : "", + coroutine->coroutine.lineno, + coroutine->coroutine.waker->filename ? ZSTR_VAL(coroutine->coroutine.waker->filename) + : "", + coroutine->coroutine.waker->lineno, + ZSTR_VAL(zend_coroutine_name)); } else { return zend_strpprintf(0, - "Coroutine %d spawned at %s:%d (%s)", - coroutine->std.handle, - coroutine->coroutine.filename ? ZSTR_VAL(coroutine->coroutine.filename) : "", - coroutine->coroutine.lineno, - ZSTR_VAL(zend_coroutine_name) - ); + "Coroutine %d spawned at %s:%d (%s)", + coroutine->std.handle, + coroutine->coroutine.filename ? ZSTR_VAL(coroutine->coroutine.filename) : "", + coroutine->coroutine.lineno, + ZSTR_VAL(zend_coroutine_name)); } } @@ -951,7 +958,7 @@ void async_coroutine_suspend(const bool from_main) async_scheduler_coroutine_suspend(NULL); } -void async_coroutine_resume(zend_coroutine_t *coroutine, zend_object * error, const bool transfer_error) +void async_coroutine_resume(zend_coroutine_t *coroutine, zend_object *error, const bool transfer_error) { if (UNEXPECTED(coroutine->waker == NULL)) { async_throw_error("Cannot resume a coroutine that has not been suspended"); @@ -994,7 +1001,10 @@ void async_coroutine_resume(zend_coroutine_t *coroutine, zend_object * error, co coroutine->waker->status = ZEND_ASYNC_WAKER_QUEUED; } -void async_coroutine_cancel(zend_coroutine_t *zend_coroutine, zend_object *error, bool transfer_error, const bool is_safely) +void async_coroutine_cancel(zend_coroutine_t *zend_coroutine, + zend_object *error, + bool transfer_error, + const bool is_safely) { // If the coroutine finished, do nothing. if (ZEND_COROUTINE_IS_FINISHED(zend_coroutine)) { @@ -1022,9 +1032,7 @@ void async_coroutine_cancel(zend_coroutine_t *zend_coroutine, zend_object *error } if (zend_coroutine->exception == NULL) { - zend_coroutine->exception = async_new_exception( - async_ce_cancellation_exception, "Coroutine cancelled" - ); + zend_coroutine->exception = async_new_exception(async_ce_cancellation_exception, "Coroutine cancelled"); } return; @@ -1034,7 +1042,7 @@ void async_coroutine_cancel(zend_coroutine_t *zend_coroutine, zend_object *error zend_async_waker_new(zend_coroutine); } - zend_async_waker_t * waker = zend_coroutine->waker; + zend_async_waker_t *waker = zend_coroutine->waker; if (UNEXPECTED(waker == NULL)) { async_throw_error("Waker is not initialized"); @@ -1114,9 +1122,8 @@ void async_coroutine_cancel(zend_coroutine_t *zend_coroutine, zend_object *error return; } - if (was_cancelled - && waker->error != NULL - && instanceof_function(waker->error->ce, zend_ce_cancellation_exception)) { + if (was_cancelled && waker->error != NULL && + instanceof_function(waker->error->ce, zend_ce_cancellation_exception)) { if (transfer_error) { OBJ_RELEASE(error); } @@ -1138,9 +1145,9 @@ static void coroutine_object_destroy(zend_object *object) async_coroutine_t *coroutine = (async_coroutine_t *) ZEND_ASYNC_OBJECT_TO_EVENT(object); ZEND_ASSERT((coroutine->coroutine.waker == NULL || - (coroutine->coroutine.waker->status == ZEND_ASYNC_WAKER_QUEUED || - coroutine->coroutine.waker->status == ZEND_ASYNC_WAKER_IGNORED)) - && "Coroutine waker must be dequeued before destruction"); + (coroutine->coroutine.waker->status == ZEND_ASYNC_WAKER_QUEUED || + coroutine->coroutine.waker->status == ZEND_ASYNC_WAKER_IGNORED)) && + "Coroutine waker must be dequeued before destruction"); if (coroutine->coroutine.scope != NULL) { async_scope_notify_coroutine_finished(coroutine); @@ -1149,7 +1156,7 @@ static void coroutine_object_destroy(zend_object *object) if (coroutine->coroutine.fcall) { - zend_fcall_t * fcall = coroutine->coroutine.fcall; + zend_fcall_t *fcall = coroutine->coroutine.fcall; coroutine->coroutine.fcall = NULL; if (fcall->fci.param_count) { @@ -1255,7 +1262,7 @@ static zend_object *coroutine_object_create(zend_class_entry *class_entry) zend_coroutine_t *async_new_coroutine(zend_async_scope_t *scope) { - zend_object * object = coroutine_object_create(async_ce_coroutine); + zend_object *object = coroutine_object_create(async_ce_coroutine); if (UNEXPECTED(EG(exception))) { return NULL; @@ -1269,17 +1276,17 @@ zend_coroutine_t *async_new_coroutine(zend_async_scope_t *scope) static HashTable *async_coroutine_object_gc(zend_object *object, zval **table, int *num) { - async_coroutine_t *coroutine = (async_coroutine_t *)ZEND_ASYNC_OBJECT_TO_EVENT(object); + async_coroutine_t *coroutine = (async_coroutine_t *) ZEND_ASYNC_OBJECT_TO_EVENT(object); zend_get_gc_buffer *buf = zend_get_gc_buffer_create(); /* Always add basic ZVALs from coroutine structure */ zend_get_gc_buffer_add_zval(buf, &coroutine->coroutine.result); - + /* Add objects that may be present */ if (coroutine->coroutine.exception) { zend_get_gc_buffer_add_obj(buf, coroutine->coroutine.exception); } - + if (coroutine->deferred_cancellation) { zend_get_gc_buffer_add_obj(buf, coroutine->deferred_cancellation); } @@ -1287,23 +1294,27 @@ static HashTable *async_coroutine_object_gc(zend_object *object, zval **table, i /* Add finally handlers if present */ if (coroutine->finally_handlers) { zval *val; - ZEND_HASH_FOREACH_VAL(coroutine->finally_handlers, val) { + ZEND_HASH_FOREACH_VAL(coroutine->finally_handlers, val) + { zend_get_gc_buffer_add_zval(buf, val); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } /* Add internal context HashTable if present */ if (coroutine->coroutine.internal_context) { zval *val; - ZEND_HASH_FOREACH_VAL(coroutine->coroutine.internal_context, val) { + ZEND_HASH_FOREACH_VAL(coroutine->coroutine.internal_context, val) + { zend_get_gc_buffer_add_zval(buf, val); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } /* Add fcall function name and parameters if present */ if (coroutine->coroutine.fcall) { zend_get_gc_buffer_add_zval(buf, &coroutine->coroutine.fcall->fci.function_name); - + /* Add function parameters */ if (coroutine->coroutine.fcall->fci.param_count > 0 && coroutine->coroutine.fcall->fci.params) { for (uint32_t i = 0; i < coroutine->coroutine.fcall->fci.param_count; i++) { @@ -1315,15 +1326,16 @@ static HashTable *async_coroutine_object_gc(zend_object *object, zval **table, i /* Add waker-related ZVALs if present */ if (coroutine->coroutine.waker) { zend_get_gc_buffer_add_zval(buf, &coroutine->coroutine.waker->result); - + if (coroutine->coroutine.waker->error) { zend_get_gc_buffer_add_obj(buf, coroutine->coroutine.waker->error); } - + /* Add events HashTable contents */ zval *event_val; zval zval_object; - ZEND_HASH_FOREACH_VAL(&coroutine->coroutine.waker->events, event_val) { + ZEND_HASH_FOREACH_VAL(&coroutine->coroutine.waker->events, event_val) + { zend_async_event_t *event = (zend_async_event_t *) Z_PTR_P(event_val); @@ -1331,36 +1343,42 @@ static HashTable *async_coroutine_object_gc(zend_object *object, zval **table, i ZVAL_OBJ(&zval_object, ZEND_ASYNC_EVENT_TO_OBJECT(event)); zend_get_gc_buffer_add_zval(buf, &zval_object); } - } ZEND_HASH_FOREACH_END(); - + } + ZEND_HASH_FOREACH_END(); + /* Add triggered events if present */ if (coroutine->coroutine.waker->triggered_events) { - ZEND_HASH_FOREACH_VAL(coroutine->coroutine.waker->triggered_events, event_val) { + ZEND_HASH_FOREACH_VAL(coroutine->coroutine.waker->triggered_events, event_val) + { zend_get_gc_buffer_add_zval(buf, event_val); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } } /* Add context ZVALs if present */ if (coroutine->coroutine.context) { /* Cast to actual context implementation to access HashTables */ - async_context_t *context = (async_context_t *)coroutine->coroutine.context; - + async_context_t *context = (async_context_t *) coroutine->coroutine.context; + /* Add all values from context->values HashTable */ zval *val; - ZEND_HASH_FOREACH_VAL(&context->values, val) { + ZEND_HASH_FOREACH_VAL(&context->values, val) + { zend_get_gc_buffer_add_zval(buf, val); - } ZEND_HASH_FOREACH_END(); - + } + ZEND_HASH_FOREACH_END(); + /* Add all object keys from context->keys HashTable */ - ZEND_HASH_FOREACH_VAL(&context->keys, val) { + ZEND_HASH_FOREACH_VAL(&context->keys, val) + { zend_get_gc_buffer_add_zval(buf, val); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } /* Check if we should traverse execution stack (similar to fibers) */ - if (coroutine->context.status != ZEND_FIBER_STATUS_SUSPENDED || - !coroutine->execute_data) { + if (coroutine->context.status != ZEND_FIBER_STATUS_SUSPENDED || !coroutine->execute_data) { zend_get_gc_buffer_use(buf, table, num); return NULL; } @@ -1371,25 +1389,26 @@ static HashTable *async_coroutine_object_gc(zend_object *object, zval **table, i for (; ex; ex = ex->prev_execute_data) { HashTable *symTable; if (ZEND_CALL_INFO(ex) & ZEND_CALL_GENERATOR) { - zend_generator *generator = (zend_generator*)ex->return_value; + zend_generator *generator = (zend_generator *) ex->return_value; if (!(generator->flags & ZEND_GENERATOR_CURRENTLY_RUNNING)) { continue; } symTable = zend_generator_frame_gc(buf, generator); } else { - symTable = zend_unfinished_execution_gc_ex(ex, - ex->func && ZEND_USER_CODE(ex->func->type) ? ex->call : NULL, - buf, false); + symTable = zend_unfinished_execution_gc_ex( + ex, ex->func && ZEND_USER_CODE(ex->func->type) ? ex->call : NULL, buf, false); } if (symTable) { if (lastSymTable) { zval *val; - ZEND_HASH_FOREACH_VAL(lastSymTable, val) { + ZEND_HASH_FOREACH_VAL(lastSymTable, val) + { if (EXPECTED(Z_TYPE_P(val) == IS_INDIRECT)) { val = Z_INDIRECT_P(val); } zend_get_gc_buffer_add_zval(buf, val); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } lastSymTable = symTable; } @@ -1422,9 +1441,10 @@ void async_register_coroutine_ce(void) ////////////////////////////////////////////////////////////////////// -bool async_coroutine_context_set(zend_coroutine_t * z_coroutine, zval *key, zval *value) +bool async_coroutine_context_set(zend_coroutine_t *z_coroutine, zval *key, zval *value) { - async_coroutine_t * coroutine = (async_coroutine_t *) (z_coroutine != NULL ? z_coroutine : ZEND_ASYNC_CURRENT_COROUTINE); + async_coroutine_t *coroutine = + (async_coroutine_t *) (z_coroutine != NULL ? z_coroutine : ZEND_ASYNC_CURRENT_COROUTINE); if (UNEXPECTED(coroutine == NULL || coroutine->coroutine.context == NULL)) { return false; @@ -1434,9 +1454,10 @@ bool async_coroutine_context_set(zend_coroutine_t * z_coroutine, zval *key, zval return true; } -bool async_coroutine_context_get(zend_coroutine_t * z_coroutine, zval *key, zval *result) +bool async_coroutine_context_get(zend_coroutine_t *z_coroutine, zval *key, zval *result) { - async_coroutine_t * coroutine = (async_coroutine_t *) (z_coroutine != NULL ? z_coroutine : ZEND_ASYNC_CURRENT_COROUTINE); + async_coroutine_t *coroutine = + (async_coroutine_t *) (z_coroutine != NULL ? z_coroutine : ZEND_ASYNC_CURRENT_COROUTINE); if (UNEXPECTED(coroutine == NULL || coroutine->coroutine.context == NULL)) { if (result != NULL) { @@ -1448,9 +1469,10 @@ bool async_coroutine_context_get(zend_coroutine_t * z_coroutine, zval *key, zval return coroutine->coroutine.context->find(coroutine->coroutine.context, key, result, false); } -bool async_coroutine_context_has(zend_coroutine_t * z_coroutine, zval *key) +bool async_coroutine_context_has(zend_coroutine_t *z_coroutine, zval *key) { - async_coroutine_t * coroutine = (async_coroutine_t *) (z_coroutine != NULL ? z_coroutine : ZEND_ASYNC_CURRENT_COROUTINE); + async_coroutine_t *coroutine = + (async_coroutine_t *) (z_coroutine != NULL ? z_coroutine : ZEND_ASYNC_CURRENT_COROUTINE); if (UNEXPECTED(coroutine == NULL || coroutine->coroutine.context == NULL)) { return false; @@ -1459,9 +1481,10 @@ bool async_coroutine_context_has(zend_coroutine_t * z_coroutine, zval *key) return coroutine->coroutine.context->find(coroutine->coroutine.context, key, NULL, false); } -bool async_coroutine_context_delete(zend_coroutine_t * z_coroutine, zval *key) +bool async_coroutine_context_delete(zend_coroutine_t *z_coroutine, zval *key) { - async_coroutine_t * coroutine = (async_coroutine_t *) (z_coroutine != NULL ? z_coroutine : ZEND_ASYNC_CURRENT_COROUTINE); + async_coroutine_t *coroutine = + (async_coroutine_t *) (z_coroutine != NULL ? z_coroutine : ZEND_ASYNC_CURRENT_COROUTINE); if (UNEXPECTED(coroutine == NULL || coroutine->coroutine.context == NULL)) { return false; diff --git a/coroutine.h b/coroutine.h index 2223b64..e4affea 100644 --- a/coroutine.h +++ b/coroutine.h @@ -19,11 +19,12 @@ #include ZEND_STACK_ALIGNED void async_coroutine_execute(zend_fiber_transfer *transfer); -extern zend_class_entry * async_ce_coroutine; +extern zend_class_entry *async_ce_coroutine; typedef struct _async_coroutine_s async_coroutine_t; -struct _async_coroutine_s { +struct _async_coroutine_s +{ /* Basic structure for coroutine. */ zend_coroutine_t coroutine; @@ -38,7 +39,7 @@ struct _async_coroutine_s { zend_execute_data *execute_data; /* deferred cancellation object. */ - zend_object * deferred_cancellation; + zend_object *deferred_cancellation; /* Active fiber vm stack. */ zend_vm_stack vm_stack; @@ -53,11 +54,14 @@ struct _async_coroutine_s { typedef struct _finally_handlers_context_s finally_handlers_context_t; // Structure for finally handlers context -struct _finally_handlers_context_s { - union { +struct _finally_handlers_context_s +{ + union + { void *target; async_coroutine_t *coroutine; }; + zend_async_scope_t *scope; HashTable *finally_handlers; zend_object *composite_exception; @@ -69,15 +73,18 @@ struct _finally_handlers_context_s { void async_register_coroutine_ce(void); zend_coroutine_t *async_new_coroutine(zend_async_scope_t *scope); void async_coroutine_cleanup(zend_fiber_context *context); -void async_coroutine_finalize(zend_fiber_transfer *transfer, async_coroutine_t * coroutine); -void async_coroutine_finalize_from_scheduler(async_coroutine_t * coroutine); +void async_coroutine_finalize(zend_fiber_transfer *transfer, async_coroutine_t *coroutine); +void async_coroutine_finalize_from_scheduler(async_coroutine_t *coroutine); void async_coroutine_suspend(const bool from_main); -void async_coroutine_resume(zend_coroutine_t *coroutine, zend_object * error, const bool transfer_error); -void async_coroutine_cancel(zend_coroutine_t *zend_coroutine, zend_object *error, bool transfer_error, const bool is_safely); -bool async_coroutine_context_set(zend_coroutine_t * z_coroutine, zval *key, zval *value); -bool async_coroutine_context_get(zend_coroutine_t * z_coroutine, zval *key, zval *result); -bool async_coroutine_context_has(zend_coroutine_t * z_coroutine, zval *key); -bool async_coroutine_context_delete(zend_coroutine_t * z_coroutine, zval *key); +void async_coroutine_resume(zend_coroutine_t *coroutine, zend_object *error, const bool transfer_error); +void async_coroutine_cancel(zend_coroutine_t *zend_coroutine, + zend_object *error, + bool transfer_error, + const bool is_safely); +bool async_coroutine_context_set(zend_coroutine_t *z_coroutine, zval *key, zval *value); +bool async_coroutine_context_get(zend_coroutine_t *z_coroutine, zval *key, zval *result); +bool async_coroutine_context_has(zend_coroutine_t *z_coroutine, zval *key); +bool async_coroutine_context_delete(zend_coroutine_t *z_coroutine, zval *key); bool async_call_finally_handlers(HashTable *finally_handlers, finally_handlers_context_t *context, int32_t priority); -#endif //COROUTINE_H +#endif // COROUTINE_H diff --git a/coroutine_arginfo.h b/coroutine_arginfo.h index 2eecd06..9c477c3 100644 --- a/coroutine_arginfo.h +++ b/coroutine_arginfo.h @@ -45,11 +45,11 @@ ZEND_END_ARG_INFO() #define arginfo_class_Async_Coroutine_getAwaitingInfo arginfo_class_Async_Coroutine_getTrace ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Coroutine_cancel, 0, 0, IS_VOID, 0) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellationException, CancellationException, 1, "null") +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellationException, CancellationException, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Coroutine_onFinally, 0, 1, IS_VOID, 0) - ZEND_ARG_OBJ_INFO(0, callback, Closure, 0) +ZEND_ARG_OBJ_INFO(0, callback, Closure, 0) ZEND_END_ARG_INFO() ZEND_METHOD(Async_Coroutine, getId); @@ -74,27 +74,71 @@ ZEND_METHOD(Async_Coroutine, cancel); ZEND_METHOD(Async_Coroutine, onFinally); static const zend_function_entry class_Async_Coroutine_methods[] = { - ZEND_ME(Async_Coroutine, getId, arginfo_class_Async_Coroutine_getId, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, asHiPriority, arginfo_class_Async_Coroutine_asHiPriority, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, getContext, arginfo_class_Async_Coroutine_getContext, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, getResult, arginfo_class_Async_Coroutine_getResult, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, getException, arginfo_class_Async_Coroutine_getException, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, getTrace, arginfo_class_Async_Coroutine_getTrace, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, getSpawnFileAndLine, arginfo_class_Async_Coroutine_getSpawnFileAndLine, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, getSpawnLocation, arginfo_class_Async_Coroutine_getSpawnLocation, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, getSuspendFileAndLine, arginfo_class_Async_Coroutine_getSuspendFileAndLine, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, getSuspendLocation, arginfo_class_Async_Coroutine_getSuspendLocation, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, isStarted, arginfo_class_Async_Coroutine_isStarted, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, isQueued, arginfo_class_Async_Coroutine_isQueued, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, isRunning, arginfo_class_Async_Coroutine_isRunning, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, isSuspended, arginfo_class_Async_Coroutine_isSuspended, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, isCancelled, arginfo_class_Async_Coroutine_isCancelled, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, isCancellationRequested, arginfo_class_Async_Coroutine_isCancellationRequested, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, isFinished, arginfo_class_Async_Coroutine_isFinished, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, getAwaitingInfo, arginfo_class_Async_Coroutine_getAwaitingInfo, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, cancel, arginfo_class_Async_Coroutine_cancel, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Coroutine, onFinally, arginfo_class_Async_Coroutine_onFinally, ZEND_ACC_PUBLIC) - ZEND_FE_END + ZEND_ME(Async_Coroutine, getId, arginfo_class_Async_Coroutine_getId, ZEND_ACC_PUBLIC) ZEND_ME( + Async_Coroutine, + asHiPriority, + arginfo_class_Async_Coroutine_asHiPriority, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Coroutine, + getContext, + arginfo_class_Async_Coroutine_getContext, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Coroutine, + getResult, + arginfo_class_Async_Coroutine_getResult, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Coroutine, getException, arginfo_class_Async_Coroutine_getException, ZEND_ACC_PUBLIC) ZEND_ME( + Async_Coroutine, + getTrace, + arginfo_class_Async_Coroutine_getTrace, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Coroutine, + getSpawnFileAndLine, + arginfo_class_Async_Coroutine_getSpawnFileAndLine, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Coroutine, + getSpawnLocation, + arginfo_class_Async_Coroutine_getSpawnLocation, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Coroutine, + getSuspendFileAndLine, + arginfo_class_Async_Coroutine_getSuspendFileAndLine, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Coroutine, + getSuspendLocation, + arginfo_class_Async_Coroutine_getSuspendLocation, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Coroutine, + isStarted, + arginfo_class_Async_Coroutine_isStarted, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Coroutine, + isQueued, + arginfo_class_Async_Coroutine_isQueued, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Coroutine, + isRunning, + arginfo_class_Async_Coroutine_isRunning, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Coroutine, + isSuspended, + arginfo_class_Async_Coroutine_isSuspended, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Coroutine, + isCancelled, + arginfo_class_Async_Coroutine_isCancelled, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Coroutine, + isCancellationRequested, + arginfo_class_Async_Coroutine_isCancellationRequested, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Coroutine, + isFinished, + arginfo_class_Async_Coroutine_isFinished, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Coroutine, + getAwaitingInfo, + arginfo_class_Async_Coroutine_getAwaitingInfo, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Coroutine, + cancel, + arginfo_class_Async_Coroutine_cancel, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Coroutine, + onFinally, + arginfo_class_Async_Coroutine_onFinally, + ZEND_ACC_PUBLIC) ZEND_FE_END }; static zend_class_entry *register_class_Async_Coroutine(zend_class_entry *class_entry_Async_Awaitable) @@ -102,7 +146,8 @@ static zend_class_entry *register_class_Async_Coroutine(zend_class_entry *class_ zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "Async", "Coroutine", class_Async_Coroutine_methods); - class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + class_entry = zend_register_internal_class_with_flags( + &ce, NULL, ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES | ZEND_ACC_NOT_SERIALIZABLE); zend_class_implements(class_entry, 1, class_entry_Async_Awaitable); return class_entry; diff --git a/exceptions.c b/exceptions.c index cfa9a0e..164cf62 100644 --- a/exceptions.c +++ b/exceptions.c @@ -22,20 +22,20 @@ #include "exceptions_arginfo.h" #include "zend_common.h" -zend_class_entry * async_ce_async_exception = NULL; -zend_class_entry * async_ce_cancellation_exception = NULL; -zend_class_entry * async_ce_input_output_exception = NULL; -zend_class_entry * async_ce_timeout_exception = NULL; -zend_class_entry * async_ce_poll_exception = NULL; -zend_class_entry * async_ce_dns_exception = NULL; -zend_class_entry * async_ce_composite_exception = NULL; +zend_class_entry *async_ce_async_exception = NULL; +zend_class_entry *async_ce_cancellation_exception = NULL; +zend_class_entry *async_ce_input_output_exception = NULL; +zend_class_entry *async_ce_timeout_exception = NULL; +zend_class_entry *async_ce_poll_exception = NULL; +zend_class_entry *async_ce_dns_exception = NULL; +zend_class_entry *async_ce_composite_exception = NULL; PHP_METHOD(Async_CompositeException, addException) { zval *exception; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJECT_OF_CLASS(exception, zend_ce_throwable) + Z_PARAM_OBJECT_OF_CLASS(exception, zend_ce_throwable) ZEND_PARSE_PARAMETERS_END(); zval *object = ZEND_THIS; @@ -48,8 +48,7 @@ PHP_METHOD(Async_CompositeException, getExceptions) zval *object = ZEND_THIS; zval *exceptions_prop = zend_read_property( - async_ce_composite_exception, Z_OBJ_P(object), "exceptions", sizeof("exceptions")-1, 0, NULL - ); + async_ce_composite_exception, Z_OBJ_P(object), "exceptions", sizeof("exceptions") - 1, 0, NULL); if (Z_TYPE_P(exceptions_prop) == IS_ARRAY) { RETURN_ZVAL(exceptions_prop, 1, 0); @@ -69,7 +68,7 @@ void async_register_exceptions_ce(void) async_ce_composite_exception = register_class_Async_CompositeException(zend_ce_exception); } -zend_object * async_new_exception(zend_class_entry *exception_ce, const char *format, ...) +zend_object *async_new_exception(zend_class_entry *exception_ce, const char *format, ...) { zval exception, message_val; @@ -77,8 +76,7 @@ zend_object * async_new_exception(zend_class_entry *exception_ce, const char *fo exception_ce = zend_ce_exception; } - ZEND_ASSERT(instanceof_function(exception_ce, zend_ce_throwable) - && "Exceptions must implement Throwable"); + ZEND_ASSERT(instanceof_function(exception_ce, zend_ce_throwable) && "Exceptions must implement Throwable"); object_init_ex(&exception, exception_ce); @@ -97,7 +95,7 @@ zend_object * async_new_exception(zend_class_entry *exception_ce, const char *fo return Z_OBJ(exception); } -ZEND_API ZEND_COLD zend_object * async_throw_error(const char *format, ...) +ZEND_API ZEND_COLD zend_object *async_throw_error(const char *format, ...) { va_list args; va_start(args, format); @@ -107,7 +105,7 @@ ZEND_API ZEND_COLD zend_object * async_throw_error(const char *format, ...) zend_object *obj = NULL; if (EXPECTED(EG(current_execute_data))) { - obj = zend_throw_exception(async_ce_async_exception, ZSTR_VAL(message), 0); + obj = zend_throw_exception(async_ce_async_exception, ZSTR_VAL(message), 0); } else { obj = async_new_exception(async_ce_async_exception, ZSTR_VAL(message)); async_apply_exception_to_context(obj); @@ -117,13 +115,12 @@ ZEND_API ZEND_COLD zend_object * async_throw_error(const char *format, ...) return obj; } -ZEND_API ZEND_COLD zend_object * async_throw_cancellation(const char *format, ...) +ZEND_API ZEND_COLD zend_object *async_throw_cancellation(const char *format, ...) { const zend_object *previous_exception = EG(exception); - if (format == NULL - && previous_exception != NULL - && instanceof_function(previous_exception->ce, async_ce_cancellation_exception)) { + if (format == NULL && previous_exception != NULL && + instanceof_function(previous_exception->ce, async_ce_cancellation_exception)) { format = "The operation was canceled by timeout"; } else { format = format ? format : "The operation was canceled"; @@ -145,7 +142,7 @@ ZEND_API ZEND_COLD zend_object * async_throw_cancellation(const char *format, .. return obj; } -ZEND_API ZEND_COLD zend_object * async_throw_input_output(const char *format, ...) +ZEND_API ZEND_COLD zend_object *async_throw_input_output(const char *format, ...) { format = format ? format : "An input/output error occurred."; @@ -165,7 +162,7 @@ ZEND_API ZEND_COLD zend_object * async_throw_input_output(const char *format, .. return obj; } -ZEND_API ZEND_COLD zend_object * async_throw_timeout(const char *format, const zend_long timeout) +ZEND_API ZEND_COLD zend_object *async_throw_timeout(const char *format, const zend_long timeout) { format = format ? format : "A timeout of %u microseconds occurred"; @@ -178,7 +175,7 @@ ZEND_API ZEND_COLD zend_object * async_throw_timeout(const char *format, const z } } -ZEND_API ZEND_COLD zend_object * async_throw_poll(const char *format, ...) +ZEND_API ZEND_COLD zend_object *async_throw_poll(const char *format, ...) { va_list args; va_start(args, format); @@ -196,14 +193,15 @@ ZEND_API ZEND_COLD zend_object * async_throw_poll(const char *format, ...) return obj; } -ZEND_API ZEND_COLD zend_object * async_new_composite_exception(void) +ZEND_API ZEND_COLD zend_object *async_new_composite_exception(void) { zval composite; object_init_ex(&composite, async_ce_composite_exception); return Z_OBJ(composite); } -ZEND_API ZEND_COLD void async_composite_exception_add_exception(zend_object *composite, zend_object *exception, bool transfer) +ZEND_API ZEND_COLD void +async_composite_exception_add_exception(zend_object *composite, zend_object *exception, bool transfer) { if (composite == NULL || exception == NULL) { return; @@ -286,7 +284,7 @@ bool async_spawn_and_throw(zend_object *exception, zend_async_scope_t *scope, in * * @return The extracted exception object with an increased reference count. */ -zend_object * async_extract_exception(void) +zend_object *async_extract_exception(void) { zend_exception_save(); zend_exception_restore(); @@ -308,11 +306,10 @@ zend_object * async_extract_exception(void) */ void async_apply_exception(zend_object **to_exception) { - if (UNEXPECTED(EG(exception) - && false == ( - instanceof_function(EG(exception)->ce, zend_ce_cancellation_exception) - || zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception)) - ))) { + if (UNEXPECTED(EG(exception) && + false == + (instanceof_function(EG(exception)->ce, zend_ce_cancellation_exception) || + zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception))))) { zend_object *exception = async_extract_exception(); diff --git a/exceptions.h b/exceptions.h index a1222f7..33395f5 100644 --- a/exceptions.h +++ b/exceptions.h @@ -22,29 +22,29 @@ BEGIN_EXTERN_C() -extern zend_class_entry * async_ce_async_exception; -extern zend_class_entry * async_ce_cancellation_exception; -extern zend_class_entry * async_ce_input_output_exception; -extern zend_class_entry * async_ce_timeout_exception; -extern zend_class_entry * async_ce_poll_exception; -extern zend_class_entry * async_ce_dns_exception; -extern zend_class_entry * async_ce_composite_exception; +extern zend_class_entry *async_ce_async_exception; +extern zend_class_entry *async_ce_cancellation_exception; +extern zend_class_entry *async_ce_input_output_exception; +extern zend_class_entry *async_ce_timeout_exception; +extern zend_class_entry *async_ce_poll_exception; +extern zend_class_entry *async_ce_dns_exception; +extern zend_class_entry *async_ce_composite_exception; void async_register_exceptions_ce(void); -ZEND_API ZEND_COLD zend_object * async_new_exception(zend_class_entry *exception_ce, const char *format, ...); -ZEND_API ZEND_COLD zend_object * async_throw_error(const char *format, ...); -ZEND_API ZEND_COLD zend_object * async_throw_cancellation(const char *format, ...); -ZEND_API ZEND_COLD zend_object * async_throw_input_output(const char *format, ...); -ZEND_API ZEND_COLD zend_object * async_throw_timeout(const char *format, const zend_long timeout); -ZEND_API ZEND_COLD zend_object * async_throw_poll(const char *format, ...); -ZEND_API ZEND_COLD zend_object * async_new_composite_exception(void); +ZEND_API ZEND_COLD zend_object *async_new_exception(zend_class_entry *exception_ce, const char *format, ...); +ZEND_API ZEND_COLD zend_object *async_throw_error(const char *format, ...); +ZEND_API ZEND_COLD zend_object *async_throw_cancellation(const char *format, ...); +ZEND_API ZEND_COLD zend_object *async_throw_input_output(const char *format, ...); +ZEND_API ZEND_COLD zend_object *async_throw_timeout(const char *format, const zend_long timeout); +ZEND_API ZEND_COLD zend_object *async_throw_poll(const char *format, ...); +ZEND_API ZEND_COLD zend_object *async_new_composite_exception(void); ZEND_API void async_composite_exception_add_exception(zend_object *composite, zend_object *exception, bool transfer); bool async_spawn_and_throw(zend_object *exception, zend_async_scope_t *scope, int32_t priority); void async_apply_exception_to_context(zend_object *exception); -zend_object * async_extract_exception(void); +zend_object *async_extract_exception(void); void async_rethrow_exception(zend_object *exception); void async_apply_exception(zend_object **to_exception); END_EXTERN_C() -#endif //ASYNC_EXCEPTIONS_H +#endif // ASYNC_EXCEPTIONS_H diff --git a/exceptions_arginfo.h b/exceptions_arginfo.h index 1e2331a..e71a590 100644 --- a/exceptions_arginfo.h +++ b/exceptions_arginfo.h @@ -2,7 +2,7 @@ * Stub hash: 9bd64d6113fa23a91c46300cf51db636fea98124 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_CompositeException_addException, 0, 1, IS_VOID, 0) - ZEND_ARG_OBJ_INFO(0, exception, Throwable, 0) +ZEND_ARG_OBJ_INFO(0, exception, Throwable, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_CompositeException_getExceptions, 0, 0, IS_ARRAY, 0) @@ -11,11 +11,14 @@ ZEND_END_ARG_INFO() ZEND_METHOD(Async_CompositeException, addException); ZEND_METHOD(Async_CompositeException, getExceptions); -static const zend_function_entry class_Async_CompositeException_methods[] = { - ZEND_ME(Async_CompositeException, addException, arginfo_class_Async_CompositeException_addException, ZEND_ACC_PUBLIC) - ZEND_ME(Async_CompositeException, getExceptions, arginfo_class_Async_CompositeException_getExceptions, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; +static const zend_function_entry class_Async_CompositeException_methods[] = { ZEND_ME( + Async_CompositeException, + addException, + arginfo_class_Async_CompositeException_addException, + ZEND_ACC_PUBLIC) ZEND_ME(Async_CompositeException, + getExceptions, + arginfo_class_Async_CompositeException_getExceptions, + ZEND_ACC_PUBLIC) ZEND_FE_END }; static zend_class_entry *register_class_Async_CancellationException(zend_class_entry *class_entry_CancellationException) { @@ -82,12 +85,18 @@ static zend_class_entry *register_class_Async_CompositeException(zend_class_entr zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "Async", "CompositeException", class_Async_CompositeException_methods); - class_entry = zend_register_internal_class_with_flags(&ce, class_entry_Exception, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES); + class_entry = zend_register_internal_class_with_flags( + &ce, class_entry_Exception, ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES); zval property_exceptions_default_value; ZVAL_UNDEF(&property_exceptions_default_value); zend_string *property_exceptions_name = zend_string_init("exceptions", sizeof("exceptions") - 1, 1); - zend_declare_typed_property(class_entry, property_exceptions_name, &property_exceptions_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_declare_typed_property(class_entry, + property_exceptions_name, + &property_exceptions_default_value, + ZEND_ACC_PRIVATE, + NULL, + (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); zend_string_release(property_exceptions_name); return class_entry; diff --git a/internal/allocator.c b/internal/allocator.c index d75fbb6..a02429a 100644 --- a/internal/allocator.c +++ b/internal/allocator.c @@ -53,12 +53,7 @@ void zend_std_free(void *ptr) #endif } -allocator_t zend_std_allocator = { - zend_std_alloc, - zend_std_calloc, - zend_std_realloc, - zend_std_free -}; +allocator_t zend_std_allocator = { zend_std_alloc, zend_std_calloc, zend_std_realloc, zend_std_free }; void *zend_std_palloc(const size_t size) { @@ -96,9 +91,4 @@ void zend_std_pfree(void *ptr) #endif } -allocator_t zend_std_persistent_allocator = { - zend_std_palloc, - zend_std_pcalloc, - zend_std_prealloc, - zend_std_pfree -}; \ No newline at end of file +allocator_t zend_std_persistent_allocator = { zend_std_palloc, zend_std_pcalloc, zend_std_prealloc, zend_std_pfree }; \ No newline at end of file diff --git a/internal/allocator.h b/internal/allocator.h index 6f94950..4134cbb 100644 --- a/internal/allocator.h +++ b/internal/allocator.h @@ -20,7 +20,8 @@ typedef struct _allocator_s allocator_t; -struct _allocator_s { +struct _allocator_s +{ void *(*m_alloc)(size_t size); void *(*m_calloc)(size_t num, size_t size); void *(*m_realloc)(void *ptr, size_t size, const size_t old_size); @@ -30,4 +31,4 @@ struct _allocator_s { extern allocator_t zend_std_allocator; extern allocator_t zend_std_persistent_allocator; -#endif //ASYNC_ALLOCATOR_H +#endif // ASYNC_ALLOCATOR_H diff --git a/internal/circular_buffer.c b/internal/circular_buffer.c index 1056130..93d29de 100644 --- a/internal/circular_buffer.c +++ b/internal/circular_buffer.c @@ -25,15 +25,17 @@ */ static zend_always_inline size_t round_up_to_power_of_2(size_t n) { - if (n == 0) return 1; - if ((n & (n - 1)) == 0) return n; // Already power of 2 - - // Find the highest bit position - size_t power = 1; - while (power < n) { - power <<= 1; - } - return power; + if (n == 0) + return 1; + if ((n & (n - 1)) == 0) + return n; // Already power of 2 + + // Find the highest bit position + size_t power = 1; + while (power < n) { + power <<= 1; + } + return power; } #ifdef ASYNC_UNIT_TESTS @@ -51,35 +53,35 @@ static zend_always_inline size_t round_up_to_power_of_2(size_t n) */ circular_buffer_t *circular_buffer_new(size_t count, const size_t item_size, const allocator_t *allocator) { - if(item_size <= 0) { - ASYNC_ERROR(E_ERROR, "Item size must be greater than zero"); - return NULL; - } + if (item_size <= 0) { + ASYNC_ERROR(E_ERROR, "Item size must be greater than zero"); + return NULL; + } - if(allocator == NULL) { - allocator = &zend_std_allocator; - } + if (allocator == NULL) { + allocator = &zend_std_allocator; + } - if(count <= 0) { - count = MINIMUM_COUNT; - } + if (count <= 0) { + count = MINIMUM_COUNT; + } - // Ensure count is always a power of 2 for optimal performance - count = round_up_to_power_of_2(count); + // Ensure count is always a power of 2 for optimal performance + count = round_up_to_power_of_2(count); - circular_buffer_t* buffer = (allocator->m_calloc)(1, sizeof(circular_buffer_t)); + circular_buffer_t *buffer = (allocator->m_calloc)(1, sizeof(circular_buffer_t)); - if (UNEXPECTED(buffer == NULL)) { - ASYNC_ERROR(E_ERROR, "Failed to allocate memory for circular buffer"); - return NULL; - } + if (UNEXPECTED(buffer == NULL)) { + ASYNC_ERROR(E_ERROR, "Failed to allocate memory for circular buffer"); + return NULL; + } - if (UNEXPECTED(circular_buffer_ctor(buffer, count, item_size, allocator) == FAILURE)) { - (allocator->m_free)(buffer); - return NULL; - } + if (UNEXPECTED(circular_buffer_ctor(buffer, count, item_size, allocator) == FAILURE)) { + (allocator->m_free)(buffer); + return NULL; + } - return buffer; + return buffer; } /** @@ -87,49 +89,50 @@ circular_buffer_t *circular_buffer_new(size_t count, const size_t item_size, con */ void circular_buffer_destroy(circular_buffer_t *buffer) { - (buffer->allocator->m_free)(buffer->data); - (buffer->allocator->m_free)(buffer); + (buffer->allocator->m_free)(buffer->data); + (buffer->allocator->m_free)(buffer); } -zend_result circular_buffer_ctor(circular_buffer_t *buffer, size_t count, const size_t item_size, const allocator_t *allocator) +zend_result +circular_buffer_ctor(circular_buffer_t *buffer, size_t count, const size_t item_size, const allocator_t *allocator) { - if(allocator == NULL) { - allocator = &zend_std_allocator; - } - - if(count <= 0) { - count = MINIMUM_COUNT; - } - - // Ensure count is always a power of 2 for optimal performance - count = round_up_to_power_of_2(count); - - void *data = (allocator->m_calloc)(count, item_size); - - if (UNEXPECTED(data == NULL)) { - ASYNC_ERROR(E_ERROR, "Failed to allocate memory for circular buffer"); - return FAILURE; - } - - buffer->allocator = allocator; - buffer->item_size = item_size; - buffer->min_size = count; - buffer->capacity = count; - buffer->auto_optimize = true; // Default to enabled for backward compatibility - buffer->decrease_t = count > MINIMUM_COUNT ? (count / 2 - count / 4) : 0; - buffer->data = data; - buffer->head = 0; - buffer->tail = 0; - - return SUCCESS; + if (allocator == NULL) { + allocator = &zend_std_allocator; + } + + if (count <= 0) { + count = MINIMUM_COUNT; + } + + // Ensure count is always a power of 2 for optimal performance + count = round_up_to_power_of_2(count); + + void *data = (allocator->m_calloc)(count, item_size); + + if (UNEXPECTED(data == NULL)) { + ASYNC_ERROR(E_ERROR, "Failed to allocate memory for circular buffer"); + return FAILURE; + } + + buffer->allocator = allocator; + buffer->item_size = item_size; + buffer->min_size = count; + buffer->capacity = count; + buffer->auto_optimize = true; // Default to enabled for backward compatibility + buffer->decrease_t = count > MINIMUM_COUNT ? (count / 2 - count / 4) : 0; + buffer->data = data; + buffer->head = 0; + buffer->tail = 0; + + return SUCCESS; } void circular_buffer_dtor(circular_buffer_t *buffer) { - if (buffer->data != NULL) { - (buffer->allocator->m_free)(buffer->data); - buffer->data = NULL; - } + if (buffer->data != NULL) { + (buffer->allocator->m_free)(buffer->data); + buffer->data = NULL; + } } /** @@ -138,9 +141,9 @@ void circular_buffer_dtor(circular_buffer_t *buffer) */ static zend_always_inline size_t next_index(size_t index, size_t capacity) { - ZEND_ASSERT((capacity & (capacity - 1)) == 0 && "Capacity must be power of 2"); - // Since capacity is always power of 2, we can use fast bitwise AND - return (index + 1) & (capacity - 1); + ZEND_ASSERT((capacity & (capacity - 1)) == 0 && "Capacity must be power of 2"); + // Since capacity is always power of 2, we can use fast bitwise AND + return (index + 1) & (capacity - 1); } /** @@ -148,9 +151,8 @@ static zend_always_inline size_t next_index(size_t index, size_t capacity) */ static zend_always_inline bool should_decrease(const circular_buffer_t *buffer) { - return buffer->auto_optimize && - !circular_buffer_is_empty(buffer) && - circular_buffer_count(buffer) < buffer->decrease_t; + return buffer->auto_optimize && !circular_buffer_is_empty(buffer) && + circular_buffer_count(buffer) < buffer->decrease_t; } /** @@ -158,7 +160,7 @@ static zend_always_inline bool should_decrease(const circular_buffer_t *buffer) */ static void recalc_decrease_threshold(circular_buffer_t *buffer, size_t new_count) { - buffer->decrease_t = (new_count <= buffer->min_size) ? 0 : (new_count / 2 - new_count / 4); + buffer->decrease_t = (new_count <= buffer->min_size) ? 0 : (new_count / 2 - new_count / 4); } /** @@ -166,166 +168,165 @@ static void recalc_decrease_threshold(circular_buffer_t *buffer, size_t new_coun */ zend_result circular_buffer_realloc(circular_buffer_t *buffer, size_t new_count) { - ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); - ZEND_ASSERT(buffer->data != NULL && "Buffer data cannot be NULL"); - ZEND_ASSERT(buffer->capacity > 0 && "Buffer capacity must be positive"); - ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); - ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); - ZEND_ASSERT(buffer->item_size > 0 && "Item size must be positive"); - - if(new_count <= 0) { - if(circular_buffer_is_full(buffer)) { - // Buffer is full, need to increase size (double it, stays power of 2) - new_count = buffer->capacity * 2; - } else if(should_decrease(buffer)) { - // Buffer is underused, can decrease size (halve it, stays power of 2) - new_count = buffer->capacity / 2; - if(new_count < buffer->min_size) { - new_count = buffer->min_size; - } - } else { - return SUCCESS; // No need to reallocate - } - } else { - // Ensure manually specified count is also power of 2 - new_count = round_up_to_power_of_2(new_count); - } - - ZEND_ASSERT(new_count > 0 && "New count must be positive"); - ZEND_ASSERT(new_count >= buffer->min_size && "New count cannot be less than minimum size"); - ZEND_ASSERT((new_count & (new_count - 1)) == 0 && "New count must be power of 2"); - - /* - * Case 1: Empty buffer - simple replacement - * - * Before: [ | | | ] head=tail=0 - * After: [ | | | | | ] head=tail=0 - */ - if(circular_buffer_is_empty(buffer)) { - void *new_data = (buffer->allocator->m_alloc)(new_count * buffer->item_size); - if (UNEXPECTED(new_data == NULL)) { - ASYNC_ERROR(E_WARNING, "Failed to reallocate circular buffer"); - return FAILURE; - } - - (buffer->allocator->m_free)(buffer->data); - buffer->data = new_data; - buffer->capacity = new_count; - buffer->head = 0; - buffer->tail = 0; - recalc_decrease_threshold(buffer, new_count); - return SUCCESS; - } - - size_t count = circular_buffer_count(buffer); - - /* - * Case 2: Linear order (head >= tail) - data is contiguous - * - * Example: - * Before: [ | A| B| C| | ] tail=1, head=4, count=3 - * ^ ^ - * tail head - */ - if (buffer->head >= buffer->tail) { - - if (EXPECTED(new_count > buffer->capacity)) { - /* - * Increasing size - can use realloc safely - * Data layout won't change, just more space at the end - * - * After: [ | A| B| C| | | | | ] tail=1, head=4 - * ^ ^ - * tail head - */ - void *new_data = (buffer->allocator->m_realloc)(buffer->data, - new_count * buffer->item_size, buffer->capacity * buffer->item_size); - - if (UNEXPECTED(new_data == NULL)) { - ASYNC_ERROR(E_WARNING, "Failed to reallocate circular buffer"); - return FAILURE; - } - - buffer->data = new_data; - buffer->capacity = new_count; - // head and tail offsets remain the same - - } else { - /* - * Decreasing size - use memcpy to copy only needed data - * - * Copy [tail...head) to beginning of new buffer - * After: [ A| B| C| ] tail=0, head=3 - * ^ ^ - * tail head - */ - void *new_data = (buffer->allocator->m_alloc)(new_count * buffer->item_size); - if (UNEXPECTED(new_data == NULL)) { - ASYNC_ERROR(E_WARNING, "Failed to reallocate circular buffer"); - return FAILURE; - } - - // Single memcpy for contiguous data - memcpy(new_data, (char *)buffer->data + buffer->tail * buffer->item_size, - count * buffer->item_size); - - (buffer->allocator->m_free)(buffer->data); - buffer->data = new_data; - buffer->capacity = new_count; - buffer->tail = 0; - buffer->head = count; - } - - } else { - /* - * Case 3: Wrapped order (head < tail) - data wraps around - * - * Example: - * Before: [ C| D| | | A| B] tail=4, head=2, count=4 - * ^ ^ - * head tail - * - * Need to copy in two parts: - * Part 1: [A, B] from positions [tail...end] - * Part 2: [C, D] from positions [start...head) - * - * After: [ A| B| C| D| | ] tail=0, head=4 - * ^ ^ - * tail head - */ - void *new_data = (buffer->allocator->m_alloc)(new_count * buffer->item_size); - if (UNEXPECTED(new_data == NULL)) { - ASYNC_ERROR(E_WARNING, "Failed to reallocate circular buffer"); - return FAILURE; - } - - // First part: copy [tail...end] to beginning of new buffer - size_t first_part_count = buffer->capacity - buffer->tail; - memcpy(new_data, - (char *)buffer->data + buffer->tail * buffer->item_size, - first_part_count * buffer->item_size); - - // Second part: copy [start...head) after first part - memcpy((char *)new_data + first_part_count * buffer->item_size, - buffer->data, - buffer->head * buffer->item_size); - - (buffer->allocator->m_free)(buffer->data); - buffer->data = new_data; - buffer->capacity = new_count; - buffer->tail = 0; - buffer->head = count; - } - - // Final consistency checks - ZEND_ASSERT(buffer->data != NULL && "Buffer data should not be NULL after realloc"); - ZEND_ASSERT(buffer->capacity == new_count && "Capacity should match new_count"); - ZEND_ASSERT(buffer->head < buffer->capacity && "Head should be within new capacity"); - ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail should be within new capacity"); - ZEND_ASSERT(circular_buffer_count(buffer) == count && "Element count should be preserved"); - - recalc_decrease_threshold(buffer, new_count); - return SUCCESS; + ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); + ZEND_ASSERT(buffer->data != NULL && "Buffer data cannot be NULL"); + ZEND_ASSERT(buffer->capacity > 0 && "Buffer capacity must be positive"); + ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); + ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); + ZEND_ASSERT(buffer->item_size > 0 && "Item size must be positive"); + + if (new_count <= 0) { + if (circular_buffer_is_full(buffer)) { + // Buffer is full, need to increase size (double it, stays power of 2) + new_count = buffer->capacity * 2; + } else if (should_decrease(buffer)) { + // Buffer is underused, can decrease size (halve it, stays power of 2) + new_count = buffer->capacity / 2; + if (new_count < buffer->min_size) { + new_count = buffer->min_size; + } + } else { + return SUCCESS; // No need to reallocate + } + } else { + // Ensure manually specified count is also power of 2 + new_count = round_up_to_power_of_2(new_count); + } + + ZEND_ASSERT(new_count > 0 && "New count must be positive"); + ZEND_ASSERT(new_count >= buffer->min_size && "New count cannot be less than minimum size"); + ZEND_ASSERT((new_count & (new_count - 1)) == 0 && "New count must be power of 2"); + + /* + * Case 1: Empty buffer - simple replacement + * + * Before: [ | | | ] head=tail=0 + * After: [ | | | | | ] head=tail=0 + */ + if (circular_buffer_is_empty(buffer)) { + void *new_data = (buffer->allocator->m_alloc)(new_count * buffer->item_size); + if (UNEXPECTED(new_data == NULL)) { + ASYNC_ERROR(E_WARNING, "Failed to reallocate circular buffer"); + return FAILURE; + } + + (buffer->allocator->m_free)(buffer->data); + buffer->data = new_data; + buffer->capacity = new_count; + buffer->head = 0; + buffer->tail = 0; + recalc_decrease_threshold(buffer, new_count); + return SUCCESS; + } + + size_t count = circular_buffer_count(buffer); + + /* + * Case 2: Linear order (head >= tail) - data is contiguous + * + * Example: + * Before: [ | A| B| C| | ] tail=1, head=4, count=3 + * ^ ^ + * tail head + */ + if (buffer->head >= buffer->tail) { + + if (EXPECTED(new_count > buffer->capacity)) { + /* + * Increasing size - can use realloc safely + * Data layout won't change, just more space at the end + * + * After: [ | A| B| C| | | | | ] tail=1, head=4 + * ^ ^ + * tail head + */ + void *new_data = (buffer->allocator->m_realloc)( + buffer->data, new_count * buffer->item_size, buffer->capacity * buffer->item_size); + + if (UNEXPECTED(new_data == NULL)) { + ASYNC_ERROR(E_WARNING, "Failed to reallocate circular buffer"); + return FAILURE; + } + + buffer->data = new_data; + buffer->capacity = new_count; + // head and tail offsets remain the same + + } else { + /* + * Decreasing size - use memcpy to copy only needed data + * + * Copy [tail...head) to beginning of new buffer + * After: [ A| B| C| ] tail=0, head=3 + * ^ ^ + * tail head + */ + void *new_data = (buffer->allocator->m_alloc)(new_count * buffer->item_size); + if (UNEXPECTED(new_data == NULL)) { + ASYNC_ERROR(E_WARNING, "Failed to reallocate circular buffer"); + return FAILURE; + } + + // Single memcpy for contiguous data + memcpy(new_data, (char *) buffer->data + buffer->tail * buffer->item_size, count * buffer->item_size); + + (buffer->allocator->m_free)(buffer->data); + buffer->data = new_data; + buffer->capacity = new_count; + buffer->tail = 0; + buffer->head = count; + } + + } else { + /* + * Case 3: Wrapped order (head < tail) - data wraps around + * + * Example: + * Before: [ C| D| | | A| B] tail=4, head=2, count=4 + * ^ ^ + * head tail + * + * Need to copy in two parts: + * Part 1: [A, B] from positions [tail...end] + * Part 2: [C, D] from positions [start...head) + * + * After: [ A| B| C| D| | ] tail=0, head=4 + * ^ ^ + * tail head + */ + void *new_data = (buffer->allocator->m_alloc)(new_count * buffer->item_size); + if (UNEXPECTED(new_data == NULL)) { + ASYNC_ERROR(E_WARNING, "Failed to reallocate circular buffer"); + return FAILURE; + } + + // First part: copy [tail...end] to beginning of new buffer + size_t first_part_count = buffer->capacity - buffer->tail; + memcpy(new_data, + (char *) buffer->data + buffer->tail * buffer->item_size, + first_part_count * buffer->item_size); + + // Second part: copy [start...head) after first part + memcpy((char *) new_data + first_part_count * buffer->item_size, + buffer->data, + buffer->head * buffer->item_size); + + (buffer->allocator->m_free)(buffer->data); + buffer->data = new_data; + buffer->capacity = new_count; + buffer->tail = 0; + buffer->head = count; + } + + // Final consistency checks + ZEND_ASSERT(buffer->data != NULL && "Buffer data should not be NULL after realloc"); + ZEND_ASSERT(buffer->capacity == new_count && "Capacity should match new_count"); + ZEND_ASSERT(buffer->head < buffer->capacity && "Head should be within new capacity"); + ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail should be within new capacity"); + ZEND_ASSERT(circular_buffer_count(buffer) == count && "Element count should be preserved"); + + recalc_decrease_threshold(buffer, new_count); + return SUCCESS; } /** @@ -333,52 +334,52 @@ zend_result circular_buffer_realloc(circular_buffer_t *buffer, size_t new_count) */ zend_result circular_buffer_push(circular_buffer_t *buffer, const void *value, const bool should_resize) { - ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); - ZEND_ASSERT(buffer->data != NULL && "Buffer data cannot be NULL"); - ZEND_ASSERT(value != NULL && "Value cannot be NULL"); - ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); - ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); - ZEND_ASSERT(buffer->item_size > 0 && "Item size must be positive"); - - // First check if resize is needed - if (should_resize) { - // Check resize conditions once - bool need_increase = circular_buffer_is_full(buffer); - bool need_decrease = !need_increase && should_decrease(buffer); - - if (need_increase || need_decrease) { - if (circular_buffer_realloc(buffer, 0) == FAILURE) { - return FAILURE; - } - } - } else if (circular_buffer_is_full(buffer)) { - // If resize is disabled but buffer is full - error - ASYNC_ERROR(E_WARNING, "Cannot push into full circular buffer"); - return FAILURE; - } - - /* - * Classic circular buffer push operation: - * 1. Store data at head position - * 2. Advance head to next position - * - * Visual example: - * Before: [ A| B| | ] head=2, tail=0 - * ^ - * head - * - * After: [ A| B| C| ] head=3, tail=0 - * ^ - * head - */ - ZEND_ASSERT(!circular_buffer_is_full(buffer) && "Buffer should not be full at this point"); - - memcpy((char *)buffer->data + buffer->head * buffer->item_size, value, buffer->item_size); - buffer->head = next_index(buffer->head, buffer->capacity); - - ZEND_ASSERT(buffer->head < buffer->capacity && "Head index should be valid after increment"); - - return SUCCESS; + ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); + ZEND_ASSERT(buffer->data != NULL && "Buffer data cannot be NULL"); + ZEND_ASSERT(value != NULL && "Value cannot be NULL"); + ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); + ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); + ZEND_ASSERT(buffer->item_size > 0 && "Item size must be positive"); + + // First check if resize is needed + if (should_resize) { + // Check resize conditions once + bool need_increase = circular_buffer_is_full(buffer); + bool need_decrease = !need_increase && should_decrease(buffer); + + if (need_increase || need_decrease) { + if (circular_buffer_realloc(buffer, 0) == FAILURE) { + return FAILURE; + } + } + } else if (circular_buffer_is_full(buffer)) { + // If resize is disabled but buffer is full - error + ASYNC_ERROR(E_WARNING, "Cannot push into full circular buffer"); + return FAILURE; + } + + /* + * Classic circular buffer push operation: + * 1. Store data at head position + * 2. Advance head to next position + * + * Visual example: + * Before: [ A| B| | ] head=2, tail=0 + * ^ + * head + * + * After: [ A| B| C| ] head=3, tail=0 + * ^ + * head + */ + ZEND_ASSERT(!circular_buffer_is_full(buffer) && "Buffer should not be full at this point"); + + memcpy((char *) buffer->data + buffer->head * buffer->item_size, value, buffer->item_size); + buffer->head = next_index(buffer->head, buffer->capacity); + + ZEND_ASSERT(buffer->head < buffer->capacity && "Head index should be valid after increment"); + + return SUCCESS; } /** @@ -388,66 +389,66 @@ zend_result circular_buffer_push(circular_buffer_t *buffer, const void *value, c */ zend_result circular_buffer_push_front(circular_buffer_t *buffer, const void *value, const bool should_resize) { - ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); - ZEND_ASSERT(buffer->data != NULL && "Buffer data cannot be NULL"); - ZEND_ASSERT(value != NULL && "Value cannot be NULL"); - ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); - ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); - ZEND_ASSERT(buffer->item_size > 0 && "Item size must be positive"); - - // First check if resize is needed - if (should_resize) { - // Check resize conditions once - bool need_increase = circular_buffer_is_full(buffer); - bool need_decrease = !need_increase && should_decrease(buffer); - - if (need_increase || need_decrease) { - if (circular_buffer_realloc(buffer, 0) == FAILURE) { - return FAILURE; - } - } - } - - // If buffer is full after potential resize, fall back to normal push - if (circular_buffer_is_full(buffer)) { - if (should_resize) { - // Should not happen if resize worked correctly - ASYNC_ERROR(E_WARNING, "Buffer is still full after resize attempt"); - return FAILURE; - } else { - // Fall back to normal push behavior - return circular_buffer_push(buffer, value, false); - } - } - - /* - * Push front operation: - * 1. Move tail backward (with wraparound) - * 2. Store data at new tail position - * - * Visual example: - * Before: [ A| B| C| ] head=3, tail=0 - * ^ - * tail - * - * After: [X| A| B| C] head=3, tail=3 (wrapped around) - * ^ - * tail - */ - ZEND_ASSERT(!circular_buffer_is_full(buffer) && "Buffer should not be full at this point"); - - // Move tail backward (with wraparound) - if (buffer->tail == 0) { - buffer->tail = buffer->capacity - 1; - } else { - buffer->tail--; - } - - memcpy((char *)buffer->data + buffer->tail * buffer->item_size, value, buffer->item_size); - - ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index should be valid after decrement"); - - return SUCCESS; + ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); + ZEND_ASSERT(buffer->data != NULL && "Buffer data cannot be NULL"); + ZEND_ASSERT(value != NULL && "Value cannot be NULL"); + ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); + ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); + ZEND_ASSERT(buffer->item_size > 0 && "Item size must be positive"); + + // First check if resize is needed + if (should_resize) { + // Check resize conditions once + bool need_increase = circular_buffer_is_full(buffer); + bool need_decrease = !need_increase && should_decrease(buffer); + + if (need_increase || need_decrease) { + if (circular_buffer_realloc(buffer, 0) == FAILURE) { + return FAILURE; + } + } + } + + // If buffer is full after potential resize, fall back to normal push + if (circular_buffer_is_full(buffer)) { + if (should_resize) { + // Should not happen if resize worked correctly + ASYNC_ERROR(E_WARNING, "Buffer is still full after resize attempt"); + return FAILURE; + } else { + // Fall back to normal push behavior + return circular_buffer_push(buffer, value, false); + } + } + + /* + * Push front operation: + * 1. Move tail backward (with wraparound) + * 2. Store data at new tail position + * + * Visual example: + * Before: [ A| B| C| ] head=3, tail=0 + * ^ + * tail + * + * After: [X| A| B| C] head=3, tail=3 (wrapped around) + * ^ + * tail + */ + ZEND_ASSERT(!circular_buffer_is_full(buffer) && "Buffer should not be full at this point"); + + // Move tail backward (with wraparound) + if (buffer->tail == 0) { + buffer->tail = buffer->capacity - 1; + } else { + buffer->tail--; + } + + memcpy((char *) buffer->data + buffer->tail * buffer->item_size, value, buffer->item_size); + + ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index should be valid after decrement"); + + return SUCCESS; } /** @@ -455,41 +456,41 @@ zend_result circular_buffer_push_front(circular_buffer_t *buffer, const void *va */ zend_result circular_buffer_pop(circular_buffer_t *buffer, void *value) { - ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); - ZEND_ASSERT(buffer->data != NULL && "Buffer data cannot be NULL"); - ZEND_ASSERT(value != NULL && "Value cannot be NULL"); - ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); - ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); - ZEND_ASSERT(buffer->item_size > 0 && "Item size must be positive"); - - if(circular_buffer_is_empty(buffer)) { - ASYNC_ERROR(E_WARNING, "Cannot pop from empty circular buffer"); - return FAILURE; - } - - /* - * Classic circular buffer pop operation: - * 1. Read data from tail position - * 2. Advance tail to next position - * - * Visual example: - * Before: [ A| B| C| ] head=3, tail=0 - * ^ - * tail - * - * After: [ A| B| C| ] head=3, tail=1 - * ^ - * tail - * (A is returned, but memory isn't cleared for performance) - */ - ZEND_ASSERT(!circular_buffer_is_empty(buffer) && "Buffer should not be empty at this point"); - - memcpy(value, (char *)buffer->data + buffer->tail * buffer->item_size, buffer->item_size); - buffer->tail = next_index(buffer->tail, buffer->capacity); - - ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index should be valid after increment"); - - return SUCCESS; + ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); + ZEND_ASSERT(buffer->data != NULL && "Buffer data cannot be NULL"); + ZEND_ASSERT(value != NULL && "Value cannot be NULL"); + ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); + ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); + ZEND_ASSERT(buffer->item_size > 0 && "Item size must be positive"); + + if (circular_buffer_is_empty(buffer)) { + ASYNC_ERROR(E_WARNING, "Cannot pop from empty circular buffer"); + return FAILURE; + } + + /* + * Classic circular buffer pop operation: + * 1. Read data from tail position + * 2. Advance tail to next position + * + * Visual example: + * Before: [ A| B| C| ] head=3, tail=0 + * ^ + * tail + * + * After: [ A| B| C| ] head=3, tail=1 + * ^ + * tail + * (A is returned, but memory isn't cleared for performance) + */ + ZEND_ASSERT(!circular_buffer_is_empty(buffer) && "Buffer should not be empty at this point"); + + memcpy(value, (char *) buffer->data + buffer->tail * buffer->item_size, buffer->item_size); + buffer->tail = next_index(buffer->tail, buffer->capacity); + + ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index should be valid after increment"); + + return SUCCESS; } /** @@ -497,13 +498,13 @@ zend_result circular_buffer_pop(circular_buffer_t *buffer, void *value) */ bool circular_buffer_is_empty(const circular_buffer_t *buffer) { - // Empty when head == tail - return buffer->head == buffer->tail; + // Empty when head == tail + return buffer->head == buffer->tail; } bool circular_buffer_is_not_empty(const circular_buffer_t *buffer) { - return buffer->head != buffer->tail; + return buffer->head != buffer->tail; } /** @@ -511,9 +512,9 @@ bool circular_buffer_is_not_empty(const circular_buffer_t *buffer) */ bool circular_buffer_is_full(const circular_buffer_t *buffer) { - // Full when advancing head would make it equal to tail - // (we keep one slot empty to distinguish full from empty) - return next_index(buffer->head, buffer->capacity) == buffer->tail; + // Full when advancing head would make it equal to tail + // (we keep one slot empty to distinguish full from empty) + return next_index(buffer->head, buffer->capacity) == buffer->tail; } /** @@ -521,32 +522,32 @@ bool circular_buffer_is_full(const circular_buffer_t *buffer) */ size_t circular_buffer_count(const circular_buffer_t *buffer) { - ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); - ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); - ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); - - /* - * Two cases to handle: - * Case 1: head >= tail (normal order) - * count = head - tail - * - * Case 2: head < tail (wrapped around) - * count = capacity - tail + head - */ - size_t count; - if (buffer->head >= buffer->tail) { - count = buffer->head - buffer->tail; - } else { - count = buffer->capacity - buffer->tail + buffer->head; - } - - ZEND_ASSERT(count <= buffer->capacity && "Count cannot exceed capacity"); - return count; + ZEND_ASSERT(buffer != NULL && "Buffer cannot be NULL"); + ZEND_ASSERT(buffer->head < buffer->capacity && "Head index out of bounds"); + ZEND_ASSERT(buffer->tail < buffer->capacity && "Tail index out of bounds"); + + /* + * Two cases to handle: + * Case 1: head >= tail (normal order) + * count = head - tail + * + * Case 2: head < tail (wrapped around) + * count = capacity - tail + head + */ + size_t count; + if (buffer->head >= buffer->tail) { + count = buffer->head - buffer->tail; + } else { + count = buffer->capacity - buffer->tail + buffer->head; + } + + ZEND_ASSERT(count <= buffer->capacity && "Count cannot exceed capacity"); + return count; } size_t circular_buffer_capacity(const circular_buffer_t *buffer) { - return buffer->capacity - 1; // One slot is reserved to distinguish full from empty + return buffer->capacity - 1; // One slot is reserved to distinguish full from empty } // @@ -554,7 +555,7 @@ size_t circular_buffer_capacity(const circular_buffer_t *buffer) // circular_buffer_t *zval_circular_buffer_new(const size_t count, const allocator_t *allocator) { - return circular_buffer_new(count, sizeof(zval), allocator); + return circular_buffer_new(count, sizeof(zval), allocator); } /** @@ -563,8 +564,8 @@ circular_buffer_t *zval_circular_buffer_new(const size_t count, const allocator_ */ zend_result zval_circular_buffer_push(circular_buffer_t *buffer, zval *value, const bool should_resize) { - Z_TRY_ADDREF_P(value); - return circular_buffer_push(buffer, value, should_resize); + Z_TRY_ADDREF_P(value); + return circular_buffer_push(buffer, value, should_resize); } /** @@ -573,6 +574,6 @@ zend_result zval_circular_buffer_push(circular_buffer_t *buffer, zval *value, co */ zend_result zval_circular_buffer_pop(circular_buffer_t *buffer, zval *value) { - ZVAL_UNDEF(value); - return circular_buffer_pop(buffer, value); + ZVAL_UNDEF(value); + return circular_buffer_pop(buffer, value); } \ No newline at end of file diff --git a/internal/circular_buffer.h b/internal/circular_buffer.h index 85277a4..23d3ede 100644 --- a/internal/circular_buffer.h +++ b/internal/circular_buffer.h @@ -21,46 +21,48 @@ typedef struct _circular_buffer_s circular_buffer_t; -struct _circular_buffer_s { - size_t item_size; - size_t min_size; - size_t capacity; // Always a power of 2 for optimal performance - /** - * Optional memory optimization flag. - * When enabled, buffer will automatically shrink when usage drops below threshold. - */ - bool auto_optimize; - /** - * Decrease threshold. - * - * The number of elements to decrease the buffer size. - * - * This value is recalculated each time the buffer is resized or its size is increased. - * It is usually calculated using the formula: current_size / 2.5, - * meaning the buffer will be reduced when its current size is equal to or - * less than 2.5 times its current capacity. - * This approach prevents frequent buffer reductions without explicit necessity. - */ - size_t decrease_t; - /* allocator handlers */ - const allocator_t *allocator; - /* point to the buffer memory */ - void *data; - /** - * Head offset - points to the next position where data will be written. - * When buffer is empty, head == tail. - * Head can never catch up to tail (must maintain at least one free slot). - */ - size_t head; - /** - * Tail offset - points to the next position where data will be read from. - * When buffer is empty, tail == head. - * Tail points to valid data except when buffer is empty. - */ - size_t tail; +struct _circular_buffer_s +{ + size_t item_size; + size_t min_size; + size_t capacity; // Always a power of 2 for optimal performance + /** + * Optional memory optimization flag. + * When enabled, buffer will automatically shrink when usage drops below threshold. + */ + bool auto_optimize; + /** + * Decrease threshold. + * + * The number of elements to decrease the buffer size. + * + * This value is recalculated each time the buffer is resized or its size is increased. + * It is usually calculated using the formula: current_size / 2.5, + * meaning the buffer will be reduced when its current size is equal to or + * less than 2.5 times its current capacity. + * This approach prevents frequent buffer reductions without explicit necessity. + */ + size_t decrease_t; + /* allocator handlers */ + const allocator_t *allocator; + /* point to the buffer memory */ + void *data; + /** + * Head offset - points to the next position where data will be written. + * When buffer is empty, head == tail. + * Head can never catch up to tail (must maintain at least one free slot). + */ + size_t head; + /** + * Tail offset - points to the next position where data will be read from. + * When buffer is empty, tail == head. + * Tail points to valid data except when buffer is empty. + */ + size_t tail; }; -zend_result circular_buffer_ctor(circular_buffer_t *buffer, size_t count, const size_t item_size, const allocator_t *allocator); +zend_result +circular_buffer_ctor(circular_buffer_t *buffer, size_t count, const size_t item_size, const allocator_t *allocator); void circular_buffer_dtor(circular_buffer_t *buffer); circular_buffer_t *circular_buffer_new(const size_t count, const size_t item_size, const allocator_t *allocator); void circular_buffer_destroy(circular_buffer_t *buffer); @@ -79,4 +81,4 @@ circular_buffer_t *zval_circular_buffer_new(const size_t count, const allocator_ zend_result zval_circular_buffer_push(circular_buffer_t *buffer, zval *value, bool should_resize); zend_result zval_circular_buffer_pop(circular_buffer_t *buffer, zval *value); -#endif //ASYNC_CIRCULAR_BUFFER_V2_H \ No newline at end of file +#endif // ASYNC_CIRCULAR_BUFFER_V2_H \ No newline at end of file diff --git a/internal/tests/circular_buffer_test.c b/internal/tests/circular_buffer_test.c index 8545424..33e92a1 100644 --- a/internal/tests/circular_buffer_test.c +++ b/internal/tests/circular_buffer_test.c @@ -19,106 +19,98 @@ #include #include "../internal/circular_buffer.h" -#define ASSERT(condition, message) \ - do { \ - if (!(condition)) { \ - fprintf(stderr, "Assertion failed: %s\n", #condition); \ - fprintf(stderr, "Message: %s\n", message); \ - fprintf(stderr, "File: %s, Line: %d\n", __FILE__, __LINE__); \ - exit(1); \ - } \ - } while (0) - -typedef struct { - int a; - int b; +#define ASSERT(condition, message) \ + do { \ + if (!(condition)) { \ + fprintf(stderr, "Assertion failed: %s\n", #condition); \ + fprintf(stderr, "Message: %s\n", message); \ + fprintf(stderr, "File: %s, Line: %d\n", __FILE__, __LINE__); \ + exit(1); \ + } \ + } while (0) + +typedef struct +{ + int a; + int b; char c; char d; } test_struct_t; static void test_create_and_destroy() { - circular_buffer_t *buffer = circular_buffer_new(8, sizeof(test_struct_t), NULL); + circular_buffer_t *buffer = circular_buffer_new(8, sizeof(test_struct_t), NULL); ASSERT(buffer != NULL, "Buffer creation failed"); - ASSERT(buffer->item_size == sizeof(test_struct_t), "Buffer item size mismatch"); + ASSERT(buffer->item_size == sizeof(test_struct_t), "Buffer item size mismatch"); - circular_buffer_destroy(buffer); - printf("[*] test_create_and_destroy passed\n"); + circular_buffer_destroy(buffer); + printf("[*] test_create_and_destroy passed\n"); } static void test_push_and_pop() { - circular_buffer_t *buffer = circular_buffer_new(16, sizeof(test_struct_t), NULL); - test_struct_t value_in = {1, 2, 'a', 'b'}; - test_struct_t value_out = {0, 0, 0, 0}; - - ASSERT(circular_buffer_push(buffer, &value_in, true) == SUCCESS, "Push operation failed"); - ASSERT(circular_buffer_pop(buffer, &value_out) == SUCCESS, "Pop operation failed"); - - ASSERT( - value_in.a == value_out.a && - value_in.b == value_out.b && - value_in.c == value_out.c && - value_in.d == value_out.d - , "Value mismatch after pop" - ); - - circular_buffer_destroy(buffer); - printf("[*] test_push_and_pop passed\n"); + circular_buffer_t *buffer = circular_buffer_new(16, sizeof(test_struct_t), NULL); + test_struct_t value_in = { 1, 2, 'a', 'b' }; + test_struct_t value_out = { 0, 0, 0, 0 }; + + ASSERT(circular_buffer_push(buffer, &value_in, true) == SUCCESS, "Push operation failed"); + ASSERT(circular_buffer_pop(buffer, &value_out) == SUCCESS, "Pop operation failed"); + + ASSERT(value_in.a == value_out.a && value_in.b == value_out.b && value_in.c == value_out.c && + value_in.d == value_out.d, + "Value mismatch after pop"); + + circular_buffer_destroy(buffer); + printf("[*] test_push_and_pop passed\n"); } static void test_is_empty_and_is_full() { - // Request size 2, but will be rounded up to 2 (already power of 2) - // Capacity=2 means 1 usable slot (1 slot reserved to distinguish full/empty) - circular_buffer_t *buffer = circular_buffer_new(2, sizeof(test_struct_t), NULL); - test_struct_t value = {100, 200, 'x', 'q'}; + // Request size 2, but will be rounded up to 2 (already power of 2) + // Capacity=2 means 1 usable slot (1 slot reserved to distinguish full/empty) + circular_buffer_t *buffer = circular_buffer_new(2, sizeof(test_struct_t), NULL); + test_struct_t value = { 100, 200, 'x', 'q' }; - ASSERT(circular_buffer_is_empty(buffer), "Buffer should be empty initially"); - ASSERT(!circular_buffer_is_full(buffer), "Buffer should not be full initially"); + ASSERT(circular_buffer_is_empty(buffer), "Buffer should be empty initially"); + ASSERT(!circular_buffer_is_full(buffer), "Buffer should not be full initially"); - circular_buffer_push(buffer, &value, true); - ASSERT(!circular_buffer_is_empty(buffer), "Buffer should not be empty after push"); + circular_buffer_push(buffer, &value, true); + ASSERT(!circular_buffer_is_empty(buffer), "Buffer should not be empty after push"); - ASSERT(circular_buffer_is_full(buffer), "Buffer should be full after one push (capacity=2, usable=1)"); + ASSERT(circular_buffer_is_full(buffer), "Buffer should be full after one push (capacity=2, usable=1)"); - circular_buffer_destroy(buffer); - printf("[*] test_is_empty_and_is_full passed\n"); + circular_buffer_destroy(buffer); + printf("[*] test_is_empty_and_is_full passed\n"); } static void test_reallocation() { - circular_buffer_t *buffer = circular_buffer_new(2, sizeof(test_struct_t), NULL); - test_struct_t value = {100, 200, 'x', 'q'}; + circular_buffer_t *buffer = circular_buffer_new(2, sizeof(test_struct_t), NULL); + test_struct_t value = { 100, 200, 'x', 'q' }; // Insert 5 elements into the buffer - for (int i = 1; i <= 5; i++) { + for (int i = 1; i <= 5; i++) { value.a++; value.b--; - circular_buffer_push(buffer, &value, true); - } + circular_buffer_push(buffer, &value, true); + } // Assert insertion - test_struct_t expected = {100, 200, 'x', 'q'}; - test_struct_t result = {0, 0, '0', '0'}; + test_struct_t expected = { 100, 200, 'x', 'q' }; + test_struct_t result = { 0, 0, '0', '0' }; for (int i = 1; i <= 5; i++) { expected.a++; expected.b--; - circular_buffer_pop(buffer, &result); - - ASSERT( - expected.a == result.a && - expected.b == result.b && - expected.c == result.c && - expected.d == result.d - , "Expected mismatch after pop" - ); + circular_buffer_pop(buffer, &result); + + ASSERT(expected.a == result.a && expected.b == result.b && expected.c == result.c && expected.d == result.d, + "Expected mismatch after pop"); } - circular_buffer_destroy(buffer); - printf("[*] test_reallocation passed\n"); + circular_buffer_destroy(buffer); + printf("[*] test_reallocation passed\n"); } static void test_wrap_around_order(void) @@ -127,9 +119,12 @@ static void test_wrap_around_order(void) int in, out; /* push 1 2 3 */ - in = 1; circular_buffer_push(buffer, &in, false); - in = 2; circular_buffer_push(buffer, &in, false); - in = 3; circular_buffer_push(buffer, &in, false); + in = 1; + circular_buffer_push(buffer, &in, false); + in = 2; + circular_buffer_push(buffer, &in, false); + in = 3; + circular_buffer_push(buffer, &in, false); /* pop two → expect 1, 2 */ circular_buffer_pop(buffer, &out); @@ -138,11 +133,13 @@ static void test_wrap_around_order(void) ASSERT(out == 2, "Expected 2 after second pop"); /* push 4 5 … here head will wrap */ - in = 4; circular_buffer_push(buffer, &in, false); - in = 5; circular_buffer_push(buffer, &in, false); + in = 4; + circular_buffer_push(buffer, &in, false); + in = 5; + circular_buffer_push(buffer, &in, false); /* pop remaining elements: expect 3 4 5 */ - int expect_seq[] = {3, 4, 5}; + int expect_seq[] = { 3, 4, 5 }; for (size_t i = 0; i < 3; i++) { circular_buffer_pop(buffer, &out); ASSERT(out == expect_seq[i], "Sequence mismatch after wrap‑around"); @@ -161,9 +158,12 @@ static void test_wrap_realloc(void) int in, out; /* fill 1,2,3 (fills the buffer) */ - in = 1; circular_buffer_push(buffer, &in, true); - in = 2; circular_buffer_push(buffer, &in, true); - in = 3; circular_buffer_push(buffer, &in, true); + in = 1; + circular_buffer_push(buffer, &in, true); + in = 2; + circular_buffer_push(buffer, &in, true); + in = 3; + circular_buffer_push(buffer, &in, true); /* pop two (removes 1, 2) */ circular_buffer_pop(buffer, &out); @@ -175,14 +175,17 @@ static void test_wrap_realloc(void) ASSERT(current_count == 1, "Buffer should have 1 item before realloc"); /* push 4, 5 (should fit in current capacity=4) */ - in = 4; circular_buffer_push(buffer, &in, true); - in = 5; circular_buffer_push(buffer, &in, true); - + in = 4; + circular_buffer_push(buffer, &in, true); + in = 5; + circular_buffer_push(buffer, &in, true); + /* push 6 (triggers realloc: 4 -> 8) */ - in = 6; circular_buffer_push(buffer, &in, true); /* realloc here */ + in = 6; + circular_buffer_push(buffer, &in, true); /* realloc here */ /* Pop remaining 4 elements: expect 3,4,5,6 */ - int expect_seq[] = {3,4,5,6}; + int expect_seq[] = { 3, 4, 5, 6 }; for (size_t i = 0; i < 4; i++) { circular_buffer_pop(buffer, &out); ASSERT(out == expect_seq[i], "Order mismatch after realloc wrap‑around"); @@ -198,22 +201,32 @@ static void test_wrap_with_decrease_realloc(void) circular_buffer_t *buffer = circular_buffer_new(2, sizeof(int), NULL); int in, out; - in = 1; circular_buffer_push(buffer, &in, true); - in = 2; circular_buffer_push(buffer, &in, true); - in = 3; circular_buffer_push(buffer, &in, true); - in = 4; circular_buffer_push(buffer, &in, true); - in = 5; circular_buffer_push(buffer, &in, true); + in = 1; + circular_buffer_push(buffer, &in, true); + in = 2; + circular_buffer_push(buffer, &in, true); + in = 3; + circular_buffer_push(buffer, &in, true); + in = 4; + circular_buffer_push(buffer, &in, true); + in = 5; + circular_buffer_push(buffer, &in, true); for (size_t i = 1; i <= 5; i++) { circular_buffer_pop(buffer, &out); ASSERT(out == i, "Order mismatch"); } - in = 1; circular_buffer_push(buffer, &in, true); - in = 2; circular_buffer_push(buffer, &in, true); - in = 3; circular_buffer_push(buffer, &in, true); - in = 4; circular_buffer_push(buffer, &in, true); - in = 5; circular_buffer_push(buffer, &in, true); + in = 1; + circular_buffer_push(buffer, &in, true); + in = 2; + circular_buffer_push(buffer, &in, true); + in = 3; + circular_buffer_push(buffer, &in, true); + in = 4; + circular_buffer_push(buffer, &in, true); + in = 5; + circular_buffer_push(buffer, &in, true); for (size_t i = 1; i <= 5; i++) { circular_buffer_pop(buffer, &out); @@ -231,7 +244,7 @@ static void test_wrap_with_decrease2_realloc(void) int in, out; for (size_t i = 1; i <= 16; i++) { - in = (int)i; + in = (int) i; circular_buffer_push(buffer, &in, true); } @@ -240,15 +253,17 @@ static void test_wrap_with_decrease2_realloc(void) ASSERT(out == i, "Order mismatch"); } - in = 17; circular_buffer_push(buffer, &in, true); + in = 17; + circular_buffer_push(buffer, &in, true); for (size_t i = 15; i <= 15; i++) { circular_buffer_pop(buffer, &out); ASSERT(out == i, "Order mismatch"); } - //buffer->decrease_t = 20; // Set a high decrease threshold to force reallocation - in = 18; circular_buffer_push(buffer, &in, true); + // buffer->decrease_t = 20; // Set a high decrease threshold to force reallocation + in = 18; + circular_buffer_push(buffer, &in, true); for (size_t i = 16; i <= 18; i++) { circular_buffer_pop(buffer, &out); @@ -260,51 +275,50 @@ static void test_wrap_with_decrease2_realloc(void) printf("[*] test_wrap_with_decrease2_realloc passed\n"); } - static void test_pop_empty() { - circular_buffer_t *buffer = circular_buffer_new(2, sizeof(test_struct_t), NULL); - test_struct_t result = {0, 0, '0', '0'}; + circular_buffer_t *buffer = circular_buffer_new(2, sizeof(test_struct_t), NULL); + test_struct_t result = { 0, 0, '0', '0' }; - ASSERT(circular_buffer_pop(buffer, &result) == FAILURE, "Pop from empty buffer should fail"); + ASSERT(circular_buffer_pop(buffer, &result) == FAILURE, "Pop from empty buffer should fail"); - circular_buffer_destroy(buffer); - printf("[*] test_pop_empty passed\n"); + circular_buffer_destroy(buffer); + printf("[*] test_pop_empty passed\n"); } static void test_push_full() { - // Capacity=2, usable=1 slot - circular_buffer_t *buffer = circular_buffer_new(2, sizeof(test_struct_t), NULL); - test_struct_t value = {100, 200, 'x', 'q'}; + // Capacity=2, usable=1 slot + circular_buffer_t *buffer = circular_buffer_new(2, sizeof(test_struct_t), NULL); + test_struct_t value = { 100, 200, 'x', 'q' }; - // Fill the only usable slot - circular_buffer_push(buffer, &value, false); + // Fill the only usable slot + circular_buffer_push(buffer, &value, false); - // Second push should fail (buffer is full) - ASSERT(circular_buffer_push(buffer, &value, false) == FAILURE, "Push to full buffer should fail"); + // Second push should fail (buffer is full) + ASSERT(circular_buffer_push(buffer, &value, false) == FAILURE, "Push to full buffer should fail"); - circular_buffer_destroy(buffer); - printf("[*] test_push_full passed\n"); + circular_buffer_destroy(buffer); + printf("[*] test_push_full passed\n"); } static void test_head_and_tail_exchange() { - circular_buffer_t *buffer = circular_buffer_new(4, sizeof(test_struct_t), NULL); - test_struct_t value = {100, 200, 'x', 'q'}; + circular_buffer_t *buffer = circular_buffer_new(4, sizeof(test_struct_t), NULL); + test_struct_t value = { 100, 200, 'x', 'q' }; // Insert 3 elements into the buffer - for (int i = 1; i <= 3; i++) { - circular_buffer_push(buffer, &value, false); - } + for (int i = 1; i <= 3; i++) { + circular_buffer_push(buffer, &value, false); + } - ASSERT(circular_buffer_is_full(buffer), "Buffer should be full"); + ASSERT(circular_buffer_is_full(buffer), "Buffer should be full"); - circular_buffer_pop(buffer, &value); - circular_buffer_pop(buffer, &value); + circular_buffer_pop(buffer, &value); + circular_buffer_pop(buffer, &value); circular_buffer_push(buffer, &value, false); - test_struct_t new_value = {500, 500, 'a', 'z'}; + test_struct_t new_value = { 500, 500, 'a', 'z' }; /** * If the head is to the left of the tail and the difference between them is one element, * the circular buffer is considered full, even though the tail points to a read element @@ -316,108 +330,96 @@ static void test_head_and_tail_exchange() * * The minimum difference between them must always be one element if the head is to the left. */ - circular_buffer_push(buffer, &new_value, false); + circular_buffer_push(buffer, &new_value, false); - ASSERT(circular_buffer_push(buffer, &new_value, false) == FAILURE, "Push to full buffer should fail"); + ASSERT(circular_buffer_push(buffer, &new_value, false) == FAILURE, "Push to full buffer should fail"); - // Buffer full? - ASSERT(circular_buffer_is_full(buffer), "Buffer should be full"); + // Buffer full? + ASSERT(circular_buffer_is_full(buffer), "Buffer should be full"); circular_buffer_pop(buffer, &value); circular_buffer_pop(buffer, &value); - // This value should be equal to the {100, 200, 'x', 'q'} - ASSERT( - value.a == 100 && - value.b == 200 && - value.c == 'x' && - value.d == 'q' - , "Value mismatch after pop" - ); - - // This value should be equal to the {500, 500, 'a', 'z'} - circular_buffer_pop(buffer, &value); - ASSERT( - value.a == 500 && - value.b == 500 && - value.c == 'a' && - value.d == 'z' - , "Value mismatch after pop" - ); - - ASSERT(circular_buffer_is_empty(buffer), "Buffer should be empty"); - - circular_buffer_destroy(buffer); - printf("[*] test_head_and_tail_exchange passed\n"); -} + // This value should be equal to the {100, 200, 'x', 'q'} + ASSERT(value.a == 100 && value.b == 200 && value.c == 'x' && value.d == 'q', "Value mismatch after pop"); + // This value should be equal to the {500, 500, 'a', 'z'} + circular_buffer_pop(buffer, &value); + ASSERT(value.a == 500 && value.b == 500 && value.c == 'a' && value.d == 'z', "Value mismatch after pop"); + + ASSERT(circular_buffer_is_empty(buffer), "Buffer should be empty"); + + circular_buffer_destroy(buffer); + printf("[*] test_head_and_tail_exchange passed\n"); +} static void test_power_of_2_rounding() { - // Test that requested sizes are rounded up to power of 2 - circular_buffer_t *buffer; - - // Request 3, should get 4 - buffer = circular_buffer_new(3, sizeof(int), NULL); - ASSERT(buffer->capacity == 4, "Size 3 should round up to 4"); - circular_buffer_destroy(buffer); - - // Request 5, should get 8 - buffer = circular_buffer_new(5, sizeof(int), NULL); - ASSERT(buffer->capacity == 8, "Size 5 should round up to 8"); - circular_buffer_destroy(buffer); - - // Request 10, should get 16 - buffer = circular_buffer_new(10, sizeof(int), NULL); - ASSERT(buffer->capacity == 16, "Size 10 should round up to 16"); - circular_buffer_destroy(buffer); - - // Request 16, should stay 16 (already power of 2) - buffer = circular_buffer_new(16, sizeof(int), NULL); - ASSERT(buffer->capacity == 16, "Size 16 should stay 16"); - circular_buffer_destroy(buffer); - - printf("[*] test_power_of_2_rounding passed\n"); + // Test that requested sizes are rounded up to power of 2 + circular_buffer_t *buffer; + + // Request 3, should get 4 + buffer = circular_buffer_new(3, sizeof(int), NULL); + ASSERT(buffer->capacity == 4, "Size 3 should round up to 4"); + circular_buffer_destroy(buffer); + + // Request 5, should get 8 + buffer = circular_buffer_new(5, sizeof(int), NULL); + ASSERT(buffer->capacity == 8, "Size 5 should round up to 8"); + circular_buffer_destroy(buffer); + + // Request 10, should get 16 + buffer = circular_buffer_new(10, sizeof(int), NULL); + ASSERT(buffer->capacity == 16, "Size 10 should round up to 16"); + circular_buffer_destroy(buffer); + + // Request 16, should stay 16 (already power of 2) + buffer = circular_buffer_new(16, sizeof(int), NULL); + ASSERT(buffer->capacity == 16, "Size 16 should stay 16"); + circular_buffer_destroy(buffer); + + printf("[*] test_power_of_2_rounding passed\n"); } static void test_zval_buffer() { - zval value_in; - zval value_out; - ZVAL_STRING(&value_in, "Hello, World!"); + zval value_in; + zval value_out; + ZVAL_STRING(&value_in, "Hello, World!"); - // Request 5, will be rounded to 8 - circular_buffer_t *buffer = zval_circular_buffer_new(5, NULL); - ASSERT(buffer != NULL, "zval buffer creation failed"); - ASSERT(buffer->capacity == 8, "Size 5 should round up to 8"); + // Request 5, will be rounded to 8 + circular_buffer_t *buffer = zval_circular_buffer_new(5, NULL); + ASSERT(buffer != NULL, "zval buffer creation failed"); + ASSERT(buffer->capacity == 8, "Size 5 should round up to 8"); - ASSERT(zval_circular_buffer_push(buffer, &value_in, true) == SUCCESS, "zval push failed"); - ASSERT(zval_circular_buffer_pop(buffer, &value_out) == SUCCESS, "zval pop failed"); + ASSERT(zval_circular_buffer_push(buffer, &value_in, true) == SUCCESS, "zval push failed"); + ASSERT(zval_circular_buffer_pop(buffer, &value_out) == SUCCESS, "zval pop failed"); - ASSERT(Z_TYPE(value_out) == IS_STRING && strcmp(Z_STRVAL(value_out), "Hello, World!") == 0, "zval value mismatch"); + ASSERT(Z_TYPE(value_out) == IS_STRING && strcmp(Z_STRVAL(value_out), "Hello, World!") == 0, "zval value mismatch"); - zval_ptr_dtor(&value_in); - zval_ptr_dtor(&value_out); - circular_buffer_destroy(buffer); + zval_ptr_dtor(&value_in); + zval_ptr_dtor(&value_out); + circular_buffer_destroy(buffer); - printf("[*] test_zval_buffer passed\n"); + printf("[*] test_zval_buffer passed\n"); } -int main() { - test_create_and_destroy(); - test_push_and_pop(); - test_is_empty_and_is_full(); - test_reallocation(); +int main() +{ + test_create_and_destroy(); + test_push_and_pop(); + test_is_empty_and_is_full(); + test_reallocation(); test_wrap_around_order(); test_wrap_realloc(); test_wrap_with_decrease_realloc(); test_wrap_with_decrease2_realloc(); - test_pop_empty(); - test_push_full(); - test_head_and_tail_exchange(); - test_power_of_2_rounding(); - test_zval_buffer(); - - printf("\n[✅] All tests passed! Buffer now uses power-of-2 optimization.\n"); - return 0; + test_pop_empty(); + test_push_full(); + test_head_and_tail_exchange(); + test_power_of_2_rounding(); + test_zval_buffer(); + + printf("\n[✅] All tests passed! Buffer now uses power-of-2 optimization.\n"); + return 0; } \ No newline at end of file diff --git a/internal/tests/circular_buffer_test.h b/internal/tests/circular_buffer_test.h index 11e097e..4f8edb6 100644 --- a/internal/tests/circular_buffer_test.h +++ b/internal/tests/circular_buffer_test.h @@ -18,4 +18,4 @@ void circular_buffer_run(void); -#endif //CIRCULAR_BUFFER_TEST_H +#endif // CIRCULAR_BUFFER_TEST_H diff --git a/internal/tests/main.c b/internal/tests/main.c index 6c16ab3..1a3bfb7 100644 --- a/internal/tests/main.c +++ b/internal/tests/main.c @@ -26,7 +26,8 @@ #include "circular_buffer_test.h" -int main() { +int main() +{ circular_buffer_run(); printf("All tests passed!\n"); return 0; diff --git a/internal/zval_circular_buffer.h b/internal/zval_circular_buffer.h index 3752ddb..be85920 100644 --- a/internal/zval_circular_buffer.h +++ b/internal/zval_circular_buffer.h @@ -21,14 +21,14 @@ zend_always_inline static void zval_c_buffer_new(size_t count, const allocator_t *allocator) { - if(circular_buffer_new(count, sizeof(zval), allocator) == NULL) { + if (circular_buffer_new(count, sizeof(zval), allocator) == NULL) { zend_throw_error(NULL, "Failed to allocate memory for zval circular buffer"); } } zend_always_inline static void zval_c_buffer_push_with_resize(circular_buffer_t *buffer, zval *value) { - if(circular_buffer_push(buffer, value, true) == FAILURE) { + if (circular_buffer_push(buffer, value, true) == FAILURE) { zend_throw_error(NULL, "Failed to push zval into circular buffer"); } else { Z_TRY_ADDREF_P(value); @@ -37,12 +37,12 @@ zend_always_inline static void zval_c_buffer_push_with_resize(circular_buffer_t zend_always_inline static void zval_c_buffer_push(circular_buffer_t *buffer, zval *value) { - if(circular_buffer_is_full(buffer)) { - zend_throw_error(NULL, "Failed to push zval into circular buffer: buffer is full"); + if (circular_buffer_is_full(buffer)) { + zend_throw_error(NULL, "Failed to push zval into circular buffer: buffer is full"); return; } - if(circular_buffer_push(buffer, value, false) == FAILURE) { + if (circular_buffer_push(buffer, value, false) == FAILURE) { zend_throw_error(NULL, "Failed to push zval into circular buffer"); } else { Z_TRY_ADDREF_P(value); @@ -64,4 +64,4 @@ zend_always_inline static void zval_c_buffer_cleanup(circular_buffer_t *buffer) } } -#endif //ZVAL_CIRCULAR_BUFFER_H \ No newline at end of file +#endif // ZVAL_CIRCULAR_BUFFER_H \ No newline at end of file diff --git a/iterator.c b/iterator.c index 72346aa..b3c5984 100644 --- a/iterator.c +++ b/iterator.c @@ -22,7 +22,7 @@ /** * An additional coroutine destructor that frees the iterator if the coroutine never started. */ -void coroutine_extended_dispose(zend_coroutine_t * coroutine) +void coroutine_extended_dispose(zend_coroutine_t *coroutine) { if (coroutine->extended_data == NULL) { return; @@ -39,12 +39,12 @@ void iterator_microtask(zend_async_microtask_t *microtask) { async_iterator_t *iterator = (async_iterator_t *) microtask; - if (iterator->state == ASYNC_ITERATOR_FINISHED - || (iterator->concurrency > 0 && iterator->active_coroutines >= iterator->concurrency)) { + if (iterator->state == ASYNC_ITERATOR_FINISHED || + (iterator->concurrency > 0 && iterator->active_coroutines >= iterator->concurrency)) { return; } - zend_coroutine_t * coroutine = ZEND_ASYNC_SPAWN_WITH_SCOPE_EX(iterator->scope, iterator->priority); + zend_coroutine_t *coroutine = ZEND_ASYNC_SPAWN_WITH_SCOPE_EX(iterator->scope, iterator->priority); if (coroutine == NULL) { return; @@ -71,7 +71,7 @@ void iterator_dtor(zend_async_microtask_t *microtask) // Call the extended destructor if it exists ASYNC_ITERATOR_DTOR extended_dtor = iterator->extended_dtor; iterator->extended_dtor = NULL; - extended_dtor((zend_async_iterator_t *)iterator); + extended_dtor((zend_async_iterator_t *) iterator); } // Free hash iterator if it was allocated @@ -114,45 +114,43 @@ void iterator_dtor(zend_async_microtask_t *microtask) // Safe iterator modification means making changes during which no new iterator coroutines will be created, // because the iterator’s state is undefined. // -#define ITERATOR_SAFE_MOVING_START(iterator) \ - (iterator)->state = ASYNC_ITERATOR_MOVING; \ - (iterator)->microtask.is_cancelled = true; \ +#define ITERATOR_SAFE_MOVING_START(iterator) \ + (iterator)->state = ASYNC_ITERATOR_MOVING; \ + (iterator)->microtask.is_cancelled = true; \ uint32_t prev_ref_count = (iterator)->microtask.ref_count; // // End of the block for safe iterator modification. // -#define ITERATOR_SAFE_MOVING_END(iterator) \ - (iterator)->state = ASYNC_ITERATOR_STARTED; \ - if (prev_ref_count != (iterator)->microtask.ref_count) { \ - (iterator)->microtask.is_cancelled = false; \ - ZEND_ASYNC_ADD_MICROTASK(&(iterator)->microtask); \ +#define ITERATOR_SAFE_MOVING_END(iterator) \ + (iterator)->state = ASYNC_ITERATOR_STARTED; \ + if (prev_ref_count != (iterator)->microtask.ref_count) { \ + (iterator)->microtask.is_cancelled = false; \ + ZEND_ASYNC_ADD_MICROTASK(&(iterator)->microtask); \ } -async_iterator_t * async_iterator_new( - zval *array, - zend_object_iterator *zend_iterator, - zend_fcall_t *fcall, - async_iterator_handler_t handler, - zend_async_scope_t *scope, - unsigned int concurrency, - int32_t priority, - size_t iterator_size - ) +async_iterator_t *async_iterator_new(zval *array, + zend_object_iterator *zend_iterator, + zend_fcall_t *fcall, + async_iterator_handler_t handler, + zend_async_scope_t *scope, + unsigned int concurrency, + int32_t priority, + size_t iterator_size) { if (iterator_size == 0) { iterator_size = sizeof(async_iterator_t); } - async_iterator_t * iterator = ecalloc(1, iterator_size); + async_iterator_t *iterator = ecalloc(1, iterator_size); iterator->microtask.handler = iterator_microtask; iterator->microtask.dtor = iterator_dtor; iterator->microtask.ref_count = 1; - - iterator->run = (void (*)(zend_async_iterator_t *))async_iterator_run; - iterator->run_in_coroutine = (void (*)(zend_async_iterator_t *, int32_t))async_iterator_run_in_coroutine; - + + iterator->run = (void (*)(zend_async_iterator_t *)) async_iterator_run; + iterator->run_in_coroutine = (void (*)(zend_async_iterator_t *, int32_t)) async_iterator_run_in_coroutine; + iterator->state = ASYNC_ITERATOR_INIT; iterator->concurrency = concurrency; @@ -232,8 +230,8 @@ static zend_always_inline void iterate(async_iterator_t *iterator) } if (iterator->zend_iterator == NULL) { - iterator->position = 0; - iterator->hash_iterator = -1; + iterator->position = 0; + iterator->hash_iterator = -1; zend_hash_internal_pointer_reset_ex(Z_ARRVAL(iterator->array), &iterator->position); iterator->hash_iterator = zend_hash_iterator_add(Z_ARRVAL(iterator->array), iterator->position); @@ -252,15 +250,17 @@ static zend_always_inline void iterate(async_iterator_t *iterator) iterator->hash_iterator = -1; if (iterator->zend_iterator->funcs->rewind) { - ITERATOR_SAFE_MOVING_START(iterator) { + ITERATOR_SAFE_MOVING_START(iterator) + { iterator->zend_iterator->funcs->rewind(iterator->zend_iterator); - } ITERATOR_SAFE_MOVING_END(iterator); + } + ITERATOR_SAFE_MOVING_END(iterator); } RETURN_IF_EXCEPTION(iterator); } - zval * current; + zval *current; zval current_item; zval key; ZVAL_UNDEF(¤t_item); @@ -279,9 +279,11 @@ static zend_always_inline void iterate(async_iterator_t *iterator) } else if (SUCCESS == iterator->zend_iterator->funcs->valid(iterator->zend_iterator)) { RETURN_IF_EXCEPTION(iterator); - ITERATOR_SAFE_MOVING_START(iterator) { + ITERATOR_SAFE_MOVING_START(iterator) + { current = iterator->zend_iterator->funcs->get_current_data(iterator->zend_iterator); - } ITERATOR_SAFE_MOVING_END(iterator); + } + ITERATOR_SAFE_MOVING_END(iterator); RETURN_IF_EXCEPTION(iterator); if (current != NULL) { @@ -306,19 +308,21 @@ static zend_always_inline void iterate(async_iterator_t *iterator) if (Z_TYPE_P(current) == IS_UNDEF) { if (iterator->zend_iterator == NULL) { - zend_hash_move_forward(Z_ARR(iterator->array)); - } else { + zend_hash_move_forward(Z_ARR(iterator->array)); + } else { - if (iterator->state == ASYNC_ITERATOR_MOVING) { - return; - } + if (iterator->state == ASYNC_ITERATOR_MOVING) { + return; + } - ITERATOR_SAFE_MOVING_START(iterator) { - iterator->zend_iterator->funcs->move_forward(iterator->zend_iterator); - } ITERATOR_SAFE_MOVING_END(iterator); + ITERATOR_SAFE_MOVING_START(iterator) + { + iterator->zend_iterator->funcs->move_forward(iterator->zend_iterator); + } + ITERATOR_SAFE_MOVING_END(iterator); - RETURN_IF_EXCEPTION(iterator); - } + RETURN_IF_EXCEPTION(iterator); + } continue; } @@ -327,30 +331,34 @@ static zend_always_inline void iterate(async_iterator_t *iterator) /* Retrieve key */ if (iterator->target_hash != NULL) { zend_hash_get_current_key_zval_ex(iterator->target_hash, &key, &iterator->position); - } else { - ITERATOR_SAFE_MOVING_START(iterator) { - iterator->zend_iterator->funcs->get_current_key(iterator->zend_iterator, &key); - } ITERATOR_SAFE_MOVING_END(iterator); + } else { + ITERATOR_SAFE_MOVING_START(iterator) + { + iterator->zend_iterator->funcs->get_current_key(iterator->zend_iterator, &key); + } + ITERATOR_SAFE_MOVING_END(iterator); - RETURN_IF_EXCEPTION_AND(iterator, zval_ptr_dtor(¤t_item)); - } + RETURN_IF_EXCEPTION_AND(iterator, zval_ptr_dtor(¤t_item)); + } /* * Move to next element already now -- this mirrors the approach used by foreach * and ensures proper behavior with regard to modifications. */ - if (iterator->target_hash != NULL) { - zend_hash_move_forward_ex(iterator->target_hash, &iterator->position); - // And update the iterator position - EG(ht_iterators)[iterator->hash_iterator].pos = iterator->position; - } else { + if (iterator->target_hash != NULL) { + zend_hash_move_forward_ex(iterator->target_hash, &iterator->position); + // And update the iterator position + EG(ht_iterators)[iterator->hash_iterator].pos = iterator->position; + } else { - ITERATOR_SAFE_MOVING_START(iterator) { - iterator->zend_iterator->funcs->move_forward(iterator->zend_iterator); - } ITERATOR_SAFE_MOVING_END(iterator); + ITERATOR_SAFE_MOVING_START(iterator) + { + iterator->zend_iterator->funcs->move_forward(iterator->zend_iterator); + } + ITERATOR_SAFE_MOVING_END(iterator); - RETURN_IF_EXCEPTION_AND(iterator, zval_ptr_dtor(¤t_item); zval_ptr_dtor(&key)); - } + RETURN_IF_EXCEPTION_AND(iterator, zval_ptr_dtor(¤t_item); zval_ptr_dtor(&key)); + } if (iterator->fcall != NULL) { /* Call the userland function */ @@ -368,9 +376,9 @@ static zend_always_inline void iterate(async_iterator_t *iterator) if (result == SUCCESS) { if (Z_TYPE(retval) == IS_FALSE) { - iterator->state = ASYNC_ITERATOR_FINISHED; + iterator->state = ASYNC_ITERATOR_FINISHED; iterator->microtask.is_cancelled = true; - } + } zval_ptr_dtor(&retval); @@ -393,8 +401,8 @@ static zend_always_inline void iterate(async_iterator_t *iterator) if (UNEXPECTED(result == FAILURE || EG(exception) != NULL)) { iterator->state = ASYNC_ITERATOR_FINISHED; iterator->microtask.is_cancelled = true; - break; - } + break; + } } } @@ -452,7 +460,7 @@ void async_iterator_run_in_coroutine(async_iterator_t *iterator, int32_t priorit iterator->scope = ZEND_ASYNC_CURRENT_SCOPE; } - zend_coroutine_t * iterator_coroutine = ZEND_ASYNC_SPAWN_WITH_SCOPE_EX(iterator->scope, priority); + zend_coroutine_t *iterator_coroutine = ZEND_ASYNC_SPAWN_WITH_SCOPE_EX(iterator->scope, priority); if (UNEXPECTED(iterator_coroutine == NULL || EG(exception))) { return; } @@ -471,9 +479,8 @@ void async_iterator_apply_exception(async_iterator_t *iterator) } ZEND_ASYNC_SCOPE_CANCEL( - iterator->scope, - async_new_exception(async_ce_cancellation_exception, "Cancellation of the iterator due to an exception"), - true, - ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(iterator->scope) - ); + iterator->scope, + async_new_exception(async_ce_cancellation_exception, "Cancellation of the iterator due to an exception"), + true, + ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(iterator->scope)); } \ No newline at end of file diff --git a/iterator.h b/iterator.h index 4043e5c..3e7a688 100644 --- a/iterator.h +++ b/iterator.h @@ -32,16 +32,14 @@ typedef enum ASYNC_ITERATOR_FINISHED, } async_iterator_state_t; -async_iterator_t * async_iterator_new( - zval *array, - zend_object_iterator *zend_iterator, - zend_fcall_t *fcall, - async_iterator_handler_t handler, - zend_async_scope_t *scope, - unsigned int concurrency, - int32_t priority, - size_t iterator_size -); +async_iterator_t *async_iterator_new(zval *array, + zend_object_iterator *zend_iterator, + zend_fcall_t *fcall, + async_iterator_handler_t handler, + zend_async_scope_t *scope, + unsigned int concurrency, + int32_t priority, + size_t iterator_size); #define ASYNC_ITERATOR_DTOR zend_async_iterator_method_t @@ -49,7 +47,8 @@ void async_iterator_run(async_iterator_t *iterator); void async_iterator_run_in_coroutine(async_iterator_t *iterator, int32_t priority); void async_iterator_apply_exception(async_iterator_t *iterator); -struct _async_iterator_t { +struct _async_iterator_t +{ ZEND_ASYNC_ITERATOR_FIELDS /* The current state of the iterator. See async_iterator_state_t */ async_iterator_state_t state; @@ -68,4 +67,4 @@ struct _async_iterator_t { zend_object_iterator *zend_iterator; }; -#endif //ITERATOR_H +#endif // ITERATOR_H diff --git a/libuv_reactor.c b/libuv_reactor.c index 7634a07..642356a 100644 --- a/libuv_reactor.c +++ b/libuv_reactor.c @@ -50,7 +50,10 @@ static void libuv_cleanup_process_events(void); #define LIBUV_REACTOR_VAR zend_async_globals *reactor = LIBUV_REACTOR; #define LIBUV_REACTOR_VAR_FROM(var) zend_async_globals *reactor = (zend_async_globals *) var; #define WATCHER ASYNC_G(watcherThread) -#define IF_EXCEPTION_STOP_REACTOR if (UNEXPECTED(EG(exception) != NULL)) { libuv_reactor_stop_with_exception(); } +#define IF_EXCEPTION_STOP_REACTOR \ + if (UNEXPECTED(EG(exception) != NULL)) { \ + libuv_reactor_stop_with_exception(); \ + } #define ASYNC_OF_EXCEPTION_MESSAGE "Async mode is disabled. Reactor API cannot be used." @@ -124,6 +127,7 @@ void libuv_reactor_startup(void) uv_loop_set_data(UVLOOP, ASYNC_GLOBALS); ASYNC_G(reactor_started) = true; } + /* }}} */ /* {{{ libuv_reactor_stop_with_exception */ @@ -131,6 +135,7 @@ static void libuv_reactor_stop_with_exception(void) { // TODO: implement libuv_reactor_stop_with_exception } + /* }}} */ /* {{{ libuv_reactor_shutdown */ @@ -152,6 +157,7 @@ void libuv_reactor_shutdown(void) ASYNC_G(reactor_started) = false; } } + /* }}} */ /* {{{ libuv_reactor_execute */ @@ -161,6 +167,7 @@ bool libuv_reactor_execute(bool no_wait) return ZEND_ASYNC_ACTIVE_EVENT_COUNT > 0 || has_handles; } + /* }}} */ /* {{{ libuv_reactor_loop_alive */ @@ -172,6 +179,7 @@ bool libuv_reactor_loop_alive(void) return ZEND_ASYNC_ACTIVE_EVENT_COUNT > 0 && uv_loop_alive(UVLOOP) != 0; } + /* }}} */ /* {{{ libuv_close_handle_cb */ @@ -179,6 +187,7 @@ static void libuv_close_handle_cb(uv_handle_t *handle) { pefree(handle->data, 0); } + /* }}} */ /* {{{ libuv_add_callback */ @@ -186,6 +195,7 @@ static void libuv_add_callback(zend_async_event_t *event, zend_async_event_callb { zend_async_callbacks_push(event, callback); } + /* }}} */ /* {{{ libuv_remove_callback */ @@ -193,6 +203,7 @@ static void libuv_remove_callback(zend_async_event_t *event, zend_async_event_ca { zend_async_callbacks_remove(event, callback); } + /* }}} */ ///////////////////////////////////////////////////////////////////////////// @@ -200,15 +211,13 @@ static void libuv_remove_callback(zend_async_event_t *event, zend_async_event_ca ////////////////////////////////////////////////////////////////////////////// /* {{{ on_poll_event */ -static void on_poll_event(uv_poll_t* handle, int status, int events) +static void on_poll_event(uv_poll_t *handle, int status, int events) { async_poll_event_t *poll = handle->data; zend_object *exception = NULL; if (status < 0) { - exception = async_new_exception( - async_ce_input_output_exception, "Input output error: %s", uv_strerror(status) - ); + exception = async_new_exception(async_ce_input_output_exception, "Input output error: %s", uv_strerror(status)); } poll->event.triggered_events = events; @@ -221,6 +230,7 @@ static void on_poll_event(uv_poll_t* handle, int status, int events) IF_EXCEPTION_STOP_REACTOR; } + /* }}} */ /* {{{ libuv_poll_start */ @@ -228,18 +238,19 @@ static void libuv_poll_start(zend_async_event_t *event) { EVENT_START_PROLOGUE(event); - async_poll_event_t *poll = (async_poll_event_t *)(event); + async_poll_event_t *poll = (async_poll_event_t *) (event); - const int error = uv_poll_start(&poll->uv_handle, poll->event.events, on_poll_event); + const int error = uv_poll_start(&poll->uv_handle, poll->event.events, on_poll_event); - if (error < 0) { - async_throw_error("Failed to start poll handle: %s", uv_strerror(error)); - return; - } + if (error < 0) { + async_throw_error("Failed to start poll handle: %s", uv_strerror(error)); + return; + } event->loop_ref_count++; - ZEND_ASYNC_INCREASE_EVENT_COUNT; + ZEND_ASYNC_INCREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_poll_stop */ @@ -247,7 +258,7 @@ static void libuv_poll_stop(zend_async_event_t *event) { EVENT_STOP_PROLOGUE(event); - async_poll_event_t *poll = (async_poll_event_t *)(event); + async_poll_event_t *poll = (async_poll_event_t *) (event); const int error = uv_poll_stop(&poll->uv_handle); @@ -259,6 +270,7 @@ static void libuv_poll_stop(zend_async_event_t *event) return; } } + /* }}} */ /* {{{ libuv_poll_dispose */ @@ -276,22 +288,21 @@ static void libuv_poll_dispose(zend_async_event_t *event) zend_async_callbacks_free(event); - async_poll_event_t *poll = (async_poll_event_t *)(event); + async_poll_event_t *poll = (async_poll_event_t *) (event); - uv_close((uv_handle_t *)&poll->uv_handle, libuv_close_handle_cb); + uv_close((uv_handle_t *) &poll->uv_handle, libuv_close_handle_cb); } + /* }}} */ /* {{{ libuv_new_poll_event */ -zend_async_poll_event_t* libuv_new_poll_event( - zend_file_descriptor_t fh, zend_socket_t socket, async_poll_event events, size_t extra_size -) +zend_async_poll_event_t * +libuv_new_poll_event(zend_file_descriptor_t fh, zend_socket_t socket, async_poll_event events, size_t extra_size) { START_REACTOR_OR_RETURN_NULL; - async_poll_event_t *poll = pecalloc(1, extra_size != 0 ? - sizeof(async_poll_event_t) + extra_size : - sizeof(async_poll_event_t), 0); + async_poll_event_t *poll = + pecalloc(1, extra_size != 0 ? sizeof(async_poll_event_t) + extra_size : sizeof(async_poll_event_t), 0); int error = 0; @@ -310,7 +321,6 @@ zend_async_poll_event_t* libuv_new_poll_event( poll->event.file = fh; #endif } else { - } if (error < 0) { @@ -334,13 +344,15 @@ zend_async_poll_event_t* libuv_new_poll_event( return &poll->event; } + /* }}} */ /* {{{ libuv_new_socket_event */ -zend_async_poll_event_t* libuv_new_socket_event(zend_socket_t socket, async_poll_event events, size_t extra_size) +zend_async_poll_event_t *libuv_new_socket_event(zend_socket_t socket, async_poll_event events, size_t extra_size) { return libuv_new_poll_event(ZEND_FD_NULL, socket, events, extra_size); } + /* }}} */ ///////////////////////////////////////////////////////////////////////////////// @@ -361,6 +373,7 @@ static void on_timer_event(uv_timer_t *handle) IF_EXCEPTION_STOP_REACTOR; } + /* }}} */ /* {{{ libuv_timer_start */ @@ -368,14 +381,12 @@ static void libuv_timer_start(zend_async_event_t *event) { EVENT_START_PROLOGUE(event); - async_timer_event_t *timer = (async_timer_event_t *)(event); + async_timer_event_t *timer = (async_timer_event_t *) (event); - const int error = uv_timer_start( - &timer->uv_handle, - on_timer_event, - timer->event.timeout, - timer->event.is_periodic ? timer->event.timeout : 0 - ); + const int error = uv_timer_start(&timer->uv_handle, + on_timer_event, + timer->event.timeout, + timer->event.is_periodic ? timer->event.timeout : 0); if (error < 0) { async_throw_error("Failed to start timer handle: %s", uv_strerror(error)); @@ -385,6 +396,7 @@ static void libuv_timer_start(zend_async_event_t *event) event->loop_ref_count++; ZEND_ASYNC_INCREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_timer_stop */ @@ -392,7 +404,7 @@ static void libuv_timer_stop(zend_async_event_t *event) { EVENT_STOP_PROLOGUE(event); - async_timer_event_t *timer = (async_timer_event_t *)(event); + async_timer_event_t *timer = (async_timer_event_t *) (event); const int error = uv_timer_stop(&timer->uv_handle); @@ -404,6 +416,7 @@ static void libuv_timer_stop(zend_async_event_t *event) return; } } + /* }}} */ /* {{{ libuv_timer_dispose */ @@ -421,20 +434,21 @@ static void libuv_timer_dispose(zend_async_event_t *event) zend_async_callbacks_free(event); - async_timer_event_t *timer = (async_timer_event_t *)(event); + async_timer_event_t *timer = (async_timer_event_t *) (event); - uv_close((uv_handle_t *)&timer->uv_handle, libuv_close_handle_cb); + uv_close((uv_handle_t *) &timer->uv_handle, libuv_close_handle_cb); } + /* }}} */ /* {{{ libuv_new_timer_event */ -zend_async_timer_event_t* libuv_new_timer_event(const zend_ulong timeout, const zend_ulong nanoseconds, const bool is_periodic, size_t extra_size) +zend_async_timer_event_t * +libuv_new_timer_event(const zend_ulong timeout, const zend_ulong nanoseconds, const bool is_periodic, size_t extra_size) { START_REACTOR_OR_RETURN_NULL; - async_timer_event_t *event = pecalloc( - 1, extra_size != 0 ? sizeof(async_timer_event_t) + extra_size : sizeof(async_timer_event_t), 0 - ); + async_timer_event_t *event = + pecalloc(1, extra_size != 0 ? sizeof(async_timer_event_t) + extra_size : sizeof(async_timer_event_t), 0); const int error = uv_timer_init(UVLOOP, &event->uv_handle); @@ -445,14 +459,14 @@ zend_async_timer_event_t* libuv_new_timer_event(const zend_ulong timeout, const } event->uv_handle.data = event; - + // Calculate final timeout with nanoseconds support zend_ulong final_timeout = timeout; if (nanoseconds > 0 && timeout == 0) { // If only nanoseconds provided, convert to milliseconds with ceiling - final_timeout = (nanoseconds + 999999) / 1000000; // Round up to next millisecond + final_timeout = (nanoseconds + 999999) / 1000000; // Round up to next millisecond } - + event->event.timeout = final_timeout; event->event.is_periodic = is_periodic; event->event.base.extra_offset = sizeof(async_timer_event_t); @@ -466,6 +480,7 @@ zend_async_timer_event_t* libuv_new_timer_event(const zend_ulong timeout, const return &event->event; } + /* }}} */ ///////////////////////////////////////////////////////////////////////////////// @@ -477,29 +492,31 @@ zend_async_timer_event_t* libuv_new_timer_event(const zend_ulong timeout, const /* {{{ libuv_signal_start */ static void libuv_signal_start(zend_async_event_t *event) { - EVENT_START_PROLOGUE(event); + EVENT_START_PROLOGUE(event); - async_signal_event_t *signal = (async_signal_event_t *)(event); + async_signal_event_t *signal = (async_signal_event_t *) (event); - libuv_add_signal_event(signal->event.signal, event); + libuv_add_signal_event(signal->event.signal, event); - event->loop_ref_count++; - ZEND_ASYNC_INCREASE_EVENT_COUNT; + event->loop_ref_count++; + ZEND_ASYNC_INCREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_signal_stop */ static void libuv_signal_stop(zend_async_event_t *event) { - EVENT_STOP_PROLOGUE(event); + EVENT_STOP_PROLOGUE(event); - async_signal_event_t *signal = (async_signal_event_t *)(event); + async_signal_event_t *signal = (async_signal_event_t *) (event); - libuv_remove_signal_event(signal->event.signal, event); + libuv_remove_signal_event(signal->event.signal, event); - event->loop_ref_count = 0; - ZEND_ASYNC_DECREASE_EVENT_COUNT; + event->loop_ref_count = 0; + ZEND_ASYNC_DECREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_signal_dispose */ @@ -510,38 +527,39 @@ static void libuv_signal_dispose(zend_async_event_t *event) return; } - if (event->loop_ref_count > 0) { - event->loop_ref_count = 1; - event->stop(event); - } + if (event->loop_ref_count > 0) { + event->loop_ref_count = 1; + event->stop(event); + } - zend_async_callbacks_free(event); + zend_async_callbacks_free(event); - // Signal cleanup handled by global signal management - pefree(event, 0); + // Signal cleanup handled by global signal management + pefree(event, 0); } + /* }}} */ /* {{{ libuv_new_signal_event */ -zend_async_signal_event_t* libuv_new_signal_event(int signum, size_t extra_size) +zend_async_signal_event_t *libuv_new_signal_event(int signum, size_t extra_size) { START_REACTOR_OR_RETURN_NULL; - async_signal_event_t *signal = pecalloc( - 1, extra_size != 0 ? sizeof(async_signal_event_t) + extra_size : sizeof(async_signal_event_t), 0 - ); - signal->event.signal = signum; + async_signal_event_t *signal = + pecalloc(1, extra_size != 0 ? sizeof(async_signal_event_t) + extra_size : sizeof(async_signal_event_t), 0); + signal->event.signal = signum; signal->event.base.extra_offset = sizeof(async_signal_event_t); signal->event.base.ref_count = 1; - signal->event.base.add_callback = libuv_add_callback; - signal->event.base.del_callback = libuv_remove_callback; - signal->event.base.start = libuv_signal_start; - signal->event.base.stop = libuv_signal_stop; - signal->event.base.dispose = libuv_signal_dispose; + signal->event.base.add_callback = libuv_add_callback; + signal->event.base.del_callback = libuv_remove_callback; + signal->event.base.start = libuv_signal_start; + signal->event.base.stop = libuv_signal_stop; + signal->event.base.dispose = libuv_signal_dispose; - return &signal->event; + return &signal->event; } + /* }}} */ ///////////////////////////////////////////////////////////////////////////////// @@ -553,6 +571,7 @@ static void libuv_signal_close_cb(uv_handle_t *handle) { pefree(handle, 0); } + /* }}} */ /* {{{ libuv_global_signal_callback */ @@ -568,10 +587,11 @@ static void libuv_global_signal_callback(uv_signal_t *handle, int signum) IF_EXCEPTION_STOP_REACTOR; } + /* }}} */ /* {{{ libuv_get_or_create_signal_handler */ -static uv_signal_t* libuv_get_or_create_signal_handler(int signum) +static uv_signal_t *libuv_get_or_create_signal_handler(int signum) { if (ASYNC_G(signal_handlers) == NULL) { ASYNC_G(signal_handlers) = zend_new_array(0); @@ -595,13 +615,14 @@ static uv_signal_t* libuv_get_or_create_signal_handler(int signum) error = uv_signal_start(handler, libuv_global_signal_callback, signum); if (error < 0) { async_throw_error("Failed to start signal handle: %s", uv_strerror(error)); - uv_close((uv_handle_t*)handler, libuv_signal_close_cb); + uv_close((uv_handle_t *) handler, libuv_signal_close_cb); return NULL; } zend_hash_index_add_ptr(ASYNC_G(signal_handlers), signum, handler); return handler; } + /* }}} */ /* {{{ libuv_add_signal_event */ @@ -626,8 +647,9 @@ static void libuv_add_signal_event(int signum, zend_async_event_t *event) } // Add event to the list (use pointer address as key) - zend_hash_index_add_ptr(events_list, (zend_ulong)event, event); + zend_hash_index_add_ptr(events_list, (zend_ulong) event, event); } + /* }}} */ /* {{{ libuv_remove_signal_event */ @@ -642,7 +664,7 @@ static void libuv_remove_signal_event(int signum, zend_async_event_t *event) return; } - zend_hash_index_del(events_list, (zend_ulong)event); + zend_hash_index_del(events_list, (zend_ulong) event); // If no more events for this signal, remove the handler (but check for process events if SIGCHLD) if (zend_hash_num_elements(events_list) == 0) { @@ -659,7 +681,7 @@ static void libuv_remove_signal_event(int signum, zend_async_event_t *event) uv_signal_t *handler = zend_hash_index_find_ptr(ASYNC_G(signal_handlers), signum); if (handler != NULL) { uv_signal_stop(handler); - uv_close((uv_handle_t*)handler, libuv_signal_close_cb); + uv_close((uv_handle_t *) handler, libuv_signal_close_cb); zend_hash_index_del(ASYNC_G(signal_handlers), signum); } } @@ -669,6 +691,7 @@ static void libuv_remove_signal_event(int signum, zend_async_event_t *event) zend_hash_index_del(ASYNC_G(signal_events), signum); } } + /* }}} */ /* {{{ libuv_handle_process_events */ @@ -691,9 +714,11 @@ static void libuv_handle_process_events(void) uint32_t i = 0; zend_async_event_t *event; - ZEND_HASH_FOREACH_PTR(ASYNC_G(process_events), event) { + ZEND_HASH_FOREACH_PTR(ASYNC_G(process_events), event) + { events_copy[i++] = event; - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); // Process events from the copy for (i = 0; i < num_events; i++) { @@ -701,13 +726,13 @@ static void libuv_handle_process_events(void) // Verify event is still in the HashTable (might have been removed) if (ASYNC_G(process_events) == NULL || - zend_hash_index_find_ptr(ASYNC_G(process_events), (zend_ulong)event) == NULL) { + zend_hash_index_find_ptr(ASYNC_G(process_events), (zend_ulong) event) == NULL) { continue; } #ifndef PHP_WIN32 - async_process_event_t *process = (async_process_event_t *)event; - pid_t pid = (pid_t)process->event.process; + async_process_event_t *process = (async_process_event_t *) event; + pid_t pid = (pid_t) process->event.process; int status; pid_t result = waitpid(pid, &status, WNOHANG); @@ -729,6 +754,7 @@ static void libuv_handle_process_events(void) pefree(events_copy, 0); } + /* }}} */ /* {{{ libuv_handle_signal_events */ @@ -744,10 +770,13 @@ static void libuv_handle_signal_events(int signum) } zend_async_event_t *event; - ZEND_HASH_FOREACH_PTR(events_list, event) { + ZEND_HASH_FOREACH_PTR(events_list, event) + { ZEND_ASYNC_CALLBACKS_NOTIFY(event, NULL, NULL); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } + /* }}} */ /* {{{ libuv_add_process_event */ @@ -765,8 +794,9 @@ static void libuv_add_process_event(zend_async_event_t *event) } // Add event to the process events list (use pointer address as key) - zend_hash_index_add_ptr(ASYNC_G(process_events), (zend_ulong)event, event); + zend_hash_index_add_ptr(ASYNC_G(process_events), (zend_ulong) event, event); } + /* }}} */ /* {{{ libuv_remove_process_event */ @@ -776,7 +806,7 @@ static void libuv_remove_process_event(zend_async_event_t *event) return; } - zend_hash_index_del(ASYNC_G(process_events), (zend_ulong)event); + zend_hash_index_del(ASYNC_G(process_events), (zend_ulong) event); // Only remove SIGCHLD handler if no more process events AND no regular signal events for SIGCHLD if (zend_hash_num_elements(ASYNC_G(process_events)) == 0) { @@ -795,7 +825,7 @@ static void libuv_remove_process_event(zend_async_event_t *event) uv_signal_t *handler = zend_hash_index_find_ptr(ASYNC_G(signal_handlers), SIGCHLD); if (handler != NULL) { uv_signal_stop(handler); - uv_close((uv_handle_t*)handler, libuv_signal_close_cb); + uv_close((uv_handle_t *) handler, libuv_signal_close_cb); zend_hash_index_del(ASYNC_G(signal_handlers), SIGCHLD); } } @@ -805,6 +835,7 @@ static void libuv_remove_process_event(zend_async_event_t *event) ASYNC_G(process_events) = NULL; } } + /* }}} */ ///////////////////////////////////////////////////////////////////////////////// @@ -816,17 +847,20 @@ static void libuv_cleanup_signal_handlers(void) { if (ASYNC_G(signal_handlers) != NULL) { uv_signal_t *handler; - ZEND_HASH_FOREACH_PTR(ASYNC_G(signal_handlers), handler) { + ZEND_HASH_FOREACH_PTR(ASYNC_G(signal_handlers), handler) + { if (handler != NULL) { uv_signal_stop(handler); - uv_close((uv_handle_t*)handler, libuv_signal_close_cb); + uv_close((uv_handle_t *) handler, libuv_signal_close_cb); } - } ZEND_HASH_FOREACH_END(); - + } + ZEND_HASH_FOREACH_END(); + zend_array_destroy(ASYNC_G(signal_handlers)); ASYNC_G(signal_handlers) = NULL; } } + /* }}} */ /* {{{ libuv_cleanup_signal_events */ @@ -834,17 +868,20 @@ static void libuv_cleanup_signal_events(void) { if (ASYNC_G(signal_events) != NULL) { HashTable *events_list; - ZEND_HASH_FOREACH_PTR(ASYNC_G(signal_events), events_list) { + ZEND_HASH_FOREACH_PTR(ASYNC_G(signal_events), events_list) + { if (events_list != NULL) { zend_hash_destroy(events_list); pefree(events_list, 0); } - } ZEND_HASH_FOREACH_END(); - + } + ZEND_HASH_FOREACH_END(); + zend_array_destroy(ASYNC_G(signal_events)); ASYNC_G(signal_events) = NULL; } } + /* }}} */ /* {{{ libuv_cleanup_process_events */ @@ -855,6 +892,7 @@ static void libuv_cleanup_process_events(void) ASYNC_G(process_events) = NULL; } } + /* }}} */ ///////////////////////////////////////////////////////////////////////////////// @@ -862,7 +900,7 @@ static void libuv_cleanup_process_events(void) ///////////////////////////////////////////////////////////////////////////////// #ifdef PHP_WIN32 -static void process_watcher_thread(void * args) +static void process_watcher_thread(void *args) { LIBUV_REACTOR_VAR_FROM(args); @@ -871,13 +909,12 @@ static void process_watcher_thread(void * args) while (reactor->isRunning && reactor->ioCompletionPort != NULL) { DWORD lpNumberOfBytesTransferred; - //OVERLAPPED overlapped = {0}; + // OVERLAPPED overlapped = {0}; LPOVERLAPPED lpOverlapped = NULL; - if (false == GetQueuedCompletionStatus( - reactor->ioCompletionPort, &lpNumberOfBytesTransferred, &completionKey, &lpOverlapped, INFINITE) - ) - { + if (false == + GetQueuedCompletionStatus( + reactor->ioCompletionPort, &lpNumberOfBytesTransferred, &completionKey, &lpOverlapped, INFINITE)) { break; } @@ -886,8 +923,8 @@ static void process_watcher_thread(void * args) } if (reactor->isRunning == false) { - break; - } + break; + } switch (lpNumberOfBytesTransferred) { case JOB_OBJECT_MSG_EXIT_PROCESS: @@ -900,9 +937,9 @@ static void process_watcher_thread(void * args) continue; } -handleExitCode: + handleExitCode: - async_process_event_t * process_event = (async_process_event_t *) completionKey; + async_process_event_t *process_event = (async_process_event_t *) completionKey; if (UNEXPECTED(circular_buffer_is_full(reactor->pid_queue))) { @@ -918,7 +955,7 @@ static void process_watcher_thread(void * args) if (false == reactor->isRunning) { break; } - } + } circular_buffer_push(reactor->pid_queue, &process_event, false); uv_async_send(reactor->uvloop_wakeup); @@ -936,7 +973,7 @@ static void on_process_event(uv_async_t *handle) return; } - async_process_event_t * process_event; + async_process_event_t *process_event; while (reactor->pid_queue && circular_buffer_is_not_empty(reactor->pid_queue)) { circular_buffer_pop(reactor->pid_queue, &process_event); @@ -952,7 +989,7 @@ static void on_process_event(uv_async_t *handle) if (reactor->countWaitingDescriptors == 0) { libuv_stop_process_watcher(); } - } + } ZEND_ASYNC_CALLBACKS_NOTIFY(&process_event->event.base, NULL, NULL); process_event->event.base.stop(&process_event->event.base); @@ -975,12 +1012,10 @@ static void libuv_start_process_watcher(void) LIBUV_REACTOR_VAR; // Create IoCompletionPort - reactor->ioCompletionPort = CreateIoCompletionPort( - INVALID_HANDLE_VALUE, NULL, 0, 1 - ); + reactor->ioCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (reactor->ioCompletionPort == NULL) { - char * error_msg = php_win32_error_to_msg((HRESULT) GetLastError()); + char *error_msg = php_win32_error_to_msg((HRESULT) GetLastError()); php_error_docref(NULL, E_CORE_ERROR, "Failed to create IO completion port: %s", error_msg); php_win32_error_msg_free(error_msg); return; @@ -1017,7 +1052,7 @@ static void libuv_start_process_watcher(void) static void libuv_wakeup_close_cb(uv_handle_t *handle) { - pefree(handle, 0); + pefree(handle, 0); } /* {{{ libuv_stop_process_watcher */ @@ -1035,7 +1070,7 @@ static void libuv_stop_process_watcher(void) reactor->uvloop_wakeup = NULL; // send wake up event to stop the thread - PostQueuedCompletionStatus(reactor->ioCompletionPort, 0, (ULONG_PTR)0, NULL); + PostQueuedCompletionStatus(reactor->ioCompletionPort, 0, (ULONG_PTR) 0, NULL); uv_thread_detach(WATCHER); pefree(WATCHER, 0); WATCHER = NULL; @@ -1049,6 +1084,7 @@ static void libuv_stop_process_watcher(void) efree(reactor->pid_queue); reactor->pid_queue = NULL; } + /* }}} */ /* {{{ libuv_process_event_start */ @@ -1056,7 +1092,7 @@ static void libuv_process_event_start(zend_async_event_t *event) { EVENT_START_PROLOGUE(event); - async_process_event_t *process = (async_process_event_t *)(event); + async_process_event_t *process = (async_process_event_t *) (event); if (process->hJob != NULL) { return; @@ -1082,7 +1118,7 @@ static void libuv_process_event_start(zend_async_event_t *event) return; } - char * error_msg = php_win32_error_to_msg((HRESULT) error); + char *error_msg = php_win32_error_to_msg((HRESULT) error); async_throw_error("Failed to assign process to job object: %s", error_msg); php_win32_error_msg_free(error_msg); return; @@ -1092,17 +1128,11 @@ static void libuv_process_event_start(zend_async_event_t *event) libuv_start_process_watcher(); } - JOBOBJECT_ASSOCIATE_COMPLETION_PORT info = {0}; - info.CompletionKey = (PVOID)process; + JOBOBJECT_ASSOCIATE_COMPLETION_PORT info = { 0 }; + info.CompletionKey = (PVOID) process; info.CompletionPort = LIBUV_REACTOR->ioCompletionPort; - if (!SetInformationJobObject( - process->hJob, - JobObjectAssociateCompletionPortInformation, - &info, sizeof(info) - ) - ) - { + if (!SetInformationJobObject(process->hJob, JobObjectAssociateCompletionPortInformation, &info, sizeof(info))) { CloseHandle(process->hJob); process->hJob = NULL; @@ -1111,7 +1141,7 @@ static void libuv_process_event_start(zend_async_event_t *event) return; } - char * error_msg = php_win32_error_to_msg((HRESULT) error); + char *error_msg = php_win32_error_to_msg((HRESULT) error); async_throw_error("Failed to associate IO completion port with Job for process: %s", error_msg); php_win32_error_msg_free(error_msg); return; @@ -1121,6 +1151,7 @@ static void libuv_process_event_start(zend_async_event_t *event) ZEND_ASYNC_INCREASE_EVENT_COUNT; LIBUV_REACTOR->countWaitingDescriptors++; } + /* }}} */ /* {{{ libuv_process_event_stop */ @@ -1139,6 +1170,7 @@ static void libuv_process_event_stop(zend_async_event_t *event) ZEND_ASYNC_DECREASE_EVENT_COUNT; } + /* }}} */ #else @@ -1146,17 +1178,17 @@ static void libuv_process_event_stop(zend_async_event_t *event) static void libuv_process_event_start(zend_async_event_t *event) { EVENT_START_PROLOGUE(event); - - async_process_event_t *process = (async_process_event_t *)(event); - pid_t pid = (pid_t)process->event.process; - + + async_process_event_t *process = (async_process_event_t *) (event); + pid_t pid = (pid_t) process->event.process; + // Add handler first to guarantee we catch SIGCHLD libuv_add_process_event(event); - + // Check if process already terminated (zombie state) int exit_status; pid_t result = waitpid(pid, &exit_status, WNOHANG); - + if (result == pid) { // Process already terminated, got exit code if (WIFEXITED(exit_status)) { @@ -1166,7 +1198,7 @@ static void libuv_process_event_start(zend_async_event_t *event) } else { process->event.exit_code = -1; } - + event->stop(event); ZEND_ASYNC_CALLBACKS_NOTIFY(&process->event.base, NULL, NULL); } else if (result == 0) { @@ -1176,10 +1208,9 @@ static void libuv_process_event_start(zend_async_event_t *event) } else { // Error: process doesn't exist or already reaped libuv_remove_process_event(event); - zend_object * exception = async_new_exception( - async_ce_async_exception, "Failed to monitor process %d: %s", (int)pid, strerror(errno) - ); - ZEND_ASYNC_CALLBACKS_NOTIFY(&process->event.base,NULL, exception); + zend_object *exception = async_new_exception( + async_ce_async_exception, "Failed to monitor process %d: %s", (int) pid, strerror(errno)); + ZEND_ASYNC_CALLBACKS_NOTIFY(&process->event.base, NULL, exception); OBJ_RELEASE(exception); } } @@ -1188,10 +1219,10 @@ static void libuv_process_event_stop(zend_async_event_t *event) { EVENT_STOP_PROLOGUE(event); ZEND_ASYNC_EVENT_SET_CLOSED(event); - + // Remove from process monitoring libuv_remove_process_event(event); - + event->loop_ref_count = 0; ZEND_ASYNC_DECREASE_EVENT_COUNT; } @@ -1214,7 +1245,7 @@ static void libuv_process_event_dispose(zend_async_event_t *event) #ifdef PHP_WIN32 - async_process_event_t *process = (async_process_event_t *)(event); + async_process_event_t *process = (async_process_event_t *) (event); if (process->event.process != NULL) { process->event.process = NULL; @@ -1228,16 +1259,16 @@ static void libuv_process_event_dispose(zend_async_event_t *event) pefree(event, 0); } + /* }}} */ /* {{{ libuv_new_process_event */ -zend_async_process_event_t * libuv_new_process_event(zend_process_t process_handle, size_t extra_size) +zend_async_process_event_t *libuv_new_process_event(zend_process_t process_handle, size_t extra_size) { START_REACTOR_OR_RETURN_NULL; async_process_event_t *process_event = pecalloc( - 1, extra_size != 0 ? sizeof(async_process_event_t) + extra_size : sizeof(async_process_event_t), 0 - ); + 1, extra_size != 0 ? sizeof(async_process_event_t) + extra_size : sizeof(async_process_event_t), 0); process_event->event.process = process_handle; process_event->event.base.extra_offset = sizeof(async_process_event_t); @@ -1251,6 +1282,7 @@ zend_async_process_event_t * libuv_new_process_event(zend_process_t process_hand return &process_event->event; } + /* }}} */ ///////////////////////////////////////////////////////////////////////////////// @@ -1258,14 +1290,15 @@ zend_async_process_event_t * libuv_new_process_event(zend_process_t process_hand ///////////////////////////////////////////////////////////////////////////////// /* {{{ libuv_new_thread_event */ -zend_async_thread_event_t * libuv_new_thread_event(zend_async_thread_entry_t entry, void *arg, size_t extra_size) +zend_async_thread_event_t *libuv_new_thread_event(zend_async_thread_entry_t entry, void *arg, size_t extra_size) { - //TODO: libuv_new_thread_event - // We need to design a mechanism for creating a Thread and running a function - // in another thread in such a way that it can be awaited like an event. + // TODO: libuv_new_thread_event + // We need to design a mechanism for creating a Thread and running a function + // in another thread in such a way that it can be awaited like an event. // return NULL; } + /* }}} */ ///////////////////////////////////////////////////////////////////////////////// @@ -1275,7 +1308,7 @@ zend_async_thread_event_t * libuv_new_thread_event(zend_async_thread_entry_t ent /* {{{ on_filesystem_event */ static void on_filesystem_event(uv_fs_event_t *handle, const char *filename, int events, int status) { - async_filesystem_event_t *fs_event = handle->data; + async_filesystem_event_t *fs_event = handle->data; // Reset previous triggered filename if (fs_event->event.triggered_filename) { @@ -1285,65 +1318,63 @@ static void on_filesystem_event(uv_fs_event_t *handle, const char *filename, int fs_event->event.triggered_events = 0; - if (status < 0) { - zend_object *exception = async_new_exception( - async_ce_input_output_exception, "Filesystem monitoring error: %s", uv_strerror(status) - ); - ZEND_ASYNC_CALLBACKS_NOTIFY(&fs_event->event.base, NULL, exception); - zend_object_release(exception); - return; - } + if (status < 0) { + zend_object *exception = async_new_exception( + async_ce_input_output_exception, "Filesystem monitoring error: %s", uv_strerror(status)); + ZEND_ASYNC_CALLBACKS_NOTIFY(&fs_event->event.base, NULL, exception); + zend_object_release(exception); + return; + } - fs_event->event.triggered_events = events; - fs_event->event.triggered_filename = filename ? zend_string_init(filename, strlen(filename), 0) : NULL; + fs_event->event.triggered_events = events; + fs_event->event.triggered_filename = filename ? zend_string_init(filename, strlen(filename), 0) : NULL; - ZEND_ASYNC_CALLBACKS_NOTIFY(&fs_event->event.base, NULL, NULL); + ZEND_ASYNC_CALLBACKS_NOTIFY(&fs_event->event.base, NULL, NULL); - IF_EXCEPTION_STOP_REACTOR; + IF_EXCEPTION_STOP_REACTOR; } + /* }}} */ /* {{{ libuv_filesystem_start */ static void libuv_filesystem_start(zend_async_event_t *event) { - EVENT_START_PROLOGUE(event); + EVENT_START_PROLOGUE(event); - async_filesystem_event_t *fs_event = (async_filesystem_event_t *)(event); + async_filesystem_event_t *fs_event = (async_filesystem_event_t *) (event); - const int error = uv_fs_event_start( - &fs_event->uv_handle, - on_filesystem_event, - ZSTR_VAL(fs_event->event.path), - fs_event->event.flags - ); + const int error = uv_fs_event_start( + &fs_event->uv_handle, on_filesystem_event, ZSTR_VAL(fs_event->event.path), fs_event->event.flags); - if (error < 0) { - async_throw_error("Failed to start filesystem handle: %s", uv_strerror(error)); - return; - } + if (error < 0) { + async_throw_error("Failed to start filesystem handle: %s", uv_strerror(error)); + return; + } - event->loop_ref_count++; - ZEND_ASYNC_INCREASE_EVENT_COUNT; + event->loop_ref_count++; + ZEND_ASYNC_INCREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_filesystem_stop */ static void libuv_filesystem_stop(zend_async_event_t *event) { - EVENT_STOP_PROLOGUE(event); + EVENT_STOP_PROLOGUE(event); - async_filesystem_event_t *fs_event = (async_filesystem_event_t *)(event); + async_filesystem_event_t *fs_event = (async_filesystem_event_t *) (event); - const int error = uv_fs_event_stop(&fs_event->uv_handle); + const int error = uv_fs_event_stop(&fs_event->uv_handle); - event->loop_ref_count = 0; - ZEND_ASYNC_DECREASE_EVENT_COUNT; + event->loop_ref_count = 0; + ZEND_ASYNC_DECREASE_EVENT_COUNT; - if (error < 0) { - async_throw_error("Failed to stop filesystem handle: %s", uv_strerror(error)); - return; - } + if (error < 0) { + async_throw_error("Failed to stop filesystem handle: %s", uv_strerror(error)); + return; + } } + /* }}} */ /* {{{ libuv_filesystem_dispose */ @@ -1354,60 +1385,62 @@ static void libuv_filesystem_dispose(zend_async_event_t *event) return; } - if (event->loop_ref_count > 0) { - event->loop_ref_count = 1; - event->stop(event); - } + if (event->loop_ref_count > 0) { + event->loop_ref_count = 1; + event->stop(event); + } - zend_async_callbacks_free(event); + zend_async_callbacks_free(event); - async_filesystem_event_t *fs_event = (async_filesystem_event_t *)(event); + async_filesystem_event_t *fs_event = (async_filesystem_event_t *) (event); - if (fs_event->event.path) { - zend_string_release(fs_event->event.path); - fs_event->event.path = NULL; - } + if (fs_event->event.path) { + zend_string_release(fs_event->event.path); + fs_event->event.path = NULL; + } if (fs_event->event.triggered_filename) { zend_string_release(fs_event->event.triggered_filename); fs_event->event.triggered_filename = NULL; } - uv_close((uv_handle_t *)&fs_event->uv_handle, libuv_close_handle_cb); + uv_close((uv_handle_t *) &fs_event->uv_handle, libuv_close_handle_cb); } + /* }}} */ /* {{{ libuv_new_filesystem_event */ -zend_async_filesystem_event_t* libuv_new_filesystem_event(zend_string * path, const unsigned int flags, size_t extra_size) +zend_async_filesystem_event_t * +libuv_new_filesystem_event(zend_string *path, const unsigned int flags, size_t extra_size) { START_REACTOR_OR_RETURN_NULL; - async_filesystem_event_t *fs_event = pecalloc( - 1, extra_size != 0 ? sizeof(async_filesystem_event_t) + extra_size : sizeof(async_filesystem_event_t), 0 - ); + async_filesystem_event_t *fs_event = pecalloc( + 1, extra_size != 0 ? sizeof(async_filesystem_event_t) + extra_size : sizeof(async_filesystem_event_t), 0); - const int error = uv_fs_event_init(UVLOOP, &fs_event->uv_handle); + const int error = uv_fs_event_init(UVLOOP, &fs_event->uv_handle); - if (error < 0) { - async_throw_error("Failed to initialize filesystem handle: %s", uv_strerror(error)); - pefree(fs_event, 0); - return NULL; - } + if (error < 0) { + async_throw_error("Failed to initialize filesystem handle: %s", uv_strerror(error)); + pefree(fs_event, 0); + return NULL; + } - fs_event->uv_handle.data = fs_event; - fs_event->event.path = zend_string_copy(path); - fs_event->event.flags = flags; + fs_event->uv_handle.data = fs_event; + fs_event->event.path = zend_string_copy(path); + fs_event->event.flags = flags; fs_event->event.base.extra_offset = sizeof(async_filesystem_event_t); fs_event->event.base.ref_count = 1; - fs_event->event.base.add_callback = libuv_add_callback; - fs_event->event.base.del_callback = libuv_remove_callback; - fs_event->event.base.start = libuv_filesystem_start; - fs_event->event.base.stop = libuv_filesystem_stop; - fs_event->event.base.dispose = libuv_filesystem_dispose; + fs_event->event.base.add_callback = libuv_add_callback; + fs_event->event.base.del_callback = libuv_remove_callback; + fs_event->event.base.start = libuv_filesystem_start; + fs_event->event.base.stop = libuv_filesystem_stop; + fs_event->event.base.dispose = libuv_filesystem_dispose; - return &fs_event->event; + return &fs_event->event; } + /* }}} */ /////////////////////////////////////////////////////////////////////////////////// @@ -1417,8 +1450,8 @@ zend_async_filesystem_event_t* libuv_new_filesystem_event(zend_string * path, co /* {{{ on_nameinfo_event */ static void on_nameinfo_event(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) { - async_dns_nameinfo_t *name_info = req->data; - zend_object *exception = NULL; + async_dns_nameinfo_t *name_info = req->data; + zend_object *exception = NULL; name_info->event.hostname = NULL; name_info->event.service = NULL; @@ -1427,19 +1460,17 @@ static void on_nameinfo_event(uv_getnameinfo_t *req, int status, const char *hos // After that, the event is automatically closed. close_event(&name_info->event.base); - if (UNEXPECTED(status < 0)) { - exception = async_new_exception( - async_ce_dns_exception, "DNS error: %s", uv_strerror(status) - ); + if (UNEXPECTED(status < 0)) { + exception = async_new_exception(async_ce_dns_exception, "DNS error: %s", uv_strerror(status)); - ZEND_ASYNC_CALLBACKS_NOTIFY(&name_info->event.base, NULL, exception); + ZEND_ASYNC_CALLBACKS_NOTIFY(&name_info->event.base, NULL, exception); - if (exception != NULL) { - zend_object_release(exception); - } + if (exception != NULL) { + zend_object_release(exception); + } - return; - } + return; + } // We must copy these strings as zend_string into Zend memory space because they do not belong to us. if (hostname != NULL) { @@ -1450,10 +1481,11 @@ static void on_nameinfo_event(uv_getnameinfo_t *req, int status, const char *hos name_info->event.service = zend_string_init(service, strlen(service), 0); } - ZEND_ASYNC_CALLBACKS_NOTIFY(&name_info->event.base, NULL, NULL); + ZEND_ASYNC_CALLBACKS_NOTIFY(&name_info->event.base, NULL, NULL); - IF_EXCEPTION_STOP_REACTOR; + IF_EXCEPTION_STOP_REACTOR; } + /* }}} */ /* {{{ libuv_dns_nameinfo_start */ @@ -1464,6 +1496,7 @@ static void libuv_dns_nameinfo_start(zend_async_event_t *event) event->loop_ref_count++; ZEND_ASYNC_INCREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_dns_nameinfo_stop */ @@ -1474,6 +1507,7 @@ static void libuv_dns_nameinfo_stop(zend_async_event_t *event) event->loop_ref_count = 0; ZEND_ASYNC_DECREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_dns_nameinfo_dispose */ @@ -1491,7 +1525,7 @@ static void libuv_dns_nameinfo_dispose(zend_async_event_t *event) zend_async_callbacks_free(event); - zend_async_dns_nameinfo_t *name_info = (zend_async_dns_nameinfo_t *)(event); + zend_async_dns_nameinfo_t *name_info = (zend_async_dns_nameinfo_t *) (event); if (name_info->hostname != NULL) { zend_string_release(name_info->hostname); @@ -1505,25 +1539,22 @@ static void libuv_dns_nameinfo_dispose(zend_async_event_t *event) pefree(event, 0); } + /* }}} */ /* {{{ libuv_getnameinfo */ -static zend_async_dns_nameinfo_t * libuv_getnameinfo(const struct sockaddr *addr, int flags, size_t extra_size) +static zend_async_dns_nameinfo_t *libuv_getnameinfo(const struct sockaddr *addr, int flags, size_t extra_size) { START_REACTOR_OR_RETURN_NULL; - async_dns_nameinfo_t *name_info = pecalloc( - 1, extra_size != 0 ? sizeof(async_dns_nameinfo_t) + extra_size : sizeof(async_dns_nameinfo_t), 0 - ); + async_dns_nameinfo_t *name_info = + pecalloc(1, extra_size != 0 ? sizeof(async_dns_nameinfo_t) + extra_size : sizeof(async_dns_nameinfo_t), 0); - const int error = uv_getnameinfo( - UVLOOP, &name_info->uv_handle, on_nameinfo_event, addr, flags - ); + const int error = uv_getnameinfo(UVLOOP, &name_info->uv_handle, on_nameinfo_event, addr, flags); if (error < 0) { async_rethrow_exception(async_new_exception( - async_ce_dns_exception, "Failed to initialize getnameinfo handle: %s", uv_strerror(error) - )); + async_ce_dns_exception, "Failed to initialize getnameinfo handle: %s", uv_strerror(error))); pefree(name_info, 0); return NULL; } @@ -1540,6 +1571,7 @@ static zend_async_dns_nameinfo_t * libuv_getnameinfo(const struct sockaddr *addr return &name_info->event; } + /* }}} */ /* {{{ on_addrinfo_event */ @@ -1553,9 +1585,7 @@ static void on_addrinfo_event(uv_getaddrinfo_t *req, int status, struct addrinfo close_event(&addr_info->event.base); if (status < 0) { - exception = async_new_exception( - async_ce_dns_exception, "DNS error: %s", uv_strerror(status) - ); + exception = async_new_exception(async_ce_dns_exception, "DNS error: %s", uv_strerror(status)); } addr_info->event.result = res; @@ -1568,6 +1598,7 @@ static void on_addrinfo_event(uv_getaddrinfo_t *req, int status, struct addrinfo IF_EXCEPTION_STOP_REACTOR; } + /* }}} */ /* {{{ libuv_dns_getaddrinfo_start */ @@ -1578,6 +1609,7 @@ static void libuv_dns_getaddrinfo_start(zend_async_event_t *event) event->loop_ref_count++; ZEND_ASYNC_INCREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_dns_getaddrinfo_stop */ @@ -1588,6 +1620,7 @@ static void libuv_dns_getaddrinfo_stop(zend_async_event_t *event) event->loop_ref_count = 0; ZEND_ASYNC_DECREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_dns_getaddrinfo_dispose */ @@ -1605,32 +1638,28 @@ static void libuv_dns_getaddrinfo_dispose(zend_async_event_t *event) zend_async_callbacks_free(event); - async_dns_addrinfo_t *addr_info = (async_dns_addrinfo_t *)(event); + async_dns_addrinfo_t *addr_info = (async_dns_addrinfo_t *) (event); // Note: The addrinfo structure is allocated by libuv and should not be freed manually! - libuv_close_handle_cb((uv_handle_t *)&addr_info->uv_handle); + libuv_close_handle_cb((uv_handle_t *) &addr_info->uv_handle); } + /* }}} */ /* {{{ libuv_getaddrinfo */ -static zend_async_dns_addrinfo_t* libuv_getaddrinfo( - const char *node, const char *service, const struct addrinfo *hints, size_t extra_size -) +static zend_async_dns_addrinfo_t * +libuv_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, size_t extra_size) { START_REACTOR_OR_RETURN_NULL; - async_dns_addrinfo_t *addr_info = pecalloc( - 1, extra_size != 0 ? sizeof(async_dns_addrinfo_t) + extra_size : sizeof(async_dns_addrinfo_t), 0 - ); + async_dns_addrinfo_t *addr_info = + pecalloc(1, extra_size != 0 ? sizeof(async_dns_addrinfo_t) + extra_size : sizeof(async_dns_addrinfo_t), 0); - const int error = uv_getaddrinfo( - UVLOOP, &addr_info->uv_handle, on_addrinfo_event, node, service, hints - ); + const int error = uv_getaddrinfo(UVLOOP, &addr_info->uv_handle, on_addrinfo_event, node, service, hints); if (error < 0) { async_rethrow_exception(async_new_exception( - async_ce_dns_exception, "Failed to initialize getaddrinfo handle: %s", uv_strerror(error) - )); + async_ce_dns_exception, "Failed to initialize getaddrinfo handle: %s", uv_strerror(error))); pefree(addr_info, 0); return NULL; @@ -1648,6 +1677,7 @@ static zend_async_dns_addrinfo_t* libuv_getaddrinfo( return &addr_info->event; } + /* }}} */ /* {{{ libuv_freeaddrinfo */ @@ -1657,6 +1687,7 @@ static void libuv_freeaddrinfo(struct addrinfo *ai) uv_freeaddrinfo(ai); } } + /* }}} */ //////////////////////////////////////////////////////////////////////////////////// @@ -1664,7 +1695,7 @@ static void libuv_freeaddrinfo(struct addrinfo *ai) /////////////////////////////////////////////////////////////////////////////////// /* {{{ exec_on_exit */ -static void exec_on_exit(uv_process_t* process, const int64_t exit_status, int term_signal) +static void exec_on_exit(uv_process_t *process, const int64_t exit_status, int term_signal) { async_exec_event_t *exec = process->data; exec->event.exit_code = exit_status; @@ -1673,7 +1704,7 @@ static void exec_on_exit(uv_process_t* process, const int64_t exit_status, int t process->data = exec->process; exec->process = NULL; - uv_close((uv_handle_t*)process, libuv_close_handle_cb); + uv_close((uv_handle_t *) process, libuv_close_handle_cb); if (exec->event.terminated != true) { exec->event.terminated = true; @@ -1681,15 +1712,15 @@ static void exec_on_exit(uv_process_t* process, const int64_t exit_status, int t ZEND_ASYNC_CALLBACKS_NOTIFY(&exec->event.base, NULL, NULL); } } + //* }}} */ -static void exec_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) +static void exec_alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - async_exec_event_t * event = handle->data; - zend_async_exec_event_t * exec = &event->event; + async_exec_event_t *event = handle->data; + zend_async_exec_event_t *exec = &event->event; - if (exec->output_len == 0) - { + if (exec->output_len == 0) { exec->output_len = suggested_size; exec->output_buffer = emalloc(suggested_size); } else if (exec->output_len < suggested_size) { @@ -1703,8 +1734,8 @@ static void exec_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* static void exec_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { - async_exec_event_t * event = stream->data; - zend_async_exec_event_t * exec = &event->event; + async_exec_event_t *event = stream->data; + zend_async_exec_event_t *exec = &event->event; if (nread > 0) { switch (exec->exec_mode) { @@ -1734,7 +1765,7 @@ static void exec_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf if (Z_TYPE_P(exec->result_buffer) != IS_STRING) { ZVAL_NEW_STR(exec->result_buffer, zend_string_init(buf->base, nread, 0)); } else { - zend_string * string = Z_STR_P(exec->result_buffer); + zend_string *string = Z_STR_P(exec->result_buffer); string = zend_string_extend(string, ZSTR_LEN(string) + nread, 0); memcpy(ZSTR_VAL(string) + ZSTR_LEN(string) - nread, buf->base, nread); ZVAL_STR(exec->result_buffer, string); @@ -1762,7 +1793,7 @@ static void exec_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf uv_read_stop(stream); // For libuv_close_handle_cb to work correctly. stream->data = stream; - uv_close((uv_handle_t *)stream, libuv_close_handle_cb); + uv_close((uv_handle_t *) stream, libuv_close_handle_cb); if (exec->terminated != true) { exec->terminated = true; @@ -1772,7 +1803,7 @@ static void exec_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf } } -static void exec_std_err_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) +static void exec_std_err_alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { buf->base = emalloc(suggested_size); buf->len = suggested_size; @@ -1780,8 +1811,8 @@ static void exec_std_err_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv static void exec_std_err_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { - async_exec_event_t * event = stream->data; - zend_async_exec_event_t * exec = &event->event; + async_exec_event_t *event = stream->data; + zend_async_exec_event_t *exec = &event->event; if (nread > 0) { @@ -1789,7 +1820,7 @@ static void exec_std_err_read_cb(uv_stream_t *stream, ssize_t nread, const uv_bu if (Z_TYPE_P(exec->std_error) != IS_STRING) { ZVAL_NEW_STR(exec->std_error, zend_string_init(buf->base, nread, 0)); } else { - zend_string * string = Z_STR_P(exec->std_error); + zend_string *string = Z_STR_P(exec->std_error); string = zend_string_extend(string, ZSTR_LEN(string) + nread, 0); memcpy(ZSTR_VAL(string) + ZSTR_LEN(string) - nread, buf->base, nread); ZVAL_STR(exec->std_error, string); @@ -1803,11 +1834,12 @@ static void exec_std_err_read_cb(uv_stream_t *stream, ssize_t nread, const uv_bu uv_read_stop(stream); stream->data = stream; - uv_close((uv_handle_t *)stream, libuv_close_handle_cb); + uv_close((uv_handle_t *) stream, libuv_close_handle_cb); } efree(buf->base); } + /* }}} */ /* {{{ libuv_exec_start */ @@ -1815,7 +1847,7 @@ static void libuv_exec_start(zend_async_event_t *event) { EVENT_START_PROLOGUE(event); - async_exec_event_t *exec = (async_exec_event_t *)(event); + async_exec_event_t *exec = (async_exec_event_t *) (event); if (exec->process == NULL) { return; @@ -1824,6 +1856,7 @@ static void libuv_exec_start(zend_async_event_t *event) event->loop_ref_count++; ZEND_ASYNC_INCREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_exec_stop */ @@ -1831,7 +1864,7 @@ static void libuv_exec_stop(zend_async_event_t *event) { EVENT_STOP_PROLOGUE(event); - async_exec_event_t *exec = (async_exec_event_t *)(event); + async_exec_event_t *exec = (async_exec_event_t *) (event); event->loop_ref_count = 0; ZEND_ASYNC_DECREASE_EVENT_COUNT; @@ -1840,6 +1873,7 @@ static void libuv_exec_stop(zend_async_event_t *event) uv_process_kill(exec->process, ZEND_ASYNC_SIGTERM); } } + /* }}} */ /* {{{ libuv_exec_dispose */ @@ -1850,79 +1884,78 @@ static void libuv_exec_dispose(zend_async_event_t *event) return; } - if (event->loop_ref_count > 0) { - event->loop_ref_count = 1; - event->stop(event); - } + if (event->loop_ref_count > 0) { + event->loop_ref_count = 1; + event->stop(event); + } - zend_async_callbacks_free(event); + zend_async_callbacks_free(event); - async_exec_event_t *exec = (async_exec_event_t *)(event); + async_exec_event_t *exec = (async_exec_event_t *) (event); - if (exec->event.output_buffer != NULL) { - efree(exec->event.output_buffer); - exec->event.output_buffer = NULL; - exec->event.output_len = 0; - } + if (exec->event.output_buffer != NULL) { + efree(exec->event.output_buffer); + exec->event.output_buffer = NULL; + exec->event.output_len = 0; + } - if (exec->process != NULL && !uv_is_closing((uv_handle_t *)exec->process)) { - uv_process_kill(exec->process, ZEND_ASYNC_SIGTERM); - uv_handle_t * handle = (uv_handle_t *) exec->process; - exec->process = NULL; - // For libuv_close_handle_cb to work correctly. - handle->data = handle; - uv_close(handle, libuv_close_handle_cb); - } + if (exec->process != NULL && !uv_is_closing((uv_handle_t *) exec->process)) { + uv_process_kill(exec->process, ZEND_ASYNC_SIGTERM); + uv_handle_t *handle = (uv_handle_t *) exec->process; + exec->process = NULL; + // For libuv_close_handle_cb to work correctly. + handle->data = handle; + uv_close(handle, libuv_close_handle_cb); + } - if (exec->stdout_pipe != NULL && !uv_is_closing((uv_handle_t *)exec->stdout_pipe)) { - uv_read_stop((uv_stream_t *)exec->stdout_pipe); - uv_handle_t * handle = (uv_handle_t *) exec->stdout_pipe; + if (exec->stdout_pipe != NULL && !uv_is_closing((uv_handle_t *) exec->stdout_pipe)) { + uv_read_stop((uv_stream_t *) exec->stdout_pipe); + uv_handle_t *handle = (uv_handle_t *) exec->stdout_pipe; exec->stdout_pipe->data = NULL; - handle->data = handle; - uv_close(handle, libuv_close_handle_cb); - } + handle->data = handle; + uv_close(handle, libuv_close_handle_cb); + } - if (exec->stderr_pipe != NULL && !uv_is_closing((uv_handle_t *)exec->stderr_pipe)) { - uv_read_stop((uv_stream_t *)exec->stderr_pipe); - uv_handle_t * handle = (uv_handle_t *) exec->stderr_pipe; + if (exec->stderr_pipe != NULL && !uv_is_closing((uv_handle_t *) exec->stderr_pipe)) { + uv_read_stop((uv_stream_t *) exec->stderr_pipe); + uv_handle_t *handle = (uv_handle_t *) exec->stderr_pipe; exec->stderr_pipe->data = NULL; - handle->data = handle; - uv_close(handle, libuv_close_handle_cb); - } + handle->data = handle; + uv_close(handle, libuv_close_handle_cb); + } #ifdef PHP_WIN32 - if (exec->quoted_cmd != NULL) { - efree(exec->quoted_cmd); - exec->quoted_cmd = NULL; - } + if (exec->quoted_cmd != NULL) { + efree(exec->quoted_cmd); + exec->quoted_cmd = NULL; + } #endif // Free the event itself pefree(event, 0); } + /* }}} */ /* {{{ libuv_new_exec_event */ -static zend_async_exec_event_t * libuv_new_exec_event( - zend_async_exec_mode exec_mode, - const char *cmd, - zval *return_buffer, - zval *return_value, - zval *std_error, - const char *cwd, - const char *env, - size_t size -) +static zend_async_exec_event_t *libuv_new_exec_event(zend_async_exec_mode exec_mode, + const char *cmd, + zval *return_buffer, + zval *return_value, + zval *std_error, + const char *cwd, + const char *env, + size_t size) { START_REACTOR_OR_RETURN_NULL; - async_exec_event_t * exec = pecalloc(1, size != 0 ? size : sizeof(async_exec_event_t), 0); - zend_async_exec_event_t * base = &exec->event; + async_exec_event_t *exec = pecalloc(1, size != 0 ? size : sizeof(async_exec_event_t), 0); + zend_async_exec_event_t *base = &exec->event; uv_process_options_t *options = &exec->options; if (exec == NULL || EG(exception)) { - return NULL; - } + return NULL; + } base->exec_mode = exec_mode; base->cmd = (char *) cmd; @@ -1948,32 +1981,26 @@ static zend_async_exec_event_t * libuv_new_exec_event( size_t cmd_buffer_size = strlen(cmd) + 2; exec->quoted_cmd = emalloc(cmd_buffer_size); snprintf(exec->quoted_cmd, cmd_buffer_size, "\"%s\"", cmd); - options->args = (char*[]) { "cmd.exe", "/s", "/c", exec->quoted_cmd, NULL }; + options->args = (char *[]){ "cmd.exe", "/s", "/c", exec->quoted_cmd, NULL }; #else options->file = "/bin/sh"; - options->args = (char*[]) { "sh", "-c", (char *)cmd, NULL }; + options->args = (char *[]){ "sh", "-c", (char *) cmd, NULL }; #endif - options->stdio = (uv_stdio_container_t[]) { - { .flags = UV_IGNORE, .data = { .stream = NULL } }, - { - .data.stream = (uv_stream_t*) exec->stdout_pipe, - .flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE - }, - { - .data.stream = (uv_stream_t*) exec->stderr_pipe, - .flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE - } + options->stdio = (uv_stdio_container_t[]){ + { .flags = UV_IGNORE, .data = { .stream = NULL } }, + { .data.stream = (uv_stream_t *) exec->stdout_pipe, .flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE }, + { .data.stream = (uv_stream_t *) exec->stderr_pipe, .flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE } }; options->stdio_count = 3; - if(cwd != NULL && cwd[0] != '\0') { + if (cwd != NULL && cwd[0] != '\0') { options->cwd = cwd; } - if(env != NULL) { - options->env = (char **)env; + if (env != NULL) { + options->env = (char **) env; } const int result = uv_spawn(UVLOOP, exec->process, options); @@ -1987,8 +2014,8 @@ static zend_async_exec_event_t * libuv_new_exec_event( return NULL; } - uv_read_start((uv_stream_t*) exec->stdout_pipe, exec_alloc_cb, exec_read_cb); - uv_read_start((uv_stream_t*) exec->stderr_pipe, exec_std_err_alloc_cb, exec_std_err_read_cb); + uv_read_start((uv_stream_t *) exec->stdout_pipe, exec_alloc_cb, exec_read_cb); + uv_read_start((uv_stream_t *) exec->stderr_pipe, exec_std_err_alloc_cb, exec_std_err_read_cb); ZEND_ASYNC_INCREASE_EVENT_COUNT; @@ -2004,16 +2031,14 @@ static zend_async_exec_event_t * libuv_new_exec_event( } /* {{{ libuv_exec */ -static int libuv_exec( - zend_async_exec_mode exec_mode, - const char *cmd, - zval *return_buffer, - zval *return_value, - zval *std_error, - const char *cwd, - const char *env, - const zend_ulong timeout -) +static int libuv_exec(zend_async_exec_mode exec_mode, + const char *cmd, + zval *return_buffer, + zval *return_value, + zval *std_error, + const char *cwd, + const char *env, + const zend_ulong timeout) { zval tmp_return_value, tmp_return_buffer; @@ -2031,15 +2056,14 @@ static int libuv_exec( return -1; } - zend_async_exec_event_t * exec_event = ZEND_ASYNC_NEW_EXEC_EVENT( - exec_mode, - cmd, - return_buffer != NULL ? return_buffer : &tmp_return_buffer, - return_value != NULL ? return_value : &tmp_return_value, - std_error, - cwd, - env - ); + zend_async_exec_event_t *exec_event = + ZEND_ASYNC_NEW_EXEC_EVENT(exec_mode, + cmd, + return_buffer != NULL ? return_buffer : &tmp_return_buffer, + return_value != NULL ? return_value : &tmp_return_value, + std_error, + cwd, + env); if (UNEXPECTED(EG(exception))) { return -1; @@ -2065,11 +2089,12 @@ static int libuv_exec( zval_ptr_dtor(&tmp_return_value); zval_ptr_dtor(&tmp_return_buffer); - int exit_code = (int)exec_event->exit_code; + int exit_code = (int) exec_event->exit_code; exec_event->base.dispose(&exec_event->base); return exit_code; } + /* }}} */ ///////////////////////////////////////////////////////////////////////////////// @@ -2085,17 +2110,19 @@ static void on_trigger_event(uv_async_t *handle) IF_EXCEPTION_STOP_REACTOR; } + /* }}} */ /* {{{ libuv_trigger_event_trigger */ static void libuv_trigger_event_trigger(zend_async_trigger_event_t *event) { - async_trigger_event_t *trigger = (async_trigger_event_t *)event; - + async_trigger_event_t *trigger = (async_trigger_event_t *) event; + if (!ZEND_ASYNC_EVENT_IS_CLOSED(&trigger->event.base)) { uv_async_send(&trigger->uv_handle); } } + /* }}} */ /* {{{ libuv_trigger_event_start */ @@ -2106,6 +2133,7 @@ static void libuv_trigger_event_start(zend_async_event_t *event) event->loop_ref_count++; ZEND_ASYNC_INCREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_trigger_event_stop */ @@ -2116,6 +2144,7 @@ static void libuv_trigger_event_stop(zend_async_event_t *event) event->loop_ref_count = 0; ZEND_ASYNC_DECREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_trigger_event_dispose */ @@ -2133,20 +2162,20 @@ static void libuv_trigger_event_dispose(zend_async_event_t *event) zend_async_callbacks_free(event); - async_trigger_event_t *trigger = (async_trigger_event_t *)(event); + async_trigger_event_t *trigger = (async_trigger_event_t *) (event); - uv_close((uv_handle_t *)&trigger->uv_handle, libuv_close_handle_cb); + uv_close((uv_handle_t *) &trigger->uv_handle, libuv_close_handle_cb); } + /* }}} */ /* {{{ libuv_new_trigger_event */ -zend_async_trigger_event_t* libuv_new_trigger_event(size_t extra_size) +zend_async_trigger_event_t *libuv_new_trigger_event(size_t extra_size) { START_REACTOR_OR_RETURN_NULL; - async_trigger_event_t *trigger = pecalloc(1, extra_size != 0 ? - sizeof(async_trigger_event_t) + extra_size : - sizeof(async_trigger_event_t), 0); + async_trigger_event_t *trigger = pecalloc( + 1, extra_size != 0 ? sizeof(async_trigger_event_t) + extra_size : sizeof(async_trigger_event_t), 0); int error = uv_async_init(UVLOOP, &trigger->uv_handle, on_trigger_event); @@ -2173,13 +2202,15 @@ zend_async_trigger_event_t* libuv_new_trigger_event(size_t extra_size) return &trigger->event; } + /* }}} */ ///////////////////////////////////////////////////////////////////////////////// /// Socket Listening API ///////////////////////////////////////////////////////////////////////////////// -typedef struct { +typedef struct +{ zend_async_listen_event_t event; uv_tcp_t uv_handle; } async_listen_event_t; @@ -2197,28 +2228,26 @@ static void on_connection_event(uv_stream_t *server, int status) if (status < 0) { exception = async_new_exception( - async_ce_input_output_exception, "Connection accept error: %s", uv_strerror(status) - ); + async_ce_input_output_exception, "Connection accept error: %s", uv_strerror(status)); } else { uv_tcp_t client; int result = uv_tcp_init(UVLOOP, &client); - + if (result == 0) { - result = uv_accept(server, (uv_stream_t*)&client); + result = uv_accept(server, (uv_stream_t *) &client); if (result == 0) { uv_os_fd_t fd; - result = uv_fileno((uv_handle_t*)&client, &fd); + result = uv_fileno((uv_handle_t *) &client, &fd); if (result == 0) { - client_socket = (zend_socket_t)fd; + client_socket = (zend_socket_t) fd; } } } - + if (result < 0) { exception = async_new_exception( - async_ce_input_output_exception, "Failed to accept connection: %s", uv_strerror(result) - ); - uv_close((uv_handle_t*)&client, NULL); + async_ce_input_output_exception, "Failed to accept connection: %s", uv_strerror(result)); + uv_close((uv_handle_t *) &client, NULL); } } @@ -2230,6 +2259,7 @@ static void on_connection_event(uv_stream_t *server, int status) IF_EXCEPTION_STOP_REACTOR; } + /* }}} */ /* {{{ libuv_listen_start */ @@ -2237,9 +2267,10 @@ static void libuv_listen_start(zend_async_event_t *event) { EVENT_START_PROLOGUE(event); - async_listen_event_t *listen_event = (async_listen_event_t *)(event); + async_listen_event_t *listen_event = (async_listen_event_t *) (event); - const int error = uv_listen((uv_stream_t*)&listen_event->uv_handle, listen_event->event.backlog, on_connection_event); + const int error = + uv_listen((uv_stream_t *) &listen_event->uv_handle, listen_event->event.backlog, on_connection_event); if (error < 0) { async_throw_error("Failed to start listening: %s", uv_strerror(error)); @@ -2249,6 +2280,7 @@ static void libuv_listen_start(zend_async_event_t *event) event->loop_ref_count++; ZEND_ASYNC_INCREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_listen_stop */ @@ -2260,6 +2292,7 @@ static void libuv_listen_stop(zend_async_event_t *event) event->loop_ref_count = 0; ZEND_ASYNC_DECREASE_EVENT_COUNT; } + /* }}} */ /* {{{ libuv_listen_dispose */ @@ -2277,42 +2310,40 @@ static void libuv_listen_dispose(zend_async_event_t *event) zend_async_callbacks_free(event); - async_listen_event_t *listen_event = (async_listen_event_t *)(event); + async_listen_event_t *listen_event = (async_listen_event_t *) (event); if (listen_event->event.host) { - efree((void*)listen_event->event.host); + efree((void *) listen_event->event.host); listen_event->event.host = NULL; } - uv_close((uv_handle_t *)&listen_event->uv_handle, libuv_close_handle_cb); + uv_close((uv_handle_t *) &listen_event->uv_handle, libuv_close_handle_cb); } + /* }}} */ /* {{{ libuv_listen_get_local_address */ -static int libuv_listen_get_local_address( - zend_async_listen_event_t *listen_event, - char *host, size_t host_len, - int *port -) +static int +libuv_listen_get_local_address(zend_async_listen_event_t *listen_event, char *host, size_t host_len, int *port) { struct sockaddr_storage addr; int addr_len = sizeof(addr); - - int result = uv_tcp_getsockname(&((async_listen_event_t*)listen_event)->uv_handle, - (struct sockaddr*)&addr, &addr_len); - + + int result = uv_tcp_getsockname( + &((async_listen_event_t *) listen_event)->uv_handle, (struct sockaddr *) &addr, &addr_len); + if (result < 0) { return result; } - + if (addr.ss_family == AF_INET) { - struct sockaddr_in *addr_in = (struct sockaddr_in*)&addr; + struct sockaddr_in *addr_in = (struct sockaddr_in *) &addr; *port = ntohs(addr_in->sin_port); if (host && host_len > 0) { uv_ip4_name(addr_in, host, host_len); } } else if (addr.ss_family == AF_INET6) { - struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6*)&addr; + struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *) &addr; *port = ntohs(addr_in6->sin6_port); if (host && host_len > 0) { uv_ip6_name(addr_in6, host, host_len); @@ -2320,19 +2351,19 @@ static int libuv_listen_get_local_address( } else { return -1; } - + return 0; } + /* }}} */ /* {{{ libuv_socket_listen */ -zend_async_listen_event_t* libuv_socket_listen(const char *host, int port, int backlog, size_t extra_size) +zend_async_listen_event_t *libuv_socket_listen(const char *host, int port, int backlog, size_t extra_size) { START_REACTOR_OR_RETURN_NULL; - async_listen_event_t *listen_event = pecalloc(1, extra_size != 0 ? - sizeof(async_listen_event_t) + extra_size : - sizeof(async_listen_event_t), 0); + async_listen_event_t *listen_event = + pecalloc(1, extra_size != 0 ? sizeof(async_listen_event_t) + extra_size : sizeof(async_listen_event_t), 0); int error = uv_tcp_init(UVLOOP, &listen_event->uv_handle); if (error < 0) { @@ -2349,33 +2380,33 @@ zend_async_listen_event_t* libuv_socket_listen(const char *host, int port, int b struct sockaddr_storage addr; if (strchr(host, ':') != NULL) { // IPv6 - error = uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr); + error = uv_ip6_addr(host, port, (struct sockaddr_in6 *) &addr); } else { // IPv4 - error = uv_ip4_addr(host, port, (struct sockaddr_in*)&addr); + error = uv_ip4_addr(host, port, (struct sockaddr_in *) &addr); } if (error < 0) { async_throw_error("Failed to parse address %s:%d: %s", host, port, uv_strerror(error)); - uv_close((uv_handle_t*)&listen_event->uv_handle, libuv_close_handle_cb); + uv_close((uv_handle_t *) &listen_event->uv_handle, libuv_close_handle_cb); pefree(listen_event, 0); return NULL; } - error = uv_tcp_bind(&listen_event->uv_handle, (struct sockaddr*)&addr, 0); + error = uv_tcp_bind(&listen_event->uv_handle, (struct sockaddr *) &addr, 0); if (error < 0) { async_throw_error("Failed to bind to %s:%d: %s", host, port, uv_strerror(error)); - uv_close((uv_handle_t*)&listen_event->uv_handle, libuv_close_handle_cb); + uv_close((uv_handle_t *) &listen_event->uv_handle, libuv_close_handle_cb); pefree(listen_event, 0); return NULL; } // Get actual socket fd uv_os_fd_t fd; - error = uv_fileno((uv_handle_t*)&listen_event->uv_handle, &fd); + error = uv_fileno((uv_handle_t *) &listen_event->uv_handle, &fd); if (error < 0) { async_throw_error("Failed to get socket descriptor: %s", uv_strerror(error)); - uv_close((uv_handle_t*)&listen_event->uv_handle, libuv_close_handle_cb); + uv_close((uv_handle_t *) &listen_event->uv_handle, libuv_close_handle_cb); pefree(listen_event, 0); return NULL; } @@ -2385,7 +2416,7 @@ zend_async_listen_event_t* libuv_socket_listen(const char *host, int port, int b listen_event->event.host = estrdup(host); listen_event->event.port = port; listen_event->event.backlog = backlog; - listen_event->event.socket_fd = (zend_socket_t)fd; + listen_event->event.socket_fd = (zend_socket_t) fd; listen_event->event.base.extra_offset = sizeof(async_listen_event_t); listen_event->event.base.ref_count = 1; @@ -2399,35 +2430,30 @@ zend_async_listen_event_t* libuv_socket_listen(const char *host, int port, int b return &listen_event->event; } + /* }}} */ void async_libuv_reactor_register(void) { - zend_async_reactor_register( - LIBUV_REACTOR_NAME, - false, - libuv_reactor_startup, - libuv_reactor_shutdown, - libuv_reactor_execute, - libuv_reactor_loop_alive, - libuv_new_socket_event, - libuv_new_poll_event, - libuv_new_timer_event, - libuv_new_signal_event, - libuv_new_process_event, - libuv_new_thread_event, - libuv_new_filesystem_event, - libuv_getnameinfo, - libuv_getaddrinfo, - libuv_freeaddrinfo, - libuv_new_exec_event, - libuv_exec, - libuv_new_trigger_event - ); - - zend_async_socket_listening_register( - LIBUV_REACTOR_NAME, - false, - libuv_socket_listen - ); + zend_async_reactor_register(LIBUV_REACTOR_NAME, + false, + libuv_reactor_startup, + libuv_reactor_shutdown, + libuv_reactor_execute, + libuv_reactor_loop_alive, + libuv_new_socket_event, + libuv_new_poll_event, + libuv_new_timer_event, + libuv_new_signal_event, + libuv_new_process_event, + libuv_new_thread_event, + libuv_new_filesystem_event, + libuv_getnameinfo, + libuv_getaddrinfo, + libuv_freeaddrinfo, + libuv_new_exec_event, + libuv_exec, + libuv_new_trigger_event); + + zend_async_socket_listening_register(LIBUV_REACTOR_NAME, false, libuv_socket_listen); } \ No newline at end of file diff --git a/libuv_reactor.h b/libuv_reactor.h index 78641af..fa81fc6 100644 --- a/libuv_reactor.h +++ b/libuv_reactor.h @@ -42,64 +42,74 @@ typedef struct _async_dns_addrinfo_t async_dns_addrinfo_t; typedef struct _async_exec_event_t async_exec_event_t; -struct _async_poll_event_t { +struct _async_poll_event_t +{ zend_async_poll_event_t event; uv_poll_t uv_handle; }; -struct _async_timer_event_t { +struct _async_timer_event_t +{ zend_async_timer_event_t event; uv_timer_t uv_handle; }; -struct _async_signal_event_t { +struct _async_signal_event_t +{ zend_async_signal_event_t event; // uv_signal_t removed - now using global signal management }; -struct _async_filesystem_event_t { +struct _async_filesystem_event_t +{ zend_async_filesystem_event_t event; uv_fs_event_t uv_handle; }; -struct _async_dns_nameinfo_t { +struct _async_dns_nameinfo_t +{ zend_async_dns_nameinfo_t event; uv_getnameinfo_t uv_handle; }; -struct _async_dns_addrinfo_t { +struct _async_dns_addrinfo_t +{ zend_async_dns_addrinfo_t event; uv_getaddrinfo_t uv_handle; }; -struct _async_process_event_t { +struct _async_process_event_t +{ zend_async_process_event_t event; #ifdef PHP_WIN32 HANDLE hJob; #endif }; -struct _async_thread_event_t { +struct _async_thread_event_t +{ zend_async_thread_event_t event; uv_thread_t uv_handle; }; -struct _async_exec_event_t { +struct _async_exec_event_t +{ zend_async_exec_event_t event; - uv_process_t * process; - uv_pipe_t * stdout_pipe; - uv_pipe_t * stderr_pipe; + uv_process_t *process; + uv_pipe_t *stdout_pipe; + uv_pipe_t *stderr_pipe; uv_process_options_t options; #ifdef PHP_WIN32 - char * quoted_cmd; + char *quoted_cmd; #endif }; -struct _async_trigger_event_t { +struct _async_trigger_event_t +{ zend_async_trigger_event_t event; uv_async_t uv_handle; }; void async_libuv_reactor_register(void); -#endif //LIBUV_REACTOR_H +#endif // LIBUV_REACTOR_H diff --git a/php_async.h b/php_async.h index f24571b..124a65f 100644 --- a/php_async.h +++ b/php_async.h @@ -38,8 +38,8 @@ extern zend_module_entry async_module_entry; #define phpext_async_ptr &async_module_entry -extern zend_class_entry * async_ce_awaitable; -extern zend_class_entry * async_ce_timeout; +extern zend_class_entry *async_ce_awaitable; +extern zend_class_entry *async_ce_timeout; #define PHP_ASYNC_NAME "TrueAsync" #define PHP_ASYNC_VERSION "0.5.0" @@ -63,48 +63,48 @@ typedef struct zend_object std; } async_timeout_object_t; -#define ASYNC_TIMEOUT_FROM_EVENT(ev) ((async_timeout_ext_t *)((char *)(ev) + (ev)->extra_offset)) -#define ASYNC_TIMEOUT_FROM_OBJ(obj) ((async_timeout_object_t *)((char *)(obj) - (obj)->handlers->offset)) +#define ASYNC_TIMEOUT_FROM_EVENT(ev) ((async_timeout_ext_t *) ((char *) (ev) + (ev)->extra_offset)) +#define ASYNC_TIMEOUT_FROM_OBJ(obj) ((async_timeout_object_t *) ((char *) (obj) - (obj)->handlers->offset)) ZEND_BEGIN_MODULE_GLOBALS(async) - // Microtask queue - circular_buffer_t microtasks; - /* Queue of coroutine_queue */ - circular_buffer_t coroutine_queue; - /* List of coroutines */ - HashTable coroutines; - /* The transfer structure is used to return to the main execution context. */ - zend_fiber_transfer *main_transfer; - /* The main flow stack */ - zend_vm_stack main_vm_stack; - /* System root context */ - zend_async_context_t *root_context; - /* The default concurrency */ - int default_concurrency; +// Microtask queue +circular_buffer_t microtasks; +/* Queue of coroutine_queue */ +circular_buffer_t coroutine_queue; +/* List of coroutines */ +HashTable coroutines; +/* The transfer structure is used to return to the main execution context. */ +zend_fiber_transfer *main_transfer; +/* The main flow stack */ +zend_vm_stack main_vm_stack; +/* System root context */ +zend_async_context_t *root_context; +/* The default concurrency */ +int default_concurrency; #ifdef PHP_ASYNC_LIBUV - /* The reactor */ - uv_loop_t uvloop; - bool reactor_started; - - /* Global signal management for all platforms */ - HashTable * signal_handlers; /* signum -> uv_signal_t* */ - HashTable * signal_events; /* signum -> HashTable* (signal events) */ - HashTable * process_events; /* dedicated for SIGCHLD process events */ +/* The reactor */ +uv_loop_t uvloop; +bool reactor_started; + +/* Global signal management for all platforms */ +HashTable *signal_handlers; /* signum -> uv_signal_t* */ +HashTable *signal_events; /* signum -> HashTable* (signal events) */ +HashTable *process_events; /* dedicated for SIGCHLD process events */ #ifdef PHP_WIN32 - uv_thread_t * watcherThread; - HANDLE ioCompletionPort; - unsigned int countWaitingDescriptors; - bool isRunning; - uv_async_t * uvloop_wakeup; - /* Circular buffer of libuv_process_t ptr */ - circular_buffer_t * pid_queue; +uv_thread_t *watcherThread; +HANDLE ioCompletionPort; +unsigned int countWaitingDescriptors; +bool isRunning; +uv_async_t *uvloop_wakeup; +/* Circular buffer of libuv_process_t ptr */ +circular_buffer_t *pid_queue; #endif #endif - #ifdef PHP_WIN32 - #endif +#ifdef PHP_WIN32 +#endif ZEND_END_MODULE_GLOBALS(async) ZEND_EXTERN_MODULE_GLOBALS(async) @@ -112,8 +112,8 @@ ZEND_EXTERN_MODULE_GLOBALS(async) #define ASYNC_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(async, v) #define ASYNC_GLOBALS ZEND_MODULE_GLOBALS_BULK(async) -# if defined(ZTS) && defined(COMPILE_DL_ASYNC) +#if defined(ZTS) && defined(COMPILE_DL_ASYNC) ZEND_TSRMLS_CACHE_EXTERN() -# endif +#endif -#endif //ASYNC_H \ No newline at end of file +#endif // ASYNC_H \ No newline at end of file diff --git a/scheduler.c b/scheduler.c index 41b4260..7ddc128 100644 --- a/scheduler.c +++ b/scheduler.c @@ -24,8 +24,6 @@ #include "zend_common.h" #include "zend_observer.h" -static zend_function main_coroutine_root_function = { ZEND_INTERNAL_FUNCTION }; - void async_scheduler_startup(void) { } @@ -74,10 +72,13 @@ zend_always_inline static void execute_microtasks(void) * @param exception The exception to pass, or NULL if no exception is to be passed. * @param transfer The transfer object to define. */ -static zend_always_inline void define_transfer(async_coroutine_t *coroutine, zend_object * exception, zend_fiber_transfer *transfer) +static zend_always_inline void +define_transfer(async_coroutine_t *coroutine, zend_object *exception, zend_fiber_transfer *transfer) { - if (UNEXPECTED(coroutine->context.status == ZEND_FIBER_STATUS_INIT - && zend_fiber_init_context(&coroutine->context, async_ce_coroutine, async_coroutine_execute, EG(fiber_stack_size)) == FAILURE)) { + if (UNEXPECTED(coroutine->context.status == ZEND_FIBER_STATUS_INIT && + zend_fiber_init_context( + &coroutine->context, async_ce_coroutine, async_coroutine_execute, EG(fiber_stack_size)) == + FAILURE)) { zend_throw_error(NULL, "Failed to initialize coroutine context"); return; } @@ -106,15 +107,16 @@ static zend_always_inline void define_transfer(async_coroutine_t *coroutine, zen * @param coroutine The coroutine to switch to. * @param exception The exception to pass, or NULL if no exception is to be passed. */ -static zend_always_inline void switch_context(async_coroutine_t *coroutine, zend_object * exception) +static zend_always_inline void switch_context(async_coroutine_t *coroutine, zend_object *exception) { zend_fiber_transfer transfer = { .context = &coroutine->context, .flags = exception != NULL ? ZEND_FIBER_TRANSFER_FLAG_ERROR : 0, }; - if (coroutine->context.status == ZEND_FIBER_STATUS_INIT - && zend_fiber_init_context(&coroutine->context, async_ce_coroutine, async_coroutine_execute, EG(fiber_stack_size)) == FAILURE) { + if (coroutine->context.status == ZEND_FIBER_STATUS_INIT && + zend_fiber_init_context( + &coroutine->context, async_ce_coroutine, async_coroutine_execute, EG(fiber_stack_size)) == FAILURE) { zend_throw_error(NULL, "Failed to initialize coroutine context"); return; } @@ -125,7 +127,7 @@ static zend_always_inline void switch_context(async_coroutine_t *coroutine, zend ZVAL_NULL(&transfer.value); } - zend_coroutine_t * previous_coroutine = ZEND_ASYNC_CURRENT_COROUTINE; + zend_coroutine_t *previous_coroutine = ZEND_ASYNC_CURRENT_COROUTINE; ZEND_ASYNC_CURRENT_COROUTINE = &coroutine->coroutine; zend_fiber_switch_context(&transfer); @@ -145,7 +147,7 @@ static zend_always_inline void switch_context(async_coroutine_t *coroutine, zend } } -static zend_always_inline async_coroutine_t * next_coroutine(void) +static zend_always_inline async_coroutine_t *next_coroutine(void) { async_coroutine_t *coroutine; @@ -157,7 +159,8 @@ static zend_always_inline async_coroutine_t * next_coroutine(void) return coroutine; } -typedef enum { +typedef enum +{ COROUTINE_NOT_EXISTS, COROUTINE_SWITCHED, COROUTINE_IGNORED @@ -181,7 +184,7 @@ static switch_status execute_next_coroutine(zend_fiber_transfer *transfer) return COROUTINE_NOT_EXISTS; } - zend_async_waker_t * waker = coroutine->waker; + zend_async_waker_t *waker = coroutine->waker; if (UNEXPECTED(waker == NULL || waker->status == ZEND_ASYNC_WAKER_IGNORED)) { @@ -205,7 +208,7 @@ static switch_status execute_next_coroutine(zend_fiber_transfer *transfer) } waker->status = ZEND_ASYNC_WAKER_RESULT; - zend_object * error = waker->error; + zend_object *error = waker->error; // The Waker object can be destroyed immediately if the result is an error. // It will be delivered to the coroutine as an exception. @@ -266,53 +269,45 @@ static bool resolve_deadlocks(void) const zend_long real_coroutines = zend_hash_num_elements(&ASYNC_G(coroutines)); if (active_coroutines > real_coroutines) { - async_warning( - "The active coroutine counter contains an incorrect value: %u, real counter: %u.", - active_coroutines, real_coroutines - ); + async_warning("The active coroutine counter contains an incorrect value: %u, real counter: %u.", + active_coroutines, + real_coroutines); } if (real_coroutines == 0) { return false; } - async_warning( - "no active coroutines, deadlock detected. Coroutines in waiting: %u", real_coroutines - ); + async_warning("no active coroutines, deadlock detected. Coroutines in waiting: %u", real_coroutines); ZEND_HASH_FOREACH_VAL(&ASYNC_G(coroutines), value) - async_coroutine_t* coroutine = (async_coroutine_t*)Z_PTR_P(value); + async_coroutine_t *coroutine = (async_coroutine_t *) Z_PTR_P(value); - ZEND_ASSERT(coroutine->coroutine.waker != NULL && "The Coroutine has no waker object"); + ZEND_ASSERT(coroutine->coroutine.waker != NULL && "The Coroutine has no waker object"); - if (coroutine->coroutine.waker != NULL && coroutine->coroutine.waker->filename != NULL) { + if (coroutine->coroutine.waker != NULL && coroutine->coroutine.waker->filename != NULL) { - //Maybe we need to get the function name - //zend_string * function_name = NULL; - //zend_get_function_name_by_fci(&fiber_state->fiber->fci, &fiber_state->fiber->fci_cache, &function_name); + // Maybe we need to get the function name + // zend_string * function_name = NULL; + // zend_get_function_name_by_fci(&fiber_state->fiber->fci, &fiber_state->fiber->fci_cache, &function_name); - async_warning( - "the coroutine was suspended in file: %s, line: %d will be canceled", - ZSTR_VAL(coroutine->coroutine.waker->filename), - coroutine->coroutine.waker->lineno - ); - } + async_warning("the coroutine was suspended in file: %s, line: %d will be canceled", + ZSTR_VAL(coroutine->coroutine.waker->filename), + coroutine->coroutine.waker->lineno); + } - // In case a deadlock condition is detected, cancellation protection flags no longer apply. - if (ZEND_COROUTINE_IS_PROTECTED(&coroutine->coroutine)) { - ZEND_COROUTINE_CLR_PROTECTED(&coroutine->coroutine); - } + // In case a deadlock condition is detected, cancellation protection flags no longer apply. + if (ZEND_COROUTINE_IS_PROTECTED(&coroutine->coroutine)) { + ZEND_COROUTINE_CLR_PROTECTED(&coroutine->coroutine); + } - ZEND_ASYNC_CANCEL( - &coroutine->coroutine, - async_new_exception(async_ce_cancellation_exception, "Deadlock detected"), - true - ); + ZEND_ASYNC_CANCEL( + &coroutine->coroutine, async_new_exception(async_ce_cancellation_exception, "Deadlock detected"), true); - if (EG(exception) != NULL) { - return true; - } + if (EG(exception) != NULL) { + return true; + } ZEND_HASH_FOREACH_END(); @@ -339,16 +334,11 @@ static void async_scheduler_dtor(void) ZEND_ASYNC_SCHEDULER_CONTEXT = false; if (UNEXPECTED(false == circular_buffer_is_empty(&ASYNC_G(microtasks)))) { - async_warning( - "%u microtasks were not executed", circular_buffer_count(&ASYNC_G(microtasks)) - ); + async_warning("%u microtasks were not executed", circular_buffer_count(&ASYNC_G(microtasks))); } if (UNEXPECTED(false == circular_buffer_is_empty(&ASYNC_G(coroutine_queue)))) { - async_warning( - "%u deferred coroutines were not executed", - circular_buffer_count(&ASYNC_G(coroutine_queue)) - ); + async_warning("%u deferred coroutines were not executed", circular_buffer_count(&ASYNC_G(coroutine_queue))); } zval_c_buffer_cleanup(&ASYNC_G(coroutine_queue)); @@ -356,10 +346,12 @@ static void async_scheduler_dtor(void) zval *current; // foreach by fibers_state and release all fibers - ZEND_HASH_FOREACH_VAL(&ASYNC_G(coroutines), current) { + ZEND_HASH_FOREACH_VAL(&ASYNC_G(coroutines), current) + { async_coroutine_t *coroutine = Z_PTR_P(current); OBJ_RELEASE(&coroutine->std); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); zend_hash_clean(&ASYNC_G(coroutines)); zend_hash_destroy(&ASYNC_G(coroutines)); @@ -373,9 +365,10 @@ static void async_scheduler_dtor(void) static void dispose_coroutines(void) { - zval * current; + zval *current; - ZEND_HASH_FOREACH_VAL(&ASYNC_G(coroutines), current) { + ZEND_HASH_FOREACH_VAL(&ASYNC_G(coroutines), current) + { zend_coroutine_t *coroutine = Z_PTR_P(current); if (coroutine->waker != NULL) { @@ -387,8 +380,8 @@ static void dispose_coroutines(void) if (EG(exception)) { zend_exception_save(); } - - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } static void cancel_queued_coroutines(void) @@ -396,11 +389,12 @@ static void cancel_queued_coroutines(void) zend_exception_save(); // 1. Walk through all coroutines and cancel them if they are suspended. - zval * current; + zval *current; - zend_object * cancellation_exception = async_new_exception(async_ce_cancellation_exception, "Graceful shutdown"); + zend_object *cancellation_exception = async_new_exception(async_ce_cancellation_exception, "Graceful shutdown"); - ZEND_HASH_FOREACH_VAL(&ASYNC_G(coroutines), current) { + ZEND_HASH_FOREACH_VAL(&ASYNC_G(coroutines), current) + { zend_coroutine_t *coroutine = Z_PTR_P(current); if (((async_coroutine_t *) coroutine)->context.status == ZEND_FIBER_STATUS_INIT) { @@ -421,34 +415,38 @@ static void cancel_queued_coroutines(void) if (EG(exception)) { zend_exception_save(); } - - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); OBJ_RELEASE(cancellation_exception); zend_exception_restore(); } -void async_scheduler_start_waker_events(zend_async_waker_t * waker) +void async_scheduler_start_waker_events(zend_async_waker_t *waker) { ZEND_ASSERT(waker != NULL && "Waker is NULL in async_scheduler_start_waker_events"); - zval * current; - ZEND_HASH_FOREACH_VAL(&waker->events, current) { - const zend_async_waker_trigger_t * trigger = Z_PTR_P(current); + zval *current; + ZEND_HASH_FOREACH_VAL(&waker->events, current) + { + const zend_async_waker_trigger_t *trigger = Z_PTR_P(current); trigger->event->start(trigger->event); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } -void async_scheduler_stop_waker_events(zend_async_waker_t * waker) +void async_scheduler_stop_waker_events(zend_async_waker_t *waker) { ZEND_ASSERT(waker != NULL && "Waker is NULL in async_scheduler_stop_waker_events"); - zval * current; - ZEND_HASH_FOREACH_VAL(&waker->events, current) { - const zend_async_waker_trigger_t * trigger = Z_PTR_P(current); + zval *current; + ZEND_HASH_FOREACH_VAL(&waker->events, current) + { + const zend_async_waker_trigger_t *trigger = Z_PTR_P(current); trigger->event->stop(trigger->event); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } void start_graceful_shutdown(void) @@ -509,10 +507,10 @@ void async_scheduler_main_loop(void); #define TRY_HANDLE_EXCEPTION() \ if (UNEXPECTED(EG(exception) != NULL)) { \ - if(ZEND_ASYNC_GRACEFUL_SHUTDOWN) { \ + if (ZEND_ASYNC_GRACEFUL_SHUTDOWN) { \ finally_shutdown(); \ - break; \ - } \ + break; \ + } \ start_graceful_shutdown(); \ } @@ -561,8 +559,8 @@ void async_scheduler_launch(void) return; } - zend_async_scope_t * scope = ZEND_ASYNC_MAIN_SCOPE; - async_coroutine_t * main_coroutine = (async_coroutine_t *) ZEND_ASYNC_NEW_COROUTINE(scope); + zend_async_scope_t *scope = ZEND_ASYNC_MAIN_SCOPE; + async_coroutine_t *main_coroutine = (async_coroutine_t *) ZEND_ASYNC_NEW_COROUTINE(scope); if (UNEXPECTED(EG(exception) != NULL)) { return; @@ -629,7 +627,7 @@ void async_scheduler_launch(void) ASYNC_G(main_transfer) = main_transfer; ASYNC_G(main_vm_stack) = EG(vm_stack); - zend_coroutine_t * scheduler_coroutine = ZEND_ASYNC_NEW_COROUTINE(NULL); + zend_coroutine_t *scheduler_coroutine = ZEND_ASYNC_NEW_COROUTINE(NULL); if (UNEXPECTED(EG(exception) != NULL)) { return; } @@ -665,33 +663,36 @@ void async_scheduler_main_coroutine_suspend(void) } } - async_coroutine_t * coroutine = (async_coroutine_t *)ZEND_ASYNC_CURRENT_COROUTINE; - zend_fiber_transfer * transfer = ASYNC_G(main_transfer); - - zend_try { - // We reach this point when the main coroutine has completed its execution. - async_coroutine_finalize(transfer, coroutine); + async_coroutine_t *coroutine = (async_coroutine_t *) ZEND_ASYNC_CURRENT_COROUTINE; + zend_fiber_transfer *transfer = ASYNC_G(main_transfer); - coroutine->context.cleanup = NULL; + zend_try + { + // We reach this point when the main coroutine has completed its execution. + async_coroutine_finalize(transfer, coroutine); - OBJ_RELEASE(&coroutine->std); + coroutine->context.cleanup = NULL; - // - // At this point, we transfer control to the Scheduler coroutine. - // Although this code performs 1–2 extra context switches, - // it helps normalize the coroutine switching logic. - // + OBJ_RELEASE(&coroutine->std); - // Since the main coroutine has just finished its execution, - // we must normalize the state of EG(current_fiber_context) - // so that on the next switch we return to this exact point. - EG(current_fiber_context) = transfer->context; + // + // At this point, we transfer control to the Scheduler coroutine. + // Although this code performs 1–2 extra context switches, + // it helps normalize the coroutine switching logic. + // - switch_to_scheduler(NULL); + // Since the main coroutine has just finished its execution, + // we must normalize the state of EG(current_fiber_context) + // so that on the next switch we return to this exact point. + EG(current_fiber_context) = transfer->context; - } zend_catch { + switch_to_scheduler(NULL); + } + zend_catch + { do_bailout = true; - } zend_end_try(); + } + zend_end_try(); ZEND_ASYNC_CURRENT_COROUTINE = NULL; ZEND_ASSERT(ZEND_ASYNC_ACTIVE_COROUTINE_COUNT == 0 && "The active coroutine counter must be 0 at this point"); @@ -711,7 +712,7 @@ void async_scheduler_main_coroutine_suspend(void) // This is the exit point for ASYNC. // - zend_object * exit_exception = ZEND_ASYNC_EXIT_EXCEPTION; + zend_object *exit_exception = ZEND_ASYNC_EXIT_EXCEPTION; ZEND_ASYNC_EXIT_EXCEPTION = NULL; if (UNEXPECTED(do_bailout)) { @@ -734,7 +735,7 @@ void async_scheduler_main_coroutine_suspend(void) #define TRY_HANDLE_SUSPEND_EXCEPTION() \ if (UNEXPECTED(EG(exception) != NULL)) { \ - if(ZEND_ASYNC_GRACEFUL_SHUTDOWN) { \ + if (ZEND_ASYNC_GRACEFUL_SHUTDOWN) { \ finally_shutdown(); \ switch_to_scheduler(transfer); \ zend_exception_restore(); \ @@ -743,7 +744,7 @@ void async_scheduler_main_coroutine_suspend(void) start_graceful_shutdown(); \ } -void async_scheduler_coroutine_enqueue(zend_coroutine_t * coroutine) +void async_scheduler_coroutine_enqueue(zend_coroutine_t *coroutine) { /** * Note that the Scheduler is initialized after the first use of suspend, @@ -763,8 +764,7 @@ void async_scheduler_coroutine_enqueue(zend_coroutine_t * coroutine) // If the transfer is NULL, it means that the coroutine is being resumed // That’s why we’re adding it to the queue. // coroutine->waker->status != ZEND_ASYNC_WAKER_QUEUED means not need to add to queue twice - if (coroutine != NULL && (coroutine->waker == NULL || false == ZEND_ASYNC_WAKER_IN_QUEUE(coroutine->waker)) - ) { + if (coroutine != NULL && (coroutine->waker == NULL || false == ZEND_ASYNC_WAKER_IN_QUEUE(coroutine->waker))) { if (coroutine->waker == NULL) { zend_async_waker_t *waker = zend_async_waker_new(coroutine); if (UNEXPECTED(EG(exception))) { @@ -810,7 +810,7 @@ void async_scheduler_coroutine_suspend(zend_fiber_transfer *transfer) ZEND_ASYNC_SCHEDULER_HEARTBEAT; - zend_coroutine_t * coroutine = ZEND_ASYNC_CURRENT_COROUTINE; + zend_coroutine_t *coroutine = ZEND_ASYNC_CURRENT_COROUTINE; // // Before suspending the coroutine, @@ -864,10 +864,10 @@ void async_scheduler_coroutine_suspend(zend_fiber_transfer *transfer) // if (UNEXPECTED(transfer != NULL && transfer->flags & ZEND_FIBER_TRANSFER_FLAG_ERROR)) { - zend_object * exception = Z_OBJ(transfer->value); + zend_object *exception = Z_OBJ(transfer->value); ZEND_ASSERT(Z_TYPE(transfer->value) == IS_OBJECT && "The transfer value must be an exception object"); - transfer->flags = 0; // Reset the flags to avoid reprocessing the exception + transfer->flags = 0; // Reset the flags to avoid reprocessing the exception ZVAL_NULL(&transfer->value); // Reset the transfer value to avoid memory leaks if (ZEND_ASYNC_EXIT_EXCEPTION != NULL) { @@ -877,7 +877,7 @@ void async_scheduler_coroutine_suspend(zend_fiber_transfer *transfer) ZEND_ASYNC_EXIT_EXCEPTION = exception; } - if(ZEND_ASYNC_GRACEFUL_SHUTDOWN) { + if (ZEND_ASYNC_GRACEFUL_SHUTDOWN) { finally_shutdown(); } else { start_graceful_shutdown(); @@ -904,15 +904,11 @@ void async_scheduler_coroutine_suspend(zend_fiber_transfer *transfer) const bool is_next_coroutine = circular_buffer_is_not_empty(&ASYNC_G(coroutine_queue)); - if (UNEXPECTED( - false == has_handles - && false == is_next_coroutine - && zend_hash_num_elements(&ASYNC_G(coroutines)) > 0 - && circular_buffer_is_empty(&ASYNC_G(microtasks)) - && resolve_deadlocks() - )) { - switch_to_scheduler(transfer); - } + if (UNEXPECTED(false == has_handles && false == is_next_coroutine && + zend_hash_num_elements(&ASYNC_G(coroutines)) > 0 && circular_buffer_is_empty(&ASYNC_G(microtasks)) && + resolve_deadlocks())) { + switch_to_scheduler(transfer); + } if (EXPECTED(is_next_coroutine)) { // @@ -968,31 +964,27 @@ void async_scheduler_main_loop(void) TRY_HANDLE_EXCEPTION(); - if (UNEXPECTED( - false == has_handles - && false == was_executed - && zend_hash_num_elements(&ASYNC_G(coroutines)) > 0 - && circular_buffer_is_empty(&ASYNC_G(coroutine_queue)) - && circular_buffer_is_empty(&ASYNC_G(microtasks)) - && resolve_deadlocks() - )) { - break; - } - - } while (zend_hash_num_elements(&ASYNC_G(coroutines)) > 0 - || circular_buffer_is_not_empty(&ASYNC_G(microtasks)) - || ZEND_ASYNC_REACTOR_LOOP_ALIVE() - ); - - } zend_catch { + if (UNEXPECTED(false == has_handles && false == was_executed && + zend_hash_num_elements(&ASYNC_G(coroutines)) > 0 && + circular_buffer_is_empty(&ASYNC_G(coroutine_queue)) && + circular_buffer_is_empty(&ASYNC_G(microtasks)) && resolve_deadlocks())) { + break; + } + + } while (zend_hash_num_elements(&ASYNC_G(coroutines)) > 0 || + circular_buffer_is_not_empty(&ASYNC_G(microtasks)) || ZEND_ASYNC_REACTOR_LOOP_ALIVE()); + } + zend_catch + { dispose_coroutines(); async_scheduler_dtor(); zend_bailout(); - } zend_end_try(); + } + zend_end_try(); ZEND_ASSERT(ZEND_ASYNC_REACTOR_LOOP_ALIVE() == false && "The event loop must be stopped"); - zend_object * exit_exception = ZEND_ASYNC_EXIT_EXCEPTION; + zend_object *exit_exception = ZEND_ASYNC_EXIT_EXCEPTION; async_scheduler_dtor(); diff --git a/scheduler.h b/scheduler.h index a74283f..e634a5d 100644 --- a/scheduler.h +++ b/scheduler.h @@ -35,8 +35,8 @@ void async_scheduler_launch(void); */ void async_scheduler_coroutine_suspend(zend_fiber_transfer *transfer); void async_scheduler_main_coroutine_suspend(void); -void async_scheduler_coroutine_enqueue(zend_coroutine_t * coroutine); +void async_scheduler_coroutine_enqueue(zend_coroutine_t *coroutine); END_EXTERN_C() -#endif //PHP_SCHEDULER_H +#endif // PHP_SCHEDULER_H diff --git a/scope.c b/scope.c index f546dde..388ce92 100644 --- a/scope.c +++ b/scope.c @@ -24,14 +24,13 @@ #define METHOD(name) PHP_METHOD(Async_Scope, name) -zend_class_entry * async_ce_scope = NULL; -zend_class_entry * async_ce_scope_provider = NULL; -zend_class_entry * async_ce_spawn_strategy = NULL; +zend_class_entry *async_ce_scope = NULL; +zend_class_entry *async_ce_scope_provider = NULL; +zend_class_entry *async_ce_spawn_strategy = NULL; static zend_object_handlers async_scope_handlers; -static zend_always_inline void -async_scope_add_coroutine(async_scope_t *scope, async_coroutine_t *coroutine) +static zend_always_inline void async_scope_add_coroutine(async_scope_t *scope, async_coroutine_t *coroutine) { async_coroutines_vector_t *vector = &scope->coroutines; @@ -56,8 +55,7 @@ async_scope_add_coroutine(async_scope_t *scope, async_coroutine_t *coroutine) } } -static zend_always_inline void -async_scope_remove_coroutine(async_scope_t *scope, async_coroutine_t *coroutine) +static zend_always_inline void async_scope_remove_coroutine(async_scope_t *scope, async_coroutine_t *coroutine) { async_coroutines_vector_t *vector = &scope->coroutines; for (uint32_t i = 0; i < vector->length; ++i) { @@ -75,8 +73,7 @@ async_scope_remove_coroutine(async_scope_t *scope, async_coroutine_t *coroutine) } } -static zend_always_inline void -async_scope_free_coroutines(async_scope_t *scope) +static zend_always_inline void async_scope_free_coroutines(async_scope_t *scope) { async_coroutines_vector_t *vector = &scope->coroutines; @@ -93,9 +90,10 @@ async_scope_free_coroutines(async_scope_t *scope) /// Scope methods ////////////////////////////////////////////////////////// -static void callback_resolve_when_zombie_completed( - zend_async_event_t *event, zend_async_event_callback_t *callback, void * result, zend_object *exception -); +static void callback_resolve_when_zombie_completed(zend_async_event_t *event, + zend_async_event_callback_t *callback, + void *result, + zend_object *exception); static bool scope_can_be_disposed(async_scope_t *scope, bool with_zombies, bool check_zend_objects); static void scope_check_completion_and_notify(async_scope_t *scope, bool with_zombies); @@ -104,7 +102,8 @@ static void scope_check_completion_and_notify(async_scope_t *scope, bool with_zo static bool async_scope_call_finally_handlers(async_scope_t *scope); // Structure for scope finally handlers context -typedef struct { +typedef struct +{ async_scope_t *scope; zend_object *composite_exception; } scope_finally_handlers_context_t; @@ -118,24 +117,28 @@ static void scope_event_start(zend_async_event_t *event); static void scope_event_stop(zend_async_event_t *event); static void scope_add_callback(zend_async_event_t *event, zend_async_event_callback_t *callback); static void scope_del_callback(zend_async_event_t *event, zend_async_event_callback_t *callback); -static bool scope_replay(zend_async_event_t *event, zend_async_event_callback_t *callback, zval *result, zend_object **exception); -static zend_string* scope_info(zend_async_event_t *event); +static bool +scope_replay(zend_async_event_t *event, zend_async_event_callback_t *callback, zval *result, zend_object **exception); +static zend_string *scope_info(zend_async_event_t *event); -#define THROW_IF_SCHEDULER_CONTEXT if (UNEXPECTED(ZEND_ASYNC_IS_SCHEDULER_CONTEXT)) { \ - async_throw_error("The operation cannot be executed in the scheduler context"); \ - RETURN_THROWS(); \ +#define THROW_IF_SCHEDULER_CONTEXT \ + if (UNEXPECTED(ZEND_ASYNC_IS_SCHEDULER_CONTEXT)) { \ + async_throw_error("The operation cannot be executed in the scheduler context"); \ + RETURN_THROWS(); \ } -#define THROW_IF_ASYNC_OFF if (UNEXPECTED(ZEND_ASYNC_OFF)) { \ - async_throw_error("The operation cannot be executed while async is off"); \ - RETURN_THROWS(); \ +#define THROW_IF_ASYNC_OFF \ + if (UNEXPECTED(ZEND_ASYNC_OFF)) { \ + async_throw_error("The operation cannot be executed while async is off"); \ + RETURN_THROWS(); \ } -#define SCHEDULER_LAUNCH if (UNEXPECTED(ZEND_ASYNC_CURRENT_COROUTINE == NULL)) { \ - async_scheduler_launch(); \ - if (UNEXPECTED(EG(exception) != NULL)) { \ - RETURN_THROWS(); \ - } \ +#define SCHEDULER_LAUNCH \ + if (UNEXPECTED(ZEND_ASYNC_CURRENT_COROUTINE == NULL)) { \ + async_scheduler_launch(); \ + if (UNEXPECTED(EG(exception) != NULL)) { \ + RETURN_THROWS(); \ + } \ } #define THIS_SCOPE ((async_scope_object_t *) Z_OBJ_P(ZEND_THIS)) @@ -145,8 +148,8 @@ METHOD(inherit) zend_object *parent_scope_obj = NULL; ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(parent_scope_obj, async_ce_scope) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(parent_scope_obj, async_ce_scope) ZEND_PARSE_PARAMETERS_END(); zend_async_scope_t *base_parent_scope = NULL; @@ -216,8 +219,8 @@ METHOD(spawn) zend_fcall_info_cache fcc; ZEND_PARSE_PARAMETERS_START(1, -1) - Z_PARAM_FUNC(fci, fcc); - Z_PARAM_VARIADIC_WITH_NAMED(args, args_count, named_args); + Z_PARAM_FUNC(fci, fcc); + Z_PARAM_VARIADIC_WITH_NAMED(args, args_count, named_args); ZEND_PARSE_PARAMETERS_END(); async_scope_object_t *scope_object = THIS_SCOPE; @@ -247,8 +250,8 @@ METHOD(cancel) zend_object *cancellation = NULL; ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OR_NULL(cancellation) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OR_NULL(cancellation) ZEND_PARSE_PARAMETERS_END(); async_scope_object_t *scope_object = THIS_SCOPE; @@ -256,7 +259,7 @@ METHOD(cancel) return; } - zend_async_scope_t * scope = &scope_object->scope->scope; + zend_async_scope_t *scope = &scope_object->scope->scope; ZEND_ASYNC_SCOPE_CANCEL(scope, cancellation, false, ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(scope)); } @@ -266,7 +269,7 @@ METHOD(awaitCompletion) zend_object *cancellation_obj; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJ_OF_CLASS(cancellation_obj, async_ce_awaitable) + Z_PARAM_OBJ_OF_CLASS(cancellation_obj, async_ce_awaitable) ZEND_PARSE_PARAMETERS_END(); zend_coroutine_t *current_coroutine = ZEND_ASYNC_CURRENT_COROUTINE; @@ -290,7 +293,8 @@ METHOD(awaitCompletion) // Check for deadlock: current coroutine belongs to this scope or its children if (async_scope_contains_coroutine(scope_object->scope, current_coroutine, 0)) { - async_throw_error("Cannot await completion of scope from a coroutine that belongs to the same scope or its children"); + async_throw_error( + "Cannot await completion of scope from a coroutine that belongs to the same scope or its children"); RETURN_THROWS(); } if (UNEXPECTED(EG(exception))) { @@ -308,20 +312,17 @@ METHOD(awaitCompletion) } zend_async_resume_when( - current_coroutine, &scope_object->scope->scope.event, false, zend_async_waker_callback_resolve, NULL - ); + current_coroutine, &scope_object->scope->scope.event, false, zend_async_waker_callback_resolve, NULL); if (UNEXPECTED(EG(exception))) { zend_async_waker_destroy(current_coroutine); RETURN_THROWS(); } - zend_async_resume_when( - current_coroutine, - ZEND_ASYNC_OBJECT_TO_EVENT(cancellation_obj), - false, - zend_async_waker_callback_cancel, - NULL - ); + zend_async_resume_when(current_coroutine, + ZEND_ASYNC_OBJECT_TO_EVENT(cancellation_obj), + false, + zend_async_waker_callback_cancel, + NULL); if (UNEXPECTED(EG(exception))) { zend_async_waker_destroy(current_coroutine); RETURN_THROWS(); @@ -333,14 +334,14 @@ METHOD(awaitCompletion) METHOD(awaitAfterCancellation) { - zend_fcall_info error_handler_fci = {0}; - zend_fcall_info_cache error_handler_fcc = {0}; + zend_fcall_info error_handler_fci = { 0 }; + zend_fcall_info_cache error_handler_fcc = { 0 }; zend_object *cancellation_obj = NULL; ZEND_PARSE_PARAMETERS_START(0, 2) - Z_PARAM_OPTIONAL - Z_PARAM_FUNC_OR_NULL(error_handler_fci, error_handler_fcc) - Z_PARAM_OBJ_OR_NULL(cancellation_obj) + Z_PARAM_OPTIONAL + Z_PARAM_FUNC_OR_NULL(error_handler_fci, error_handler_fcc) + Z_PARAM_OBJ_OR_NULL(cancellation_obj) ZEND_PARSE_PARAMETERS_END(); zend_coroutine_t *current_coroutine = ZEND_ASYNC_CURRENT_COROUTINE; @@ -359,7 +360,8 @@ METHOD(awaitAfterCancellation) // Check for deadlock: current coroutine belongs to this scope or its children if (async_scope_contains_coroutine(scope_object->scope, current_coroutine, 0)) { - async_throw_error("Cannot await completion of scope from a coroutine that belongs to the same scope or its children"); + async_throw_error( + "Cannot await completion of scope from a coroutine that belongs to the same scope or its children"); RETURN_THROWS(); } if (UNEXPECTED(EG(exception))) { @@ -378,8 +380,7 @@ METHOD(awaitAfterCancellation) // We need to create a custom callback to handle errors coming from coroutines. scope_coroutine_callback_t *scope_callback = (scope_coroutine_callback_t *) zend_async_coroutine_callback_new( - current_coroutine, callback_resolve_when_zombie_completed, sizeof(scope_coroutine_callback_t) - ); + current_coroutine, callback_resolve_when_zombie_completed, sizeof(scope_coroutine_callback_t)); if (UNEXPECTED(scope_callback == NULL)) { zend_async_waker_destroy(current_coroutine); RETURN_THROWS(); @@ -393,22 +394,18 @@ METHOD(awaitAfterCancellation) scope_callback->error_fci_cache = NULL; } - zend_async_resume_when( - current_coroutine, &scope_object->scope->scope.event, true, NULL, &scope_callback->callback - ); + zend_async_resume_when(current_coroutine, &scope_object->scope->scope.event, true, NULL, &scope_callback->callback); if (UNEXPECTED(EG(exception))) { zend_async_waker_destroy(current_coroutine); RETURN_THROWS(); } if (cancellation_obj != NULL) { - zend_async_resume_when( - current_coroutine, - ZEND_ASYNC_OBJECT_TO_EVENT(cancellation_obj), - false, - zend_async_waker_callback_cancel, - NULL - ); + zend_async_resume_when(current_coroutine, + ZEND_ASYNC_OBJECT_TO_EVENT(cancellation_obj), + false, + zend_async_waker_callback_cancel, + NULL); if (UNEXPECTED(EG(exception))) { zend_async_waker_destroy(current_coroutine); RETURN_THROWS(); @@ -461,7 +458,7 @@ METHOD(setExceptionHandler) zend_fcall_info_cache fcc; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_FUNC(fci, fcc) + Z_PARAM_FUNC(fci, fcc) ZEND_PARSE_PARAMETERS_END(); async_scope_object_t *scope_object = THIS_SCOPE; @@ -471,14 +468,14 @@ METHOD(setExceptionHandler) } async_scope_t *scope = scope_object->scope; - + // Free existing exception handler if any if (scope->exception_fci != NULL || scope->exception_fcc != NULL) { zend_free_fci(scope->exception_fci, scope->exception_fcc); scope->exception_fci = NULL; scope->exception_fcc = NULL; } - + // Allocate and copy new handler scope->exception_fci = emalloc(sizeof(zend_fcall_info)); scope->exception_fcc = emalloc(sizeof(zend_fcall_info_cache)); @@ -491,7 +488,7 @@ METHOD(setChildScopeExceptionHandler) zend_fcall_info_cache fcc; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_FUNC(fci, fcc) + Z_PARAM_FUNC(fci, fcc) ZEND_PARSE_PARAMETERS_END(); async_scope_object_t *scope_object = THIS_SCOPE; @@ -501,14 +498,14 @@ METHOD(setChildScopeExceptionHandler) } async_scope_t *scope = scope_object->scope; - + // Free existing child exception handler if any if (scope->child_exception_fci != NULL || scope->child_exception_fcc != NULL) { zend_free_fci(scope->child_exception_fci, scope->child_exception_fcc); scope->child_exception_fci = NULL; scope->child_exception_fcc = NULL; } - + // Allocate and copy new handler scope->child_exception_fci = emalloc(sizeof(zend_fcall_info)); scope->child_exception_fcc = emalloc(sizeof(zend_fcall_info_cache)); @@ -520,7 +517,7 @@ METHOD(onFinally) zval *callable; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(callable) + Z_PARAM_ZVAL(callable) ZEND_PARSE_PARAMETERS_END(); // Validate callable @@ -567,7 +564,8 @@ METHOD(dispose) async_scope_object_t *scope_object = THIS_SCOPE; if (scope_object->scope != NULL) { - ZEND_ASYNC_SCOPE_CLOSE(&scope_object->scope->scope, ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(&scope_object->scope->scope)); + ZEND_ASYNC_SCOPE_CLOSE(&scope_object->scope->scope, + ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(&scope_object->scope->scope)); } } @@ -581,7 +579,8 @@ METHOD(disposeSafely) } } -typedef struct { +typedef struct +{ zend_async_event_callback_t callback; async_scope_t *scope; } scope_timeout_callback_t; @@ -597,19 +596,16 @@ static void scope_timeout_coroutine_entry(void) coroutine->extended_data = NULL; - zend_object * exception = async_new_exception( - async_ce_cancellation_exception, "Scope has been disposed due to timeout" - ); + zend_object *exception = + async_new_exception(async_ce_cancellation_exception, "Scope has been disposed due to timeout"); ZEND_ASYNC_SCOPE_CANCEL(&scope->scope, exception, false, ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(&scope->scope)); } -static void scope_timeout_callback( - zend_async_event_t *event, - zend_async_event_callback_t *callback, - void * result, - zend_object *exception -) +static void scope_timeout_callback(zend_async_event_t *event, + zend_async_event_callback_t *callback, + void *result, + zend_object *exception) { scope_timeout_callback_t *scope_callback = (scope_timeout_callback_t *) callback; async_scope_t *scope = scope_callback->scope; @@ -629,7 +625,7 @@ METHOD(disposeAfterTimeout) zend_long timeout; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_LONG(timeout) + Z_PARAM_LONG(timeout) ZEND_PARSE_PARAMETERS_END(); if (timeout < 0) { @@ -646,8 +642,7 @@ METHOD(disposeAfterTimeout) return; } - if (scope_object->scope->coroutines.length == 0 - && scope_object->scope->scope.scopes.length == 0) { + if (scope_object->scope->coroutines.length == 0 && scope_object->scope->scope.scopes.length == 0) { return; } @@ -656,9 +651,8 @@ METHOD(disposeAfterTimeout) RETURN_THROWS(); } - scope_timeout_callback_t * callback = (scope_timeout_callback_t *) zend_async_event_callback_new( - scope_timeout_callback,sizeof(scope_timeout_callback_t) - ); + scope_timeout_callback_t *callback = (scope_timeout_callback_t *) zend_async_event_callback_new( + scope_timeout_callback, sizeof(scope_timeout_callback_t)); if (UNEXPECTED(callback == NULL)) { timer_event->base.dispose(&timer_event->base); RETURN_THROWS(); @@ -700,13 +694,14 @@ METHOD(getChildScopes) ////////////////////////////////////////////////////////// /// Scope methods end ////////////////////////////////////////////////////////// -static void callback_resolve_when_zombie_completed( - zend_async_event_t *event, zend_async_event_callback_t *callback, void * result, zend_object *exception -) +static void callback_resolve_when_zombie_completed(zend_async_event_t *event, + zend_async_event_callback_t *callback, + void *result, + zend_object *exception) { async_scope_t *scope = (async_scope_t *) event; scope_coroutine_callback_t *scope_callback = (scope_coroutine_callback_t *) callback; - zend_coroutine_t * coroutine = scope_callback->callback.coroutine; + zend_coroutine_t *coroutine = scope_callback->callback.coroutine; if (UNEXPECTED(exception != NULL && scope_callback->error_fci == NULL)) { // No error handler - resume with exception @@ -717,7 +712,7 @@ static void callback_resolve_when_zombie_completed( if (UNEXPECTED(exception != NULL && scope_callback->error_fci != NULL)) { ZEND_ASYNC_EVENT_SET_EXCEPTION_HANDLED(event); - + // Prepare parameters for handler(\Throwable $error, Scope $scope) zval params[2]; ZVAL_OBJ(¶ms[0], exception); @@ -726,18 +721,17 @@ static void callback_resolve_when_zombie_completed( // Setup function call scope_callback->error_fci->param_count = 2; scope_callback->error_fci->params = params; - + zval retval; ZVAL_UNDEF(&retval); scope_callback->error_fci->retval = &retval; - + if (UNEXPECTED(zend_call_function(scope_callback->error_fci, scope_callback->error_fci_cache) == FAILURE)) { zval_ptr_dtor(&retval); ZEND_ASYNC_RESUME_WITH_ERROR( - coroutine, - async_new_exception(async_ce_async_exception, "Failed to call error handler in scope completion"), - true - ); + coroutine, + async_new_exception(async_ce_async_exception, "Failed to call error handler in scope completion"), + true); return; } @@ -749,7 +743,7 @@ static void callback_resolve_when_zombie_completed( zend_clear_exception(); return; } - + zval_ptr_dtor(&retval); } @@ -827,19 +821,18 @@ static void scope_after_coroutine_enqueue(zend_coroutine_t *coroutine, zend_asyn { } -static zend_always_inline bool try_to_handle_exception( - async_scope_t *current_scope, async_scope_t * from_scope, zend_object *exception, async_coroutine_t *coroutine -); - -static bool scope_catch_or_cancel( - zend_async_scope_t *scope, - zend_coroutine_t *coroutine, - zend_async_scope_t *from_scope, - zend_object *exception, - bool transfer_error, - const bool is_safely, - const bool is_cancellation -) +static zend_always_inline bool try_to_handle_exception(async_scope_t *current_scope, + async_scope_t *from_scope, + zend_object *exception, + async_coroutine_t *coroutine); + +static bool scope_catch_or_cancel(zend_async_scope_t *scope, + zend_coroutine_t *coroutine, + zend_async_scope_t *from_scope, + zend_object *exception, + bool transfer_error, + const bool is_safely, + const bool is_cancellation) { async_scope_t *async_scope = (async_scope_t *) scope; transfer_error = exception != NULL ? transfer_error : false; @@ -889,18 +882,16 @@ static bool scope_catch_or_cancel( // 5. Otherwise, we move to the next parent or exit. // - if (false == is_cancellation - && (async_scope->exception_fci != NULL || async_scope->child_exception_fci != NULL) - && try_to_handle_exception( - async_scope, (async_scope_t *) from_scope, exception, (async_coroutine_t *) coroutine - )) { + if (false == is_cancellation && (async_scope->exception_fci != NULL || async_scope->child_exception_fci != NULL) && + try_to_handle_exception( + async_scope, (async_scope_t *) from_scope, exception, (async_coroutine_t *) coroutine)) { goto exit_true; } ZEND_ASYNC_SCOPE_SET_CANCELLED(&async_scope->scope); - if (((async_scope_object_t *)async_scope->scope.scope_object) != NULL) { - ((async_scope_object_t *)async_scope->scope.scope_object)->is_cancelled = true; + if (((async_scope_object_t *) async_scope->scope.scope_object) != NULL) { + ((async_scope_object_t *) async_scope->scope.scope_object)->is_cancelled = true; } // If an unexpected exception occurs during the function's execution, we combine them into one. @@ -910,23 +901,21 @@ static bool scope_catch_or_cancel( } zend_object *critical_exception = NULL; - zend_async_scope_t * this_scope = &async_scope->scope; + zend_async_scope_t *this_scope = &async_scope->scope; zend_async_scopes_vector_t *scopes = &this_scope->scopes; // First cancel all children scopes for (uint32_t i = 0; i < scopes->length; ++i) { async_scope_t *child_scope = (async_scope_t *) scopes->data[i]; - child_scope->scope.catch_or_cancel( - &child_scope->scope, - coroutine, - this_scope, - // In CATCH mode, we don’t pass the exception that caused the cancellation - // to the child Scopes; instead, a new cancellation exception is generated. - is_cancellation ? exception : NULL, - false, - is_safely, - true - ); + child_scope->scope.catch_or_cancel(&child_scope->scope, + coroutine, + this_scope, + // In CATCH mode, we don’t pass the exception that caused the cancellation + // to the child Scopes; instead, a new cancellation exception is generated. + is_cancellation ? exception : NULL, + false, + is_safely, + true); if (UNEXPECTED(EG(exception))) { critical_exception = zend_exception_merge(critical_exception, true, true); @@ -963,14 +952,7 @@ static bool scope_catch_or_cancel( zend_async_scope_t *parent_scope = async_scope->scope.parent_scope; return parent_scope->catch_or_cancel( - parent_scope, - coroutine, - &async_scope->scope, - exception, - transfer_error, - is_safely, - false - ); + parent_scope, coroutine, &async_scope->scope, exception, transfer_error, is_safely, false); } exit_false: @@ -1036,7 +1018,8 @@ static void scope_del_callback(zend_async_event_t *event, zend_async_event_callb zend_async_callbacks_remove(event, callback); } -static bool scope_replay(zend_async_event_t *event, zend_async_event_callback_t *callback, zval *result, zend_object **exception) +static bool +scope_replay(zend_async_event_t *event, zend_async_event_callback_t *callback, zval *result, zend_object **exception) { async_scope_t *scope = (async_scope_t *) event; @@ -1067,7 +1050,7 @@ static bool scope_replay(zend_async_event_t *event, zend_async_event_callback_t return true; } -static zend_string* scope_info(zend_async_event_t *event) +static zend_string *scope_info(zend_async_event_t *event) { async_scope_t *scope = (async_scope_t *) event; uint32_t scope_id = 0; @@ -1102,8 +1085,8 @@ static void scope_dispose(zend_async_event_t *scope_event) ZEND_ASYNC_SCOPE_SET_DISPOSING(&scope->scope); - ZEND_ASSERT(scope->coroutines.length == 0 && scope->scope.scopes.length == 0 - && "Scope should be empty before disposal"); + ZEND_ASSERT(scope->coroutines.length == 0 && scope->scope.scopes.length == 0 && + "Scope should be empty before disposal"); zend_object *critical_exception = NULL; @@ -1116,9 +1099,8 @@ static void scope_dispose(zend_async_event_t *scope_event) critical_exception = zend_exception_merge(critical_exception, true, true); } - if (scope->finally_handlers != NULL - && zend_hash_num_elements(scope->finally_handlers) > 0 - && async_scope_call_finally_handlers(scope)) { + if (scope->finally_handlers != NULL && zend_hash_num_elements(scope->finally_handlers) > 0 && + async_scope_call_finally_handlers(scope)) { // If finally handlers were called, we don't dispose the scope yet ZEND_ASYNC_EVENT_ADD_REF(&scope->scope.event); if (critical_exception) { @@ -1148,7 +1130,7 @@ static void scope_dispose(zend_async_event_t *scope_event) zend_string_release(scope->filename); scope->filename = NULL; } - + // Free exception handlers if (scope->exception_fci != NULL || scope->exception_fcc != NULL) { zend_free_fci(scope->exception_fci, scope->exception_fcc); @@ -1160,7 +1142,7 @@ static void scope_dispose(zend_async_event_t *scope_event) scope->child_exception_fci = NULL; scope->child_exception_fcc = NULL; } - + // Free finally handlers if (scope->finally_handlers != NULL) { zend_hash_destroy(scope->finally_handlers); @@ -1178,7 +1160,7 @@ static void scope_dispose(zend_async_event_t *scope_event) } } -zend_async_scope_t * async_new_scope(zend_async_scope_t * parent_scope, const bool with_zend_object) +zend_async_scope_t *async_new_scope(zend_async_scope_t *parent_scope, const bool with_zend_object) { async_scope_t *scope = ecalloc(1, sizeof(async_scope_t)); async_scope_object_t *scope_object = NULL; @@ -1219,18 +1201,18 @@ zend_async_scope_t * async_new_scope(zend_async_scope_t * parent_scope, const bo scope->coroutines.capacity = 0; scope->coroutines.data = NULL; scope->active_coroutines_count = 0; - + // Initialize spawn location scope->filename = NULL; scope->lineno = 0; zend_apply_current_filename_and_line(&scope->filename, &scope->lineno); - + // Initialize exception handlers scope->exception_fci = NULL; scope->exception_fcc = NULL; scope->child_exception_fci = NULL; scope->child_exception_fcc = NULL; - + // Initialize finally handlers scope->finally_handlers = NULL; @@ -1276,9 +1258,8 @@ static void scope_destroy(zend_object *object) // This means we are obligated to cancel the Scope and all its child Scopes along with their coroutines. // However, the Scope itself will not be destroyed. if (false == scope->scope.try_to_dispose(&scope->scope)) { - zend_object *exception = async_new_exception( - async_ce_cancellation_exception, "Scope is being disposed due to object destruction" - ); + zend_object *exception = async_new_exception(async_ce_cancellation_exception, + "Scope is being disposed due to object destruction"); ZEND_ASYNC_SCOPE_CANCEL(&scope->scope, exception, true, ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(&scope->scope)); } @@ -1286,7 +1267,7 @@ static void scope_destroy(zend_object *object) static HashTable *scope_object_gc(zend_object *object, zval **table, int *num) { - async_scope_object_t *scope_obj = (async_scope_object_t *)object; + async_scope_object_t *scope_obj = (async_scope_object_t *) object; async_scope_t *scope = scope_obj->scope; if (scope == NULL) { @@ -1310,26 +1291,32 @@ static HashTable *scope_object_gc(zend_object *object, zval **table, int *num) /* Add finally handlers if present */ if (scope->finally_handlers) { zval *val; - ZEND_HASH_FOREACH_VAL(scope->finally_handlers, val) { + ZEND_HASH_FOREACH_VAL(scope->finally_handlers, val) + { zend_get_gc_buffer_add_zval(buf, val); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } /* Add context ZVALs if present */ if (scope->scope.context) { /* Cast to actual context implementation to access HashTables */ - async_context_t *context = (async_context_t *)scope->scope.context; - + async_context_t *context = (async_context_t *) scope->scope.context; + /* Add all values from context->values HashTable */ zval *val; - ZEND_HASH_FOREACH_VAL(&context->values, val) { + ZEND_HASH_FOREACH_VAL(&context->values, val) + { zend_get_gc_buffer_add_zval(buf, val); - } ZEND_HASH_FOREACH_END(); - + } + ZEND_HASH_FOREACH_END(); + /* Add all object keys from context->keys HashTable */ - ZEND_HASH_FOREACH_VAL(&context->keys, val) { + ZEND_HASH_FOREACH_VAL(&context->keys, val) + { zend_get_gc_buffer_add_zval(buf, val); - } ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); } zend_get_gc_buffer_use(buf, table, num); @@ -1354,9 +1341,8 @@ static void scope_object_free(zend_object *object) // This means we are obligated to cancel the Scope and all its child Scopes along with their coroutines. // However, the Scope itself will not be destroyed. if (false == scope->scope.try_to_dispose(&scope->scope)) { - zend_object *exception = async_new_exception( - async_ce_cancellation_exception, "Scope is being disposed due to object destruction" - ); + zend_object *exception = async_new_exception(async_ce_cancellation_exception, + "Scope is being disposed due to object destruction"); ZEND_ASYNC_SCOPE_CANCEL(&scope->scope, exception, true, ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(&scope->scope)); } @@ -1392,21 +1378,22 @@ static bool scope_can_be_disposed(async_scope_t *scope, bool with_zombies, bool } // If scope is closed or cancelled, it's considered completed - if (false == can_be_disposed - && (ZEND_ASYNC_SCOPE_IS_CLOSED(&scope->scope) || ZEND_ASYNC_SCOPE_IS_CANCELLED(&scope->scope))) { + if (false == can_be_disposed && + (ZEND_ASYNC_SCOPE_IS_CLOSED(&scope->scope) || ZEND_ASYNC_SCOPE_IS_CANCELLED(&scope->scope))) { return true; } // If scope has active coroutines, it's not completed - if ((with_zombies ? (scope->active_coroutines_count + scope->zombie_coroutines_count) : scope->active_coroutines_count) > 0) { + if ((with_zombies ? (scope->active_coroutines_count + scope->zombie_coroutines_count) + : scope->active_coroutines_count) > 0) { return false; } // If a Scope has no active coroutines, // it can be disposed provided that it is either cancelled or // its Zend object has already been destroyed. - if (can_be_disposed - && false == (ZEND_ASYNC_SCOPE_IS_CANCELLED(&scope->scope) || scope->scope.scope_object == NULL)) { + if (can_be_disposed && + false == (ZEND_ASYNC_SCOPE_IS_CANCELLED(&scope->scope) || scope->scope.scope_object == NULL)) { return false; } @@ -1446,9 +1433,10 @@ static void scope_check_completion_and_notify(async_scope_t *scope, bool with_zo } } -static zend_always_inline bool try_to_handle_exception( - async_scope_t *current_scope, async_scope_t *from_scope, zend_object *exception, async_coroutine_t *coroutine -) +static zend_always_inline bool try_to_handle_exception(async_scope_t *current_scope, + async_scope_t *from_scope, + zend_object *exception, + async_coroutine_t *coroutine) { // Fast return: if (current_scope->exception_fci == NULL && current_scope->child_exception_fci == NULL) { @@ -1495,7 +1483,8 @@ static zend_always_inline bool try_to_handle_exception( // If the exception came from another child Scope, // we first try to handle it using the child Scope exception handler. - if (from_scope != NULL && current_scope->child_exception_fci != NULL && current_scope->child_exception_fcc != NULL) { + if (from_scope != NULL && current_scope->child_exception_fci != NULL && + current_scope->child_exception_fcc != NULL) { zend_fcall_info *exception_fci = current_scope->child_exception_fci; diff --git a/scope.h b/scope.h index 3173d2d..3baf51b 100644 --- a/scope.h +++ b/scope.h @@ -18,46 +18,51 @@ #include "php_async.h" -extern zend_class_entry * async_ce_scope; -extern zend_class_entry * async_ce_scope_provider; -extern zend_class_entry * async_ce_spawn_strategy; +extern zend_class_entry *async_ce_scope; +extern zend_class_entry *async_ce_scope_provider; +extern zend_class_entry *async_ce_spawn_strategy; #define ASYNC_SCOPE_MAX_RECURSION_DEPTH 64 typedef struct _async_scope_s async_scope_t; -typedef struct async_coroutines_vector_t { - uint32_t length; /* current number of items */ - uint32_t capacity; /* allocated slots in the array */ - async_coroutine_t **data; /* dynamically allocated array */ +typedef struct async_coroutines_vector_t +{ + uint32_t length; /* current number of items */ + uint32_t capacity; /* allocated slots in the array */ + async_coroutine_t **data; /* dynamically allocated array */ } async_coroutines_vector_t; -struct _async_scope_s { +struct _async_scope_s +{ zend_async_scope_t scope; async_coroutines_vector_t coroutines; uint32_t active_coroutines_count; /* Number of active (non-zombie) coroutines */ uint32_t zombie_coroutines_count; /* Number of zombie coroutines */ - + /* Spawned file and line number */ zend_string *filename; uint32_t lineno; - + /* Exception handlers */ zend_fcall_info *exception_fci; zend_fcall_info_cache *exception_fcc; zend_fcall_info *child_exception_fci; zend_fcall_info_cache *child_exception_fcc; - + /* Finally handlers array (zval callables) - lazy initialization */ HashTable *finally_handlers; }; -typedef struct _async_scope_object_s { +typedef struct _async_scope_object_s +{ union { /* PHP object handle. */ zend_object std; - struct { + + struct + { char _padding[sizeof(zend_object) - sizeof(zval)]; async_scope_t *scope; bool is_cancelled; /* Indicates if the scope is cancelled */ @@ -65,13 +70,14 @@ typedef struct _async_scope_object_s { }; } async_scope_object_t; -typedef struct { +typedef struct +{ zend_coroutine_event_callback_t callback; zend_fcall_info *error_fci; zend_fcall_info_cache *error_fci_cache; } scope_coroutine_callback_t; -zend_async_scope_t * async_new_scope(zend_async_scope_t * parent_scope, const bool with_zend_object); +zend_async_scope_t *async_new_scope(zend_async_scope_t *parent_scope, const bool with_zend_object); void async_register_scope_ce(void); /* Check if coroutine belongs to this scope or any of its child scopes */ @@ -82,4 +88,4 @@ void async_scope_notify_coroutine_finished(async_coroutine_t *coroutine); /* Mark coroutine as zombie and update active count */ void async_scope_mark_coroutine_zombie(async_coroutine_t *coroutine); -#endif //SCOPE_H +#endif // SCOPE_H diff --git a/scope_arginfo.h b/scope_arginfo.h index a751957..35d8f1a 100644 --- a/scope_arginfo.h +++ b/scope_arginfo.h @@ -5,17 +5,17 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Async_ScopeProvider_provide ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_SpawnStrategy_beforeCoroutineEnqueue, 0, 2, IS_ARRAY, 0) - ZEND_ARG_OBJ_INFO(0, coroutine, Async\\Coroutine, 0) - ZEND_ARG_OBJ_INFO(0, scope, Async\\Scope, 0) +ZEND_ARG_OBJ_INFO(0, coroutine, Async\\Coroutine, 0) +ZEND_ARG_OBJ_INFO(0, scope, Async\\Scope, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_SpawnStrategy_afterCoroutineEnqueue, 0, 2, IS_VOID, 0) - ZEND_ARG_OBJ_INFO(0, coroutine, Async\\Coroutine, 0) - ZEND_ARG_OBJ_INFO(0, scope, Async\\Scope, 0) +ZEND_ARG_OBJ_INFO(0, coroutine, Async\\Coroutine, 0) +ZEND_ARG_OBJ_INFO(0, scope, Async\\Scope, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Async_Scope_inherit, 0, 0, Async\\Scope, 0) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, parentScope, Async\\Scope, 1, "null") +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, parentScope, Async\\Scope, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Async_Scope_provideScope, 0, 0, Async\\Scope, 0) @@ -27,21 +27,21 @@ ZEND_END_ARG_INFO() #define arginfo_class_Async_Scope_asNotSafely arginfo_class_Async_Scope_provideScope ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Async_Scope_spawn, 0, 1, Async\\Coroutine, 0) - ZEND_ARG_OBJ_INFO(0, callable, Closure, 0) - ZEND_ARG_VARIADIC_TYPE_INFO(0, params, IS_MIXED, 0) +ZEND_ARG_OBJ_INFO(0, callable, Closure, 0) +ZEND_ARG_VARIADIC_TYPE_INFO(0, params, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Scope_cancel, 0, 0, IS_VOID, 0) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellationException, Async\\CancellationException, 1, "null") +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellationException, Async\\CancellationException, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Scope_awaitCompletion, 0, 1, IS_VOID, 0) - ZEND_ARG_OBJ_INFO(0, cancellation, Async\\Awaitable, 0) +ZEND_ARG_OBJ_INFO(0, cancellation, Async\\Awaitable, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Scope_awaitAfterCancellation, 0, 0, IS_VOID, 0) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, errorHandler, IS_CALLABLE, 1, "null") - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") +ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, errorHandler, IS_CALLABLE, 1, "null") +ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, cancellation, Async\\Awaitable, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Scope_isFinished, 0, 0, _IS_BOOL, 0) @@ -52,13 +52,13 @@ ZEND_END_ARG_INFO() #define arginfo_class_Async_Scope_isCancelled arginfo_class_Async_Scope_isFinished ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Scope_setExceptionHandler, 0, 1, IS_VOID, 0) - ZEND_ARG_TYPE_INFO(0, exceptionHandler, IS_CALLABLE, 0) +ZEND_ARG_TYPE_INFO(0, exceptionHandler, IS_CALLABLE, 0) ZEND_END_ARG_INFO() #define arginfo_class_Async_Scope_setChildScopeExceptionHandler arginfo_class_Async_Scope_setExceptionHandler ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Scope_onFinally, 0, 1, IS_VOID, 0) - ZEND_ARG_OBJ_INFO(0, callback, Closure, 0) +ZEND_ARG_OBJ_INFO(0, callback, Closure, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Scope_dispose, 0, 0, IS_VOID, 0) @@ -67,7 +67,7 @@ ZEND_END_ARG_INFO() #define arginfo_class_Async_Scope_disposeSafely arginfo_class_Async_Scope_dispose ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Scope_disposeAfterTimeout, 0, 1, IS_VOID, 0) - ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0) +ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Async_Scope_getChildScopes, 0, 0, IS_ARRAY, 0) @@ -92,37 +92,76 @@ ZEND_METHOD(Async_Scope, disposeSafely); ZEND_METHOD(Async_Scope, disposeAfterTimeout); ZEND_METHOD(Async_Scope, getChildScopes); -static const zend_function_entry class_Async_ScopeProvider_methods[] = { - ZEND_RAW_FENTRY("provideScope", NULL, arginfo_class_Async_ScopeProvider_provideScope, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT, NULL, NULL) - ZEND_FE_END -}; - -static const zend_function_entry class_Async_SpawnStrategy_methods[] = { - ZEND_RAW_FENTRY("beforeCoroutineEnqueue", NULL, arginfo_class_Async_SpawnStrategy_beforeCoroutineEnqueue, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT, NULL, NULL) - ZEND_RAW_FENTRY("afterCoroutineEnqueue", NULL, arginfo_class_Async_SpawnStrategy_afterCoroutineEnqueue, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT, NULL, NULL) - ZEND_FE_END -}; +static const zend_function_entry class_Async_ScopeProvider_methods[] = { ZEND_RAW_FENTRY( + "provideScope", + NULL, + arginfo_class_Async_ScopeProvider_provideScope, + ZEND_ACC_PUBLIC | ZEND_ACC_ABSTRACT, + NULL, + NULL) ZEND_FE_END }; + +static const zend_function_entry class_Async_SpawnStrategy_methods[] = { ZEND_RAW_FENTRY( + "beforeCoroutineEnqueue", + NULL, + arginfo_class_Async_SpawnStrategy_beforeCoroutineEnqueue, + ZEND_ACC_PUBLIC | ZEND_ACC_ABSTRACT, + NULL, + NULL) ZEND_RAW_FENTRY("afterCoroutineEnqueue", + NULL, + arginfo_class_Async_SpawnStrategy_afterCoroutineEnqueue, + ZEND_ACC_PUBLIC | ZEND_ACC_ABSTRACT, + NULL, + NULL) ZEND_FE_END }; static const zend_function_entry class_Async_Scope_methods[] = { - ZEND_ME(Async_Scope, inherit, arginfo_class_Async_Scope_inherit, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - ZEND_ME(Async_Scope, provideScope, arginfo_class_Async_Scope_provideScope, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, __construct, arginfo_class_Async_Scope___construct, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, asNotSafely, arginfo_class_Async_Scope_asNotSafely, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, spawn, arginfo_class_Async_Scope_spawn, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, cancel, arginfo_class_Async_Scope_cancel, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, awaitCompletion, arginfo_class_Async_Scope_awaitCompletion, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, awaitAfterCancellation, arginfo_class_Async_Scope_awaitAfterCancellation, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, isFinished, arginfo_class_Async_Scope_isFinished, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, isClosed, arginfo_class_Async_Scope_isClosed, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, isCancelled, arginfo_class_Async_Scope_isCancelled, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, setExceptionHandler, arginfo_class_Async_Scope_setExceptionHandler, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, setChildScopeExceptionHandler, arginfo_class_Async_Scope_setChildScopeExceptionHandler, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, onFinally, arginfo_class_Async_Scope_onFinally, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, dispose, arginfo_class_Async_Scope_dispose, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, disposeSafely, arginfo_class_Async_Scope_disposeSafely, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, disposeAfterTimeout, arginfo_class_Async_Scope_disposeAfterTimeout, ZEND_ACC_PUBLIC) - ZEND_ME(Async_Scope, getChildScopes, arginfo_class_Async_Scope_getChildScopes, ZEND_ACC_PUBLIC) - ZEND_FE_END + ZEND_ME(Async_Scope, inherit, arginfo_class_Async_Scope_inherit, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) ZEND_ME( + Async_Scope, + provideScope, + arginfo_class_Async_Scope_provideScope, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Scope, __construct, arginfo_class_Async_Scope___construct, ZEND_ACC_PUBLIC) + ZEND_ME(Async_Scope, asNotSafely, arginfo_class_Async_Scope_asNotSafely, ZEND_ACC_PUBLIC) ZEND_ME( + Async_Scope, spawn, arginfo_class_Async_Scope_spawn, ZEND_ACC_PUBLIC) + ZEND_ME(Async_Scope, cancel, arginfo_class_Async_Scope_cancel, ZEND_ACC_PUBLIC) ZEND_ME( + Async_Scope, + awaitCompletion, + arginfo_class_Async_Scope_awaitCompletion, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Scope, + awaitAfterCancellation, + arginfo_class_Async_Scope_awaitAfterCancellation, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Scope, + isFinished, + arginfo_class_Async_Scope_isFinished, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Scope, isClosed, arginfo_class_Async_Scope_isClosed, ZEND_ACC_PUBLIC) ZEND_ME( + Async_Scope, + isCancelled, + arginfo_class_Async_Scope_isCancelled, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Scope, + setExceptionHandler, + arginfo_class_Async_Scope_setExceptionHandler, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Scope, + setChildScopeExceptionHandler, + arginfo_class_Async_Scope_setChildScopeExceptionHandler, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Scope, + onFinally, + arginfo_class_Async_Scope_onFinally, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Scope, + dispose, + arginfo_class_Async_Scope_dispose, + ZEND_ACC_PUBLIC) ZEND_ME(Async_Scope, + disposeSafely, + arginfo_class_Async_Scope_disposeSafely, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Scope, + disposeAfterTimeout, + arginfo_class_Async_Scope_disposeAfterTimeout, + ZEND_ACC_PUBLIC) + ZEND_ME(Async_Scope, + getChildScopes, + arginfo_class_Async_Scope_getChildScopes, + ZEND_ACC_PUBLIC) ZEND_FE_END }; static zend_class_entry *register_class_Async_ScopeProvider(void) @@ -151,12 +190,17 @@ static zend_class_entry *register_class_Async_Scope(zend_class_entry *class_entr zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "Async", "Scope", class_Async_Scope_methods); - class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + class_entry = zend_register_internal_class_with_flags( + &ce, NULL, ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES | ZEND_ACC_NOT_SERIALIZABLE); zend_class_implements(class_entry, 1, class_entry_Async_ScopeProvider); - zend_string *attribute_name_Override_func_providescope_0 = zend_string_init_interned("Override", sizeof("Override") - 1, 1); - zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "providescope", sizeof("providescope") - 1), attribute_name_Override_func_providescope_0, 0); + zend_string *attribute_name_Override_func_providescope_0 = + zend_string_init_interned("Override", sizeof("Override") - 1, 1); + zend_add_function_attribute( + zend_hash_str_find_ptr(&class_entry->function_table, "providescope", sizeof("providescope") - 1), + attribute_name_Override_func_providescope_0, + 0); zend_string_release(attribute_name_Override_func_providescope_0); return class_entry; diff --git a/zend_common.c b/zend_common.c index 7f32075..8a42c2e 100644 --- a/zend_common.c +++ b/zend_common.c @@ -19,10 +19,10 @@ #include "exceptions.h" -static zend_function* create_fn = NULL; -static zend_function* get_fn = NULL; +static zend_function *create_fn = NULL; +static zend_function *get_fn = NULL; -void zend_exception_to_warning(const char * format, const bool clean) +void zend_exception_to_warning(const char *format, const bool clean) { if (EG(exception) == NULL) { return; @@ -37,9 +37,8 @@ void zend_exception_to_warning(const char * format, const bool clean) } zval rv; - const zval *message = zend_read_property_ex( - EG(exception)->ce, EG(exception), zend_known_strings[ZEND_STR_MESSAGE], 0, &rv - ); + const zval *message = + zend_read_property_ex(EG(exception)->ce, EG(exception), zend_known_strings[ZEND_STR_MESSAGE], 0, &rv); if (message == NULL) { async_warning(format, "No message"); @@ -52,16 +51,15 @@ void zend_exception_to_warning(const char * format, const bool clean) } } -zend_string * zend_current_exception_get_message(const bool clean) +zend_string *zend_current_exception_get_message(const bool clean) { if (EG(exception) == NULL) { return NULL; } zval rv; - const zval *message = zend_read_property_ex( - EG(exception)->ce, EG(exception), zend_known_strings[ZEND_STR_MESSAGE], 0, &rv - ); + const zval *message = + zend_read_property_ex(EG(exception)->ce, EG(exception), zend_known_strings[ZEND_STR_MESSAGE], 0, &rv); if (clean) { zend_clear_exception(); @@ -74,16 +72,15 @@ zend_string * zend_current_exception_get_message(const bool clean) } } -zend_string * zend_current_exception_get_file(void) +zend_string *zend_current_exception_get_file(void) { if (EG(exception) == NULL) { return NULL; } zval rv; - const zval *file = zend_read_property_ex( - EG(exception)->ce, EG(exception), zend_known_strings[ZEND_STR_FILE], 0, &rv - ); + const zval *file = + zend_read_property_ex(EG(exception)->ce, EG(exception), zend_known_strings[ZEND_STR_FILE], 0, &rv); if (file != NULL && Z_TYPE_P(file) == IS_STRING) { return Z_STR_P(file); @@ -99,9 +96,8 @@ uint32_t zend_current_exception_get_line(void) } zval rv; - const zval *line = zend_read_property_ex( - EG(exception)->ce, EG(exception), zend_known_strings[ZEND_STR_LINE], 0, &rv - ); + const zval *line = + zend_read_property_ex(EG(exception)->ce, EG(exception), zend_known_strings[ZEND_STR_LINE], 0, &rv); if (line != NULL && Z_TYPE_P(line) == IS_LONG) { return Z_LVAL_P(line); @@ -110,7 +106,7 @@ uint32_t zend_current_exception_get_line(void) } } -zend_object* zend_exception_merge(zend_object *exception, bool to_previous, bool transfer_error) +zend_object *zend_exception_merge(zend_object *exception, bool to_previous, bool transfer_error) { zend_exception_save(); zend_exception_restore(); @@ -142,7 +138,7 @@ zend_object* zend_exception_merge(zend_object *exception, bool to_previous, bool return exception; } -void async_warning(const char * format, ...) +void async_warning(const char *format, ...) { va_list args; va_start(args, format); @@ -152,7 +148,7 @@ void async_warning(const char * format, ...) zend_string_release(message); } -void zend_new_weak_reference_from(const zval* referent, zval * retval) +void zend_new_weak_reference_from(const zval *referent, zval *retval) { if (UNEXPECTED(EG(exception))) { ZVAL_UNDEF(retval); @@ -171,7 +167,7 @@ void zend_new_weak_reference_from(const zval* referent, zval * retval) ZVAL_UNDEF(retval); - zend_call_known_function(create_fn, NULL, zend_ce_weakref, retval, 1, (zval*) referent, NULL); + zend_call_known_function(create_fn, NULL, zend_ce_weakref, retval, 1, (zval *) referent, NULL); if (UNEXPECTED(Z_TYPE_P(retval) == IS_NULL || Z_ISUNDEF_P(retval))) { async_warning("Failed to invoke WeakReference::create"); @@ -186,7 +182,7 @@ void zend_new_weak_reference_from(const zval* referent, zval * retval) * @warning The method may return a ZVAL with the type NULL! * @warning You must call the dtor if the result is no longer needed! */ -void zend_resolve_weak_reference(zval* weak_reference, zval* retval) +void zend_resolve_weak_reference(zval *weak_reference, zval *retval) { if (!get_fn) { @@ -214,7 +210,7 @@ zif_handler zend_hook_php_function(const char *name, const size_t len, zif_handl return original_handler; } -zif_handler zend_replace_method(zend_object * object, const char * method, const size_t len, const zif_handler handler) +zif_handler zend_replace_method(zend_object *object, const char *method, const size_t len, const zif_handler handler) { zif_handler original_handler = NULL; zend_function *func = zend_hash_str_find_ptr(&object->ce->function_table, method, len); @@ -229,15 +225,15 @@ zif_handler zend_replace_method(zend_object * object, const char * method, const return original_handler; } -void zend_get_function_name_by_fci(zend_fcall_info * fci, zend_fcall_info_cache *fci_cache, zend_string **name) +void zend_get_function_name_by_fci(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string **name) { if (fci_cache != NULL && fci_cache->function_handler != NULL) { - *name = fci_cache->function_handler->common.function_name; - } else if (fci != NULL && Z_TYPE(fci->function_name) != IS_UNDEF) { - *name = Z_STR(fci->function_name); - } else { - *name = NULL; - } + *name = fci_cache->function_handler->common.function_name; + } else if (fci != NULL && Z_TYPE(fci->function_name) != IS_UNDEF) { + *name = Z_STR(fci->function_name); + } else { + *name = NULL; + } } void zend_free_fci(zend_fcall_info *fci, zend_fcall_info_cache *fcc) @@ -262,15 +258,17 @@ void zend_free_fci(zend_fcall_info *fci, zend_fcall_info_cache *fcc) } } -void zend_copy_fci(zend_fcall_info *dest_fci, zend_fcall_info_cache *dest_fcc, - zend_fcall_info *src_fci, zend_fcall_info_cache *src_fcc) +void zend_copy_fci(zend_fcall_info *dest_fci, + zend_fcall_info_cache *dest_fcc, + zend_fcall_info *src_fci, + zend_fcall_info_cache *src_fcc) { // Copy FCI *dest_fci = *src_fci; - + // Copy function name with proper refcount ZVAL_COPY(&dest_fci->function_name, &src_fci->function_name); - + // Copy parameters if any if (src_fci->param_count > 0 && src_fci->params != NULL) { dest_fci->params = safe_emalloc(src_fci->param_count, sizeof(zval), 0); @@ -280,13 +278,13 @@ void zend_copy_fci(zend_fcall_info *dest_fci, zend_fcall_info_cache *dest_fcc, } else { dest_fci->params = NULL; } - + // Copy named params if any if (src_fci->named_params != NULL) { dest_fci->named_params = src_fci->named_params; GC_ADDREF(src_fci->named_params); } - + // Copy FCC *dest_fcc = *src_fcc; } diff --git a/zend_common.h b/zend_common.h index 1175144..d891907 100644 --- a/zend_common.h +++ b/zend_common.h @@ -20,14 +20,22 @@ #include "zend_exceptions.h" #include "zend_interfaces.h" -#define IF_THROW_RETURN_VOID if(UNEXPECTED(EG(exception) != NULL)) { return; } -#define IF_THROW_FINALLY if(UNEXPECTED(EG(exception) != NULL)) { goto finally; } -#define IF_THROW_RETURN(value) if(UNEXPECTED(EG(exception) != NULL)) { return value; } +#define IF_THROW_RETURN_VOID \ + if (UNEXPECTED(EG(exception) != NULL)) { \ + return; \ + } +#define IF_THROW_FINALLY \ + if (UNEXPECTED(EG(exception) != NULL)) { \ + goto finally; \ + } +#define IF_THROW_RETURN(value) \ + if (UNEXPECTED(EG(exception) != NULL)) { \ + return value; \ + } #define DEFINE_VAR(type, var) type *var = (type *) emalloc(sizeof(type)); - -zend_always_inline static void zval_move(zval * destination, const zval * source) +zend_always_inline static void zval_move(zval *destination, const zval *source) { if (Z_ISREF_P(source)) { source = Z_REFVAL_P(source); @@ -37,7 +45,7 @@ zend_always_inline static void zval_move(zval * destination, const zval * source ZVAL_COPY_VALUE(destination, source); } -zend_always_inline static void zval_copy(zval * destination, zval * source) +zend_always_inline static void zval_copy(zval *destination, zval *source) { if (Z_ISREF_P(source)) { source = Z_REFVAL_P(source); @@ -48,7 +56,7 @@ zend_always_inline static void zval_copy(zval * destination, zval * source) Z_TRY_ADDREF_P(source); } -zend_always_inline static void zval_assign(zval * destination, zval * source) +zend_always_inline static void zval_assign(zval *destination, zval *source) { if (Z_ISREF_P(source)) { source = Z_REFVAL_P(source); @@ -58,18 +66,18 @@ zend_always_inline static void zval_assign(zval * destination, zval * source) ZVAL_COPY_VALUE(destination, source); } -zend_always_inline static void zval_null(zval * destination) +zend_always_inline static void zval_null(zval *destination) { zval_ptr_dtor(destination); ZVAL_NULL(destination); } -zend_always_inline static void zval_property_move(zval * property, const zval * value) +zend_always_inline static void zval_property_move(zval *property, const zval *value) { if (EXPECTED(Z_TYPE_P(property) != IS_UNDEF)) { zval_ptr_dtor(property); } else { - Z_PROP_FLAG_P(property) &= ~(IS_PROP_UNINIT|IS_PROP_REINITABLE); + Z_PROP_FLAG_P(property) &= ~(IS_PROP_UNINIT | IS_PROP_REINITABLE); } if (Z_ISREF_P(value)) { @@ -79,12 +87,12 @@ zend_always_inline static void zval_property_move(zval * property, const zval * ZVAL_COPY_VALUE(property, value); } -zend_always_inline static void zval_property_copy(zval * property, zval * value) +zend_always_inline static void zval_property_copy(zval *property, zval *value) { if (EXPECTED(Z_TYPE_P(property) != IS_UNDEF)) { zval_ptr_dtor(property); } else { - Z_PROP_FLAG_P(property) &= ~(IS_PROP_UNINIT|IS_PROP_REINITABLE); + Z_PROP_FLAG_P(property) &= ~(IS_PROP_UNINIT | IS_PROP_REINITABLE); } if (Z_ISREF_P(value)) { @@ -95,7 +103,7 @@ zend_always_inline static void zval_property_copy(zval * property, zval * value) Z_TRY_ADDREF_P(value); } -zend_always_inline static void zend_object_ptr_copy(zend_object * destination, zend_object * source) +zend_always_inline static void zend_object_ptr_copy(zend_object *destination, zend_object *source) { if (EXPECTED(destination != NULL)) { OBJ_RELEASE(destination); @@ -105,7 +113,7 @@ zend_always_inline static void zend_object_ptr_copy(zend_object * destination, z GC_ADDREF(source); } -zend_always_inline static void zend_object_ptr_reset(zend_object * destination) +zend_always_inline static void zend_object_ptr_reset(zend_object *destination) { if (EXPECTED(destination != NULL)) { OBJ_RELEASE(destination); @@ -116,11 +124,12 @@ zend_always_inline static void zend_object_ptr_reset(zend_object * destination) #define ZEND_OBJECT_ALLOC_EX(obj_size, ce) pecalloc(1, obj_size, 0) -#define DEFINE_ZEND_RAW_OBJECT(type, var, class_entry) type *var = (type *) ZEND_OBJECT_ALLOC_EX(sizeof(type), class_entry) +#define DEFINE_ZEND_RAW_OBJECT(type, var, class_entry) \ + type *var = (type *) ZEND_OBJECT_ALLOC_EX(sizeof(type), class_entry) -zend_always_inline zend_object* zend_object_internal_create(const size_t obj_size, zend_class_entry *class_entry) +zend_always_inline zend_object *zend_object_internal_create(const size_t obj_size, zend_class_entry *class_entry) { - zend_object * object = ZEND_OBJECT_ALLOC_EX(obj_size, class_entry); + zend_object *object = ZEND_OBJECT_ALLOC_EX(obj_size, class_entry); zend_object_std_init(object, class_entry); object_properties_init(object, class_entry); @@ -128,9 +137,11 @@ zend_always_inline zend_object* zend_object_internal_create(const size_t obj_siz return object; } -#define DEFINE_ZEND_INTERNAL_OBJECT(type, var, class_entry) type *var = (type *) zend_object_internal_create(sizeof(type), class_entry) +#define DEFINE_ZEND_INTERNAL_OBJECT(type, var, class_entry) \ + type *var = (type *) zend_object_internal_create(sizeof(type), class_entry) -zend_always_inline static void zend_property_array_index_update(zval *property, zend_ulong h, zval *pData, const bool is_transfer_data) +zend_always_inline static void +zend_property_array_index_update(zval *property, zend_ulong h, zval *pData, const bool is_transfer_data) { SEPARATE_ARRAY(property); @@ -167,14 +178,14 @@ zend_always_inline static void zend_apply_current_filename_and_line(zend_string } } -void zend_exception_to_warning(const char * format, const bool clean); +void zend_exception_to_warning(const char *format, const bool clean); -zend_string * zend_current_exception_get_message(const bool clean); -zend_string * zend_current_exception_get_file(void); +zend_string *zend_current_exception_get_message(const bool clean); +zend_string *zend_current_exception_get_file(void); uint32_t zend_current_exception_get_line(void); -zend_object* zend_exception_merge(zend_object * exception, bool to_previous, bool transfer_error); +zend_object *zend_exception_merge(zend_object *exception, bool to_previous, bool transfer_error); -void async_warning(const char * format, ...); +void async_warning(const char *format, ...); /** * Creates a new weak reference to the given zval. @@ -197,7 +208,7 @@ void async_warning(const char * format, ...); * - The caller is responsible for managing the returned zval, which must be freed using * `zval_ptr_dtor()` when no longer needed. */ -void zend_new_weak_reference_from(const zval* referent, zval * retval); +void zend_new_weak_reference_from(const zval *referent, zval *retval); /** * Resolves a weak reference to its underlying object. @@ -220,18 +231,18 @@ void zend_new_weak_reference_from(const zval* referent, zval * retval); * - The `retval` must be initialized and will contain the resulting object or NULL. * - You must call `zval_ptr_dtor()` to decrement the reference count of the returned object. */ -void zend_resolve_weak_reference(zval* weak_reference, zval* retval); +void zend_resolve_weak_reference(zval *weak_reference, zval *retval); zif_handler zend_hook_php_function(const char *name, const size_t len, zif_handler new_function); -zif_handler zend_replace_method(zend_object * object, const char * method, const size_t len, const zif_handler handler); +zif_handler zend_replace_method(zend_object *object, const char *method, const size_t len, const zif_handler handler); -zend_always_inline zif_handler zend_replace_to_string_method(zend_object * object, const zif_handler handler) +zend_always_inline zif_handler zend_replace_to_string_method(zend_object *object, const zif_handler handler) { return zend_replace_method(object, ZEND_STRL("__toString"), handler); } -void zend_get_function_name_by_fci(zend_fcall_info * fci, zend_fcall_info_cache *fci_cache, zend_string **name); +void zend_get_function_name_by_fci(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string **name); /** * Frees memory allocated for zend_fcall_info and zend_fcall_info_cache structures. @@ -251,7 +262,9 @@ void zend_free_fci(zend_fcall_info *fci, zend_fcall_info_cache *fcc); * @param src_fci Source fci structure to copy from * @param src_fcc Source fcc structure to copy from */ -void zend_copy_fci(zend_fcall_info *dest_fci, zend_fcall_info_cache *dest_fcc, - zend_fcall_info *src_fci, zend_fcall_info_cache *src_fcc); +void zend_copy_fci(zend_fcall_info *dest_fci, + zend_fcall_info_cache *dest_fcc, + zend_fcall_info *src_fci, + zend_fcall_info_cache *src_fcc); -#endif //ASYNC_ZEND_COMMON_H +#endif // ASYNC_ZEND_COMMON_H