14
14
+----------------------------------------------------------------------+
15
15
*/
16
16
17
+ #include "zend_API.h"
18
+ #include "zend_globals.h"
17
19
#ifdef HAVE_CONFIG_H
18
20
# include "config.h"
19
21
#endif
27
29
#include "zend_weakrefs.h"
28
30
#include "main/SAPI.h"
29
31
#include "TSRM.h"
32
+ #include "zend_fibers.h"
33
+ #include "zend_stack.h"
30
34
31
35
#include <sys/types.h>
32
36
#include <sys/stat.h>
@@ -907,7 +911,9 @@ static zend_always_inline zend_string *zend_ffi_mangled_func_name(zend_string *n
907
911
/* }}} */
908
912
909
913
#if FFI_CLOSURES
914
+
910
915
typedef struct _zend_ffi_callback_data {
916
+ zend_fiber fiber ;
911
917
zend_fcall_info_cache fcc ;
912
918
zend_ffi_type * type ;
913
919
void * code ;
@@ -916,6 +922,7 @@ typedef struct _zend_ffi_callback_data {
916
922
uint32_t arg_count ;
917
923
ffi_type * ret_type ;
918
924
ffi_type * arg_types [0 ] ZEND_ELEMENT_COUNT (arg_count );
925
+ zend_ffi_call_data ffi_args ;
919
926
} zend_ffi_callback_data ;
920
927
921
928
static void zend_ffi_callback_hash_dtor (zval * zv ) /* {{{ */
@@ -951,66 +958,18 @@ static void zend_ffi_dispatch_callback_end(void){ /* {{{ */
951
958
}
952
959
/* }}} */
953
960
954
- static void zend_ffi_dispatch_callback (void ){ /* {{{ */
955
- if (!zend_atomic_bool_load_ex (& FFI_G (callback_in_progress ))) {
956
- return ;
957
- }
958
-
959
- zend_ffi_callback_data * callback_data = FFI_G (callback_data ).data ;
960
- zend_fcall_info fci ;
961
- zend_ffi_type * ret_type ;
962
- zval retval ;
963
- ALLOCA_FLAG (use_heap )
964
-
965
- fci .size = sizeof (zend_fcall_info );
966
- ZVAL_UNDEF (& fci .function_name );
967
- fci .retval = & retval ;
968
- fci .params = do_alloca (sizeof (zval ) * callback_data -> arg_count , use_heap );
969
- fci .object = NULL ;
970
- fci .param_count = callback_data -> arg_count ;
971
- fci .named_params = NULL ;
972
-
973
-
974
- if (callback_data -> type -> func .args ) {
975
- int n = 0 ;
976
- zend_ffi_type * arg_type ;
977
-
978
- ZEND_HASH_PACKED_FOREACH_PTR (callback_data -> type -> func .args , arg_type ) {
979
- arg_type = ZEND_FFI_TYPE (arg_type );
980
- zend_ffi_cdata_to_zval (NULL , FFI_G (callback_data ).args [n ], arg_type , BP_VAR_R , & fci .params [n ], (zend_ffi_flags )(arg_type -> attr & ZEND_FFI_ATTR_CONST ), 0 , 0 );
981
- n ++ ;
982
- } ZEND_HASH_FOREACH_END ();
983
- }
984
-
985
- ZVAL_UNDEF (& retval );
986
- if (zend_call_function (& fci , & callback_data -> fcc ) != SUCCESS ) {
987
- zend_throw_error (zend_ffi_exception_ce , "Cannot call callback" );
988
- }
989
-
990
- if (callback_data -> arg_count ) {
991
- int n = 0 ;
992
-
993
- for (n = 0 ; n < callback_data -> arg_count ; n ++ ) {
994
- zval_ptr_dtor (& fci .params [n ]);
995
- }
996
- }
997
- free_alloca (fci .params , use_heap );
998
-
999
- if (EG (exception )) {
1000
- // we're about to do a hard exit. unlock all mutexes
1001
- zend_ffi_dispatch_callback_end ();
1002
- tsrm_mutex_unlock (FFI_G (vm_request_lock ));
1003
- zend_error_noreturn (E_ERROR , "Throwing from FFI callbacks is not allowed" );
1004
- }
1005
-
1006
- ret_type = ZEND_FFI_TYPE (callback_data -> type -> func .ret_type );
1007
- if (ret_type -> kind != ZEND_FFI_TYPE_VOID ) {
1008
- zend_ffi_zval_to_cdata (FFI_G (callback_data ).ret , ret_type , & retval );
1009
- }
1010
-
1011
- zval_ptr_dtor (& retval );
961
+ static void zend_ffi_fci_prepare (
962
+ zend_ffi_callback_data * data ,
963
+ zend_fcall_info * fci
964
+ ){
965
+ fci -> size = sizeof (* fci );
966
+ ZVAL_UNDEF (& fci -> function_name );
967
+ fci -> retval = & data -> fiber .result ;
968
+ fci -> params = emalloc (sizeof (zval ) * data -> arg_count );
969
+ fci -> object = NULL ;
970
+ fci -> param_count = data -> arg_count ;
971
+ fci -> named_params = NULL ;
1012
972
}
1013
- /* }}} */
1014
973
1015
974
static void zend_ffi_interrupt_function (zend_execute_data * execute_data ){ /* {{{ */
1016
975
tsrm_mutex_lock (FFI_G (vm_request_lock ));
@@ -1079,6 +1038,8 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v
1079
1038
.args = args ,
1080
1039
.data = (zend_ffi_callback_data * )data
1081
1040
};
1041
+ ((zend_ffi_callback_data * )data )-> ffi_args = call_data ;
1042
+
1082
1043
FFI_G (callback_data ) = call_data ;
1083
1044
1084
1045
FFI_G (callback_tid ) = tsrm_thread_id ();
@@ -1096,8 +1057,25 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v
1096
1057
}
1097
1058
1098
1059
// dispatch the callback
1099
- zend_ffi_dispatch_callback ();
1100
-
1060
+ if (call_data .data -> type -> func .args ) {
1061
+ int n = 0 ;
1062
+ zend_ffi_type * arg_type ;
1063
+
1064
+ ZEND_HASH_PACKED_FOREACH_PTR (call_data .data -> type -> func .args , arg_type ) {
1065
+ arg_type = ZEND_FFI_TYPE (arg_type );
1066
+ zend_ffi_cdata_to_zval (NULL ,
1067
+ call_data .data -> ffi_args .args [n ], arg_type , BP_VAR_R ,
1068
+ & call_data .data -> fiber .fci .params [n ], (zend_ffi_flags )(arg_type -> attr & ZEND_FFI_ATTR_CONST ),
1069
+ 0 , 0 );
1070
+ n ++ ;
1071
+ } ZEND_HASH_FOREACH_END ();
1072
+ }
1073
+
1074
+ if (zend_atomic_bool_load_ex (& FFI_G (callback_in_progress ))) {
1075
+ zend_fiber_resume (& call_data .data -> fiber , NULL , false);
1076
+ efree (call_data .data -> fiber .fci .params );
1077
+ }
1078
+
1101
1079
zend_ffi_dispatch_callback_end ();
1102
1080
}
1103
1081
tsrm_mutex_unlock (FFI_G (vm_request_lock ));
@@ -1141,6 +1119,12 @@ static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value) /* {{{ *
1141
1119
callback_data -> callback = callback ;
1142
1120
callback_data -> code = code ;
1143
1121
callback_data -> arg_count = arg_count ;
1122
+ callback_data -> fiber .fci_cache = fcc ;
1123
+
1124
+ zend_fiber_init_context (& callback_data -> fiber .context , NULL , zend_fiber_execute , EG (fiber_stack_size ));
1125
+ callback_data -> fiber .previous = & callback_data -> fiber .context ;
1126
+
1127
+ zend_ffi_fci_prepare (callback_data , & callback_data -> fiber .fci );
1144
1128
1145
1129
if (type -> func .args ) {
1146
1130
int n = 0 ;
@@ -5763,7 +5747,6 @@ static ZEND_GINIT_FUNCTION(ffi)
5763
5747
/* {{{ ZEND_GINIT_FUNCTION */
5764
5748
static ZEND_GSHUTDOWN_FUNCTION (ffi )
5765
5749
{
5766
- tsrm_mutex_free (ffi_globals -> vm_request_lock );
5767
5750
zend_ffi_wait_request_barrier (true);
5768
5751
if (ffi_globals -> scopes ) {
5769
5752
zend_hash_destroy (ffi_globals -> scopes );
0 commit comments