@@ -113,6 +113,10 @@ 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
+ ZEND_TLS zend_fiber_transfer * transfer_data ;
119
+ #else
116
120
/* boost_context_data is our customized definition of struct transfer_t as
117
121
* provided by boost.context in fcontext.hpp:
118
122
*
@@ -130,7 +134,8 @@ typedef struct {
130
134
131
135
/* These functions are defined in assembler files provided by boost.context (located in "Zend/asm"). */
132
136
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 );
137
+ extern boost_context_data jump_fcontext (void * to , zend_fiber_transfer * transfer );
138
+ #endif
134
139
135
140
ZEND_API zend_class_entry * zend_ce_fiber ;
136
141
static zend_class_entry * zend_ce_fiber_error ;
@@ -244,28 +249,37 @@ static void zend_fiber_stack_free(zend_fiber_stack *stack)
244
249
245
250
efree (stack );
246
251
}
247
-
252
+ #ifdef ZEND_FIBER_UCONTEXT
253
+ static ZEND_NORETURN void zend_fiber_trampoline (void )
254
+ #else
248
255
static ZEND_NORETURN void zend_fiber_trampoline (boost_context_data data )
256
+ #endif
249
257
{
250
- zend_fiber_context * from = data . transfer -> context ;
258
+ zend_fiber_context * context = EG ( current_fiber_context ) ;
251
259
252
- #ifdef __SANITIZE_ADDRESS__
253
- __sanitizer_finish_switch_fiber (NULL , & from -> stack -> asan_pointer , & from -> stack -> asan_size );
260
+ /* Initialize transfer struct with a copy of passed data. */
261
+ #ifdef ZEND_FIBER_UCONTEXT
262
+ zend_fiber_transfer transfer = * transfer_data ;
263
+ #else
264
+ zend_fiber_transfer transfer = * data .transfer ;
254
265
#endif
255
266
256
- /* Get a hold of the context that resumed us and update its handle to allow for symmetric coroutines. */
267
+ zend_fiber_context * from = transfer .context ;
268
+
269
+ #ifndef ZEND_FIBER_UCONTEXT
270
+ /* Get the context that resumed us and update its handle to allow for symmetric coroutines. */
257
271
from -> handle = data .handle ;
272
+ #endif
258
273
259
- /* Initialize transfer struct with a copy of passed data. */
260
- zend_fiber_transfer transfer = * data .transfer ;
274
+ #ifdef __SANITIZE_ADDRESS__
275
+ __sanitizer_finish_switch_fiber (NULL , & from -> stack -> asan_pointer , & from -> stack -> asan_size );
276
+ #endif
261
277
262
278
/* Ensure that previous fiber will be cleaned up (needed by symmetric coroutines). */
263
279
if (from -> status == ZEND_FIBER_STATUS_DEAD ) {
264
280
zend_fiber_destroy_context (from );
265
281
}
266
282
267
- zend_fiber_context * context = EG (current_fiber_context );
268
-
269
283
context -> function (& transfer );
270
284
context -> status = ZEND_FIBER_STATUS_DEAD ;
271
285
@@ -300,11 +314,25 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, z
300
314
return false;
301
315
}
302
316
317
+ #ifdef ZEND_FIBER_UCONTEXT
318
+ ucontext_t * handle = emalloc (sizeof (ucontext_t ));
319
+ getcontext (handle );
320
+
321
+ handle -> uc_stack .ss_size = context -> stack -> size ;
322
+ handle -> uc_stack .ss_sp = context -> stack -> pointer ;
323
+ handle -> uc_stack .ss_flags = 0 ;
324
+ handle -> uc_link = NULL ;
325
+
326
+ makecontext (handle , (void (* )(void )) zend_fiber_trampoline , 0 );
327
+
328
+ context -> handle = handle ;
329
+ #else
303
330
// Stack grows down, calculate the top of the stack. make_fcontext then shifts pointer to lower 16-byte boundary.
304
331
void * stack = (void * ) ((uintptr_t ) context -> stack -> pointer + context -> stack -> size );
305
332
306
333
context -> handle = make_fcontext (stack , context -> stack -> size , zend_fiber_trampoline );
307
334
ZEND_ASSERT (context -> handle != NULL && "make_fcontext() never returns NULL" );
335
+ #endif
308
336
309
337
context -> kind = kind ;
310
338
context -> function = coroutine ;
@@ -318,6 +346,10 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, z
318
346
ZEND_API void zend_fiber_destroy_context (zend_fiber_context * context )
319
347
{
320
348
zend_fiber_stack_free (context -> stack );
349
+
350
+ #ifdef ZEND_FIBER_UCONTEXT
351
+ efree (context -> handle );
352
+ #endif
321
353
}
322
354
323
355
ZEND_API void zend_fiber_switch_context (zend_fiber_transfer * transfer )
@@ -363,14 +395,26 @@ ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)
363
395
to -> stack -> asan_size );
364
396
#endif
365
397
398
+ #ifdef ZEND_FIBER_UCONTEXT
399
+ transfer_data = transfer ;
400
+
401
+ swapcontext (from -> handle , to -> handle );
402
+
403
+ /* Copy transfer struct because it might live on the other fiber's stack that will eventually be destroyed. */
404
+ * transfer = * transfer_data ;
405
+ #else
366
406
boost_context_data data = jump_fcontext (to -> handle , transfer );
367
407
368
408
/* Copy transfer struct because it might live on the other fiber's stack that will eventually be destroyed. */
369
409
* transfer = * data .transfer ;
410
+ #endif
370
411
371
- /* Get a hold of the context that resumed us and update its handle to allow for symmetric coroutines. */
372
412
to = transfer -> context ;
413
+
414
+ #ifndef ZEND_FIBER_UCONTEXT
415
+ /* Get the context that resumed us and update its handle to allow for symmetric coroutines. */
373
416
to -> handle = data .handle ;
417
+ #endif
374
418
375
419
#ifdef __SANITIZE_ADDRESS__
376
420
__sanitizer_finish_switch_fiber (fake_stack , & to -> stack -> asan_pointer , & to -> stack -> asan_size );
@@ -844,6 +888,10 @@ void zend_fiber_init(void)
844
888
context -> stack = emalloc (sizeof (zend_fiber_stack ));
845
889
#endif
846
890
891
+ #ifdef ZEND_FIBER_UCONTEXT
892
+ context -> handle = emalloc (sizeof (ucontext_t ));
893
+ #endif
894
+
847
895
context -> status = ZEND_FIBER_STATUS_RUNNING ;
848
896
849
897
EG (main_fiber_context ) = context ;
@@ -855,9 +903,14 @@ void zend_fiber_init(void)
855
903
856
904
void zend_fiber_shutdown (void )
857
905
{
906
+ #ifdef ZEND_FIBER_UCONTEXT
907
+ efree (EG (main_fiber_context )-> handle );
908
+ #endif
909
+
858
910
#ifdef __SANITIZE_ADDRESS__
859
911
efree (EG (main_fiber_context )-> stack );
860
912
#endif
913
+
861
914
efree (EG (main_fiber_context ));
862
915
863
916
zend_fiber_switch_block ();
0 commit comments