diff options
author | Dmitry Stogov <dmitry@zend.com> | 2016-06-23 15:01:23 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2016-06-23 15:01:23 +0300 |
commit | d0460d8f6be04fc9493fc7db99d29168b46f3e72 (patch) | |
tree | 3951381c23545f2ef03d4ca5faf3f50402ffc9f3 | |
parent | adc95c511495f00cd1a90feff5fff7968e38fc4a (diff) | |
download | php-git-d0460d8f6be04fc9493fc7db99d29168b46f3e72.tar.gz |
Turn safe timeout handling into general interrupt handling ability.
-rw-r--r-- | Zend/zend.c | 3 | ||||
-rw-r--r-- | Zend/zend.h | 1 | ||||
-rw-r--r-- | Zend/zend_execute.c | 10 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 19 | ||||
-rw-r--r-- | Zend/zend_globals.h | 1 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 13 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 18 | ||||
-rw-r--r-- | Zend/zend_vm_gen.php | 6 |
8 files changed, 59 insertions, 12 deletions
diff --git a/Zend/zend.c b/Zend/zend.c index 89db3c9f69..91f5cd6966 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -52,6 +52,7 @@ ZEND_API zend_write_func_t zend_write; ZEND_API FILE *(*zend_fopen)(const char *filename, zend_string **opened_path); ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle); ZEND_API void (*zend_ticks_function)(int ticks); +ZEND_API void (*zend_interrupt_function)(zend_execute_data *execute_data); ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); size_t (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); zend_string *(*zend_vstrpprintf)(size_t max_len, const char *format, va_list ap); @@ -682,6 +683,8 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) / zend_getenv = utility_functions->getenv_function; zend_resolve_path = utility_functions->resolve_path_function; + zend_interrupt_function = NULL; + #if HAVE_DTRACE /* build with dtrace support */ zend_compile_file = dtrace_compile_file; diff --git a/Zend/zend.h b/Zend/zend.h index f473e2cc21..94f2fbdcf4 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -258,6 +258,7 @@ extern ZEND_API size_t (*zend_printf)(const char *format, ...) ZEND_ATTRIBUTE_PT extern ZEND_API zend_write_func_t zend_write; extern ZEND_API FILE *(*zend_fopen)(const char *filename, zend_string **opened_path); extern ZEND_API void (*zend_ticks_function)(int ticks); +extern ZEND_API void (*zend_interrupt_function)(zend_execute_data *execute_data); extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); extern ZEND_API void (*zend_on_timeout)(int seconds); extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index c8d2f7c513..670dcd2442 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2069,15 +2069,9 @@ void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */ } /* }}} */ -static zend_never_inline ZEND_COLD ZEND_NORETURN void ZEND_FASTCALL zend_interrupt(void) /* {{{ */ -{ - zend_timeout(0); -} -/* }}} */ - #define ZEND_VM_INTERRUPT_CHECK() do { \ - if (UNEXPECTED(EG(timed_out))) { \ - zend_interrupt(); \ + if (UNEXPECTED(EG(vm_interrupt))) { \ + ZEND_VM_INTERRUPT(); \ } \ } while (0) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index d292de19e4..4c7946f690 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -172,6 +172,7 @@ void init_executor(void) /* {{{ */ zend_objects_store_init(&EG(objects_store), 1024); EG(full_tables_cleanup) = 0; + EG(vm_interrupt) = 0; EG(timed_out) = 0; EG(exception) = NULL; @@ -1225,6 +1226,7 @@ static void zend_timeout_handler(int dummy) /* {{{ */ } EG(timed_out) = 1; + EG(vm_interrupt) = 1; #ifndef ZTS if (EG(hard_timeout) > 0) { @@ -1239,7 +1241,7 @@ static void zend_timeout_handler(int dummy) /* {{{ */ #ifdef ZEND_WIN32 VOID CALLBACK tq_timer_cb(PVOID arg, BOOLEAN timed_out) { - zend_bool *php_timed_out; + zend_executor_globals *eg; /* The doc states it'll be always true, however it theoretically could be FALSE when the thread was signaled. */ @@ -1247,8 +1249,9 @@ VOID CALLBACK tq_timer_cb(PVOID arg, BOOLEAN timed_out) return; } - php_timed_out = (zend_bool *)arg; - *php_timed_out = 1; + eg = (zend_bool *)arg; + eg->timed_out = 1; + eg->vm_interrupt = 1; } #endif @@ -1259,6 +1262,7 @@ VOID CALLBACK tq_timer_cb(PVOID arg, BOOLEAN timed_out) static void zend_set_timeout_ex(zend_long seconds, int reset_signals) /* {{{ */ { + zend_execute_data *eg; #ifdef ZEND_WIN32 if(!seconds) { @@ -1278,7 +1282,14 @@ static void zend_set_timeout_ex(zend_long seconds, int reset_signals) /* {{{ */ } /* XXX passing NULL means the default timer queue provided by the system is used */ - if (!CreateTimerQueueTimer(&tq_timer, NULL, (WAITORTIMERCALLBACK)tq_timer_cb, (VOID*)&EG(timed_out), seconds*1000, 0, WT_EXECUTEONLYONCE)) { +#ifndef ZTS + eg = &execute_data; +#elif defined(ZEND_ENABLE_STATIC_TSRMLS_CACHE) + eg = TSRMG_BULK_STATIC(executor_globals_id, zend_executor_globals *) +#else + eg = TSRMG_BULK(executor_globals_id, zend_executor_globals *) +#endif + if (!CreateTimerQueueTimer(&tq_timer, NULL, (WAITORTIMERCALLBACK)tq_timer_cb, (VOID*)eg, seconds*1000, 0, WT_EXECUTEONLYONCE)) { tq_timer = NULL; zend_error_noreturn(E_ERROR, "Could not queue new timer"); return; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index b560038b7a..3a4f0c1940 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -177,6 +177,7 @@ struct _zend_executor_globals { /* for extended information support */ zend_bool no_extensions; + zend_bool vm_interrupt; zend_bool timed_out; zend_long hard_timeout; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index add7028c6d..feded0a937 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8604,3 +8604,16 @@ ZEND_VM_C_LABEL(send_var_by_ref_simple): } ZEND_VM_DEFINE_OP(137, ZEND_OP_DATA); + +ZEND_VM_HELPER(zend_interrupt_helper, ANY, ANY) +{ + EG(vm_interrupt) = 0; + if (EG(timed_out)) { + zend_timeout(0); + } else if (zend_interrupt_function) { + SAVE_OPLINE(); + zend_interrupt_function(execute_data); + LOAD_OPLINE(); + } + ZEND_VM_CONTINUE(); +} diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 19d06bdd17..1943dc553a 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -397,8 +397,10 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H # define ZEND_VM_ENTER() return 1 # define ZEND_VM_LEAVE() return 2 #endif +#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); #define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS); ZEND_API void execute_ex(zend_execute_data *ex) { @@ -2071,6 +2073,18 @@ call_trampoline_end: ZEND_VM_LEAVE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) +{ + EG(vm_interrupt) = 0; + if (EG(timed_out)) { + zend_timeout(0); + } else if (zend_interrupt_function) { + SAVE_OPLINE(); + zend_interrupt_function(execute_data); + LOAD_OPLINE(); + } + ZEND_VM_CONTINUE(); +} static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -17055,6 +17069,7 @@ send_var_by_ref_simple: ZEND_VM_NEXT_OPCODE(); } + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_QUICK_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -17083,6 +17098,7 @@ send_var_by_ref_simple: ZEND_VM_NEXT_OPCODE(); } + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -35819,6 +35835,7 @@ send_var_by_ref_simple: ZEND_VM_NEXT_OPCODE(); } + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_QUICK_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -35847,6 +35864,7 @@ send_var_by_ref_simple: ZEND_VM_NEXT_OPCODE(); } + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 8775716753..6086237c39 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1619,8 +1619,11 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# define ZEND_VM_ENTER() return 1\n"); out($f,"# define ZEND_VM_LEAVE() return 2\n"); out($f,"#endif\n"); + out($f,"#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); out($f,"\n"); + out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS);"); + out($f,"\n"); break; case ZEND_VM_KIND_SWITCH: out($f,"\n"); @@ -1648,6 +1651,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#define ZEND_VM_RETURN() return\n"); out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); out($f,"#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n"); out($f,"\n"); break; @@ -1682,6 +1686,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#define ZEND_VM_RETURN() return\n"); out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); out($f,"#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n"); out($f,"\n"); break; @@ -2444,6 +2449,7 @@ function gen_vm($def, $skel) { out($f,"#define ZEND_VM_RETURN() return -1\n"); out($f,"#define ZEND_VM_ENTER() return 1\n"); out($f,"#define ZEND_VM_LEAVE() return 2\n"); + out($f,"#define ZEND_VM_INTERRUPT() return zend_interrupt_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n"); out($f,"\n"); } |