@@ -113,6 +113,9 @@ static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state *
113
113
EG (active_fiber ) = state -> active_fiber ;
114
114
}
115
115
116
+ #ifdef ZEND_FIBER_UCONTEXT
117
+ # include <ucontext.h>
118
+ #else
116
119
/* boost_context_data is our customized definition of struct transfer_t as
117
120
* provided by boost.context in fcontext.hpp:
118
121
*
@@ -125,12 +128,13 @@ static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state *
125
128
126
129
typedef struct {
127
130
void * handle ;
128
- zend_fiber_transfer * transfer ;
131
+ zend_fiber_context * context ;
129
132
} boost_context_data ;
130
133
131
134
/* These functions are defined in assembler files provided by boost.context (located in "Zend/asm"). */
132
135
extern void * make_fcontext (void * sp , size_t size , void (* fn )(boost_context_data ));
133
- extern boost_context_data jump_fcontext (void * to , zend_fiber_transfer * data );
136
+ extern boost_context_data jump_fcontext (void * to , zend_fiber_context * context );
137
+ #endif
134
138
135
139
ZEND_API zend_class_entry * zend_ce_fiber ;
136
140
static zend_class_entry * zend_ce_fiber_error ;
@@ -245,27 +249,21 @@ static void zend_fiber_stack_free(zend_fiber_stack *stack)
245
249
efree (stack );
246
250
}
247
251
248
- static ZEND_NORETURN void zend_fiber_trampoline (boost_context_data data )
252
+ static ZEND_NORETURN void zend_fiber_trampoline (zend_fiber_context * context )
249
253
{
250
- zend_fiber_context * from = data .transfer -> context ;
254
+ /* Initialize transfer struct with a copy of passed data. */
255
+ zend_fiber_transfer transfer = * context -> transfer ;
256
+ zend_fiber_context * from = transfer .context ;
251
257
252
258
#ifdef __SANITIZE_ADDRESS__
253
259
__sanitizer_finish_switch_fiber (NULL , & from -> stack -> asan_pointer , & from -> stack -> asan_size );
254
260
#endif
255
261
256
- /* Get a hold of the context that resumed us and update its handle to allow for symmetric coroutines. */
257
- from -> handle = data .handle ;
258
-
259
- /* Initialize transfer struct with a copy of passed data. */
260
- zend_fiber_transfer transfer = * data .transfer ;
261
-
262
262
/* Ensure that previous fiber will be cleaned up (needed by symmetric coroutines). */
263
263
if (from -> status == ZEND_FIBER_STATUS_DEAD ) {
264
264
zend_fiber_destroy_context (from );
265
265
}
266
266
267
- zend_fiber_context * context = EG (current_fiber_context );
268
-
269
267
context -> function (& transfer );
270
268
context -> status = ZEND_FIBER_STATUS_DEAD ;
271
269
@@ -276,6 +274,19 @@ static ZEND_NORETURN void zend_fiber_trampoline(boost_context_data data)
276
274
abort ();
277
275
}
278
276
277
+ #ifndef ZEND_FIBER_UCONTEXT
278
+ static ZEND_NORETURN void zend_fiber_start (boost_context_data data )
279
+ {
280
+ zend_fiber_context * context = data .context ;
281
+
282
+ /* Get the context that resumed us and update its handle to allow for symmetric coroutines. */
283
+ zend_fiber_context * from = context -> transfer -> context ;
284
+ from -> handle = data .handle ;
285
+
286
+ zend_fiber_trampoline (context );
287
+ }
288
+ #endif
289
+
279
290
ZEND_API void zend_fiber_switch_block (void )
280
291
{
281
292
++ zend_fiber_switch_blocking ;
@@ -300,11 +311,25 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, z
300
311
return false;
301
312
}
302
313
314
+ #ifdef ZEND_FIBER_UCONTEXT
315
+ ucontext_t * handle = emalloc (sizeof (ucontext_t ));
316
+ getcontext (handle );
317
+
318
+ handle -> uc_stack .ss_size = context -> stack -> size ;
319
+ handle -> uc_stack .ss_sp = context -> stack -> pointer ;
320
+ handle -> uc_stack .ss_flags = 0 ;
321
+ handle -> uc_link = NULL ;
322
+
323
+ makecontext (handle , (void (* )(void )) zend_fiber_trampoline , 1 , context );
324
+
325
+ context -> handle = handle ;
326
+ #else
303
327
// Stack grows down, calculate the top of the stack. make_fcontext then shifts pointer to lower 16-byte boundary.
304
328
void * stack = (void * ) ((uintptr_t ) context -> stack -> pointer + context -> stack -> size );
305
329
306
- context -> handle = make_fcontext (stack , context -> stack -> size , zend_fiber_trampoline );
330
+ context -> handle = make_fcontext (stack , context -> stack -> size , zend_fiber_start );
307
331
ZEND_ASSERT (context -> handle != NULL && "make_fcontext() never returns NULL" );
332
+ #endif
308
333
309
334
context -> kind = kind ;
310
335
context -> function = coroutine ;
@@ -318,6 +343,10 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, z
318
343
ZEND_API void zend_fiber_destroy_context (zend_fiber_context * context )
319
344
{
320
345
zend_fiber_stack_free (context -> stack );
346
+
347
+ #ifdef ZEND_FIBER_UCONTEXT
348
+ efree (context -> handle );
349
+ #endif
321
350
}
322
351
323
352
ZEND_API void zend_fiber_switch_context (zend_fiber_transfer * transfer )
@@ -352,6 +381,7 @@ ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)
352
381
353
382
/* Update transfer context with the current fiber before switching. */
354
383
transfer -> context = from ;
384
+ to -> transfer = transfer ;
355
385
356
386
EG (current_fiber_context ) = to ;
357
387
@@ -363,14 +393,20 @@ ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)
363
393
to -> stack -> asan_size );
364
394
#endif
365
395
366
- boost_context_data data = jump_fcontext (to -> handle , transfer );
396
+ #ifdef ZEND_FIBER_UCONTEXT
397
+ swapcontext (from -> handle , to -> handle );
398
+ #else
399
+ boost_context_data data = jump_fcontext (to -> handle , to );
400
+ #endif
367
401
368
402
/* Copy transfer struct because it might live on the other fiber's stack that will eventually be destroyed. */
369
- * transfer = * data . transfer ;
403
+ * transfer = * from -> transfer ;
370
404
371
- /* Get a hold of the context that resumed us and update its handle to allow for symmetric coroutines. */
405
+ /* Get the context that resumed us and update its handle to allow for symmetric coroutines. */
372
406
to = transfer -> context ;
407
+ #ifndef ZEND_FIBER_UCONTEXT
373
408
to -> handle = data .handle ;
409
+ #endif
374
410
375
411
#ifdef __SANITIZE_ADDRESS__
376
412
__sanitizer_finish_switch_fiber (fake_stack , & to -> stack -> asan_pointer , & to -> stack -> asan_size );
@@ -844,6 +880,10 @@ void zend_fiber_init(void)
844
880
context -> stack = emalloc (sizeof (zend_fiber_stack ));
845
881
#endif
846
882
883
+ #ifdef ZEND_FIBER_UCONTEXT
884
+ context -> handle = emalloc (sizeof (ucontext_t ));
885
+ #endif
886
+
847
887
context -> status = ZEND_FIBER_STATUS_RUNNING ;
848
888
849
889
EG (main_fiber_context ) = context ;
@@ -855,9 +895,14 @@ void zend_fiber_init(void)
855
895
856
896
void zend_fiber_shutdown (void )
857
897
{
898
+ #ifdef ZEND_FIBER_UCONTEXT
899
+ efree (EG (main_fiber_context )-> handle );
900
+ #endif
901
+
858
902
#ifdef __SANITIZE_ADDRESS__
859
903
efree (EG (main_fiber_context )-> stack );
860
904
#endif
905
+
861
906
efree (EG (main_fiber_context ));
862
907
863
908
zend_fiber_switch_block ();
0 commit comments