@@ -191,6 +191,7 @@ typedef void (*zend_async_suspend_t)(bool from_main);
191
191
typedef void (* zend_async_enqueue_coroutine_t )(zend_coroutine_t * coroutine );
192
192
typedef void (* zend_async_resume_t )(zend_coroutine_t * coroutine , zend_object * error , const bool transfer_error );
193
193
typedef void (* zend_async_cancel_t )(zend_coroutine_t * coroutine , zend_object * error , bool transfer_error , const bool is_safely );
194
+ typedef bool (* zend_async_spawn_and_throw_t )(zend_object * exception , zend_async_scope_t * scope , int32_t priority );
194
195
typedef void (* zend_async_shutdown_t )(void );
195
196
typedef zend_array * (* zend_async_get_coroutines_t )(void );
196
197
typedef void (* zend_async_add_microtask_t )(zend_async_microtask_t * microtask );
@@ -296,10 +297,26 @@ struct _zend_async_microtask_s {
296
297
/// Async iterator structures
297
298
///////////////////////////////////////////////////////////////////
298
299
300
+ typedef void (* zend_async_iterator_method_t )(zend_async_iterator_t * iterator );
301
+
302
+ #define ZEND_ASYNC_ITERATOR_FIELDS \
303
+ zend_async_microtask_t microtask; \
304
+ zend_async_scope_t *scope; \
305
+ /* NULLABLE. Custom data for the iterator, can be used to store additional information. */ \
306
+ void * extended_data ; \
307
+ /* NULLABLE. An additional destructor that will be called. */ \
308
+ zend_async_iterator_method_t extended_dtor ; \
309
+ /* A method that starts the iterator in the current coroutine. */ \
310
+ zend_async_iterator_method_t run ; \
311
+ /* A method that starts the iterator in a separate coroutine with the specified priority. */ \
312
+ void (* run_in_coroutine )(zend_async_iterator_t * iterator , int32_t priority ); \
313
+ /* The maximum number of concurrent tasks that can be executed at the same time */ \
314
+ unsigned int concurrency ; \
315
+ /* Priority for coroutines created by this iterator */ \
316
+ int32_t priority ;
317
+
299
318
struct _zend_async_iterator_s {
300
- zend_async_microtask_t microtask ;
301
- void (* run )(zend_async_iterator_t * iterator );
302
- void (* run_in_coroutine )(zend_async_iterator_t * iterator , int32_t priority );
319
+ ZEND_ASYNC_ITERATOR_FIELDS
303
320
};
304
321
305
322
typedef zend_result (* zend_async_iterator_handler_t )(zend_async_iterator_t * iterator , zval * current , zval * key );
@@ -1083,6 +1100,7 @@ ZEND_API extern zend_async_suspend_t zend_async_suspend_fn;
1083
1100
ZEND_API extern zend_async_enqueue_coroutine_t zend_async_enqueue_coroutine_fn ;
1084
1101
ZEND_API extern zend_async_resume_t zend_async_resume_fn ;
1085
1102
ZEND_API extern zend_async_cancel_t zend_async_cancel_fn ;
1103
+ ZEND_API extern zend_async_spawn_and_throw_t zend_async_spawn_and_throw_fn ;
1086
1104
ZEND_API extern zend_async_shutdown_t zend_async_shutdown_fn ;
1087
1105
ZEND_API extern zend_async_get_coroutines_t zend_async_get_coroutines_fn ;
1088
1106
ZEND_API extern zend_async_add_microtask_t zend_async_add_microtask_fn ;
@@ -1155,6 +1173,7 @@ ZEND_API bool zend_async_scheduler_register(
1155
1173
zend_async_enqueue_coroutine_t enqueue_coroutine_fn ,
1156
1174
zend_async_resume_t resume_fn ,
1157
1175
zend_async_cancel_t cancel_fn ,
1176
+ zend_async_spawn_and_throw_t spawn_and_throw_fn ,
1158
1177
zend_async_shutdown_t shutdown_fn ,
1159
1178
zend_async_get_coroutines_t get_coroutines_fn ,
1160
1179
zend_async_add_microtask_t add_microtask_fn ,
@@ -1286,6 +1305,19 @@ END_EXTERN_C()
1286
1305
#define ZEND_ASYNC_RESUME_WITH_ERROR (coroutine , error , transfer_error ) zend_async_resume_fn(coroutine, error, transfer_error)
1287
1306
#define ZEND_ASYNC_CANCEL (coroutine , error , transfer_error ) zend_async_cancel_fn(coroutine, error, transfer_error, false)
1288
1307
#define ZEND_ASYNC_CANCEL_EX (coroutine , error , transfer_error , is_safely ) zend_async_cancel_fn(coroutine, error, transfer_error, is_safely)
1308
+
1309
+ /**
1310
+ * Spawns a new coroutine and throws the specified exception within it.
1311
+ *
1312
+ * This creates a dedicated coroutine for exception handling, ensuring proper
1313
+ * scope-based error propagation when exceptions occur in microtasks or other
1314
+ * contexts where direct throwing would bypass scope exception handling.
1315
+ *
1316
+ * @param exception The exception object to throw in the new coroutine
1317
+ * @param scope Target scope for the coroutine (NULL for current scope)
1318
+ * @param priority Priority level for the exception-throwing coroutine
1319
+ */
1320
+ #define ZEND_ASYNC_SPAWN_AND_THROW (exception , scope , priority ) zend_async_spawn_and_throw_fn(exception, scope, priority)
1289
1321
#define ZEND_ASYNC_SHUTDOWN () zend_async_shutdown_fn()
1290
1322
#define ZEND_ASYNC_GET_COROUTINES () zend_async_get_coroutines_fn()
1291
1323
#define ZEND_ASYNC_ADD_MICROTASK (microtask ) zend_async_add_microtask_fn(microtask)
0 commit comments