@@ -74,6 +74,7 @@ static zend_fiber_transfer zend_test_fiber_suspend(zend_test_fiber *fiber, zval
74
74
static ZEND_STACK_ALIGNED void zend_test_fiber_execute (zend_fiber_transfer * transfer )
75
75
{
76
76
zend_test_fiber * fiber = ZT_G (active_fiber );
77
+ zval retval ;
77
78
78
79
zend_execute_data * execute_data ;
79
80
@@ -93,10 +94,11 @@ static ZEND_STACK_ALIGNED void zend_test_fiber_execute(zend_fiber_transfer *tran
93
94
EG (current_execute_data ) = execute_data ;
94
95
EG (jit_trace_num ) = 0 ;
95
96
96
- fiber -> fci .retval = & fiber -> result ;
97
+ fiber -> fci .retval = & retval ;
97
98
98
99
zend_call_function (& fiber -> fci , & fiber -> fci_cache );
99
100
101
+ zval_ptr_dtor (& fiber -> result ); // Destroy param from symmetric coroutine.
100
102
zval_ptr_dtor (& fiber -> fci .function_name );
101
103
102
104
if (EG (exception )) {
@@ -111,15 +113,30 @@ static ZEND_STACK_ALIGNED void zend_test_fiber_execute(zend_fiber_transfer *tran
111
113
112
114
zend_clear_exception ();
113
115
} else {
116
+ ZVAL_COPY_VALUE (& fiber -> result , & retval );
114
117
ZVAL_COPY (& transfer -> value , & fiber -> result );
115
118
}
116
119
} zend_catch {
117
120
fiber -> flags |= ZEND_FIBER_FLAG_BAILOUT ;
118
121
} zend_end_try ();
119
122
120
- transfer -> context = fiber -> caller ;
121
-
122
123
zend_vm_stack_destroy ();
124
+
125
+ if (fiber -> target ) {
126
+ zend_fiber_context * target = zend_test_fiber_get_context (fiber -> target );
127
+ zend_fiber_init_context (target , zend_test_fiber_class , zend_test_fiber_execute , EG (fiber_stack_size ));
128
+ transfer -> context = target ;
129
+
130
+ ZVAL_COPY (& fiber -> target -> result , & fiber -> result );
131
+ fiber -> target -> fci .params = & fiber -> target -> result ;
132
+ fiber -> target -> fci .param_count = 1 ;
133
+
134
+ fiber -> target -> caller = fiber -> caller ;
135
+ ZT_G (active_fiber ) = fiber -> target ;
136
+ } else {
137
+ transfer -> context = fiber -> caller ;
138
+ }
139
+
123
140
fiber -> caller = NULL ;
124
141
}
125
142
@@ -179,6 +196,10 @@ static void zend_test_fiber_object_free(zend_object *object)
179
196
zval_ptr_dtor (& fiber -> fci .function_name );
180
197
}
181
198
199
+ if (fiber -> target ) {
200
+ OBJ_RELEASE (& fiber -> target -> std );
201
+ }
202
+
182
203
zval_ptr_dtor (& fiber -> result );
183
204
184
205
zend_object_std_dtor (& fiber -> std );
@@ -225,6 +246,11 @@ static ZEND_METHOD(_ZendTestFiber, start)
225
246
226
247
ZEND_ASSERT (fiber -> status == ZEND_FIBER_STATUS_INIT );
227
248
249
+ if (fiber -> previous != NULL ) {
250
+ zend_throw_error (NULL , "Cannot start a fiber that is the target of another fiber" );
251
+ RETURN_THROWS ();
252
+ }
253
+
228
254
fiber -> fci .params = params ;
229
255
fiber -> fci .param_count = param_count ;
230
256
fiber -> fci .named_params = named_params ;
@@ -287,6 +313,33 @@ static ZEND_METHOD(_ZendTestFiber, resume)
287
313
delegate_transfer_result (fiber , & transfer , INTERNAL_FUNCTION_PARAM_PASSTHRU );
288
314
}
289
315
316
+ static ZEND_METHOD (_ZendTestFiber , pipeTo )
317
+ {
318
+ zend_fcall_info fci ;
319
+ zend_fcall_info_cache fci_cache ;
320
+
321
+ ZEND_PARSE_PARAMETERS_START (1 , 1 )
322
+ Z_PARAM_FUNC (fci , fci_cache )
323
+ ZEND_PARSE_PARAMETERS_END ();
324
+
325
+ zend_test_fiber * fiber = (zend_test_fiber * ) Z_OBJ_P (getThis ());
326
+ zend_test_fiber * target = (zend_test_fiber * ) zend_test_fiber_class -> create_object (zend_test_fiber_class );
327
+
328
+ target -> fci = fci ;
329
+ target -> fci_cache = fci_cache ;
330
+ Z_TRY_ADDREF (target -> fci .function_name );
331
+
332
+ target -> previous = zend_test_fiber_get_context (fiber );
333
+
334
+ if (fiber -> target ) {
335
+ OBJ_RELEASE (& fiber -> target -> std );
336
+ }
337
+
338
+ fiber -> target = target ;
339
+
340
+ RETURN_OBJ_COPY (& target -> std );
341
+ }
342
+
290
343
void zend_test_fiber_init (void )
291
344
{
292
345
zend_test_fiber_class = register_class__ZendTestFiber ();
0 commit comments