Skip to content

Commit de45e8c

Browse files
committed
+ async_spawn_and_throw
1 parent 2593f66 commit de45e8c

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

Zend/zend_async_API.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ static void enqueue_coroutine(zend_coroutine_t *coroutine)
4242
ASYNC_THROW_ERROR("Async API is not enabled");
4343
}
4444

45+
static bool spawn_and_throw(zend_object *exception, zend_async_scope_t *scope, int32_t priority)
46+
{
47+
ASYNC_THROW_ERROR("Async API is not enabled");
48+
return false;
49+
}
50+
4551
static zend_async_context_t * new_context(void)
4652
{
4753
ASYNC_THROW_ERROR("Context API is not enabled");
@@ -74,6 +80,7 @@ zend_async_suspend_t zend_async_suspend_fn = suspend;
7480
zend_async_enqueue_coroutine_t zend_async_enqueue_coroutine_fn = enqueue_coroutine;
7581
zend_async_resume_t zend_async_resume_fn = NULL;
7682
zend_async_cancel_t zend_async_cancel_fn = NULL;
83+
zend_async_spawn_and_throw_t zend_async_spawn_and_throw_fn = spawn_and_throw;
7784
zend_async_shutdown_t zend_async_shutdown_fn = NULL;
7885
zend_async_get_coroutines_t zend_async_get_coroutines_fn = NULL;
7986
zend_async_add_microtask_t zend_async_add_microtask_fn = NULL;
@@ -202,6 +209,7 @@ ZEND_API bool zend_async_scheduler_register(
202209
zend_async_enqueue_coroutine_t enqueue_coroutine_fn,
203210
zend_async_resume_t resume_fn,
204211
zend_async_cancel_t cancel_fn,
212+
zend_async_spawn_and_throw_t spawn_and_throw_fn,
205213
zend_async_shutdown_t shutdown_fn,
206214
zend_async_get_coroutines_t get_coroutines_fn,
207215
zend_async_add_microtask_t add_microtask_fn,
@@ -237,6 +245,7 @@ ZEND_API bool zend_async_scheduler_register(
237245
zend_async_enqueue_coroutine_fn = enqueue_coroutine_fn;
238246
zend_async_resume_fn = resume_fn;
239247
zend_async_cancel_fn = cancel_fn;
248+
zend_async_spawn_and_throw_fn = spawn_and_throw_fn;
240249
zend_async_shutdown_fn = shutdown_fn;
241250
zend_async_get_coroutines_fn = get_coroutines_fn;
242251
zend_async_add_microtask_fn = add_microtask_fn;

Zend/zend_async_API.h

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ typedef void (*zend_async_suspend_t)(bool from_main);
191191
typedef void (*zend_async_enqueue_coroutine_t)(zend_coroutine_t *coroutine);
192192
typedef void (*zend_async_resume_t)(zend_coroutine_t *coroutine, zend_object * error, const bool transfer_error);
193193
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);
194195
typedef void (*zend_async_shutdown_t)(void);
195196
typedef zend_array* (*zend_async_get_coroutines_t)(void);
196197
typedef void (*zend_async_add_microtask_t)(zend_async_microtask_t *microtask);
@@ -296,10 +297,26 @@ struct _zend_async_microtask_s {
296297
/// Async iterator structures
297298
///////////////////////////////////////////////////////////////////
298299

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+
299318
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
303320
};
304321

305322
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;
10831100
ZEND_API extern zend_async_enqueue_coroutine_t zend_async_enqueue_coroutine_fn;
10841101
ZEND_API extern zend_async_resume_t zend_async_resume_fn;
10851102
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;
10861104
ZEND_API extern zend_async_shutdown_t zend_async_shutdown_fn;
10871105
ZEND_API extern zend_async_get_coroutines_t zend_async_get_coroutines_fn;
10881106
ZEND_API extern zend_async_add_microtask_t zend_async_add_microtask_fn;
@@ -1155,6 +1173,7 @@ ZEND_API bool zend_async_scheduler_register(
11551173
zend_async_enqueue_coroutine_t enqueue_coroutine_fn,
11561174
zend_async_resume_t resume_fn,
11571175
zend_async_cancel_t cancel_fn,
1176+
zend_async_spawn_and_throw_t spawn_and_throw_fn,
11581177
zend_async_shutdown_t shutdown_fn,
11591178
zend_async_get_coroutines_t get_coroutines_fn,
11601179
zend_async_add_microtask_t add_microtask_fn,
@@ -1286,6 +1305,19 @@ END_EXTERN_C()
12861305
#define ZEND_ASYNC_RESUME_WITH_ERROR(coroutine, error, transfer_error) zend_async_resume_fn(coroutine, error, transfer_error)
12871306
#define ZEND_ASYNC_CANCEL(coroutine, error, transfer_error) zend_async_cancel_fn(coroutine, error, transfer_error, false)
12881307
#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)
12891321
#define ZEND_ASYNC_SHUTDOWN() zend_async_shutdown_fn()
12901322
#define ZEND_ASYNC_GET_COROUTINES() zend_async_get_coroutines_fn()
12911323
#define ZEND_ASYNC_ADD_MICROTASK(microtask) zend_async_add_microtask_fn(microtask)

0 commit comments

Comments
 (0)