summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2016-06-23 15:01:23 +0300
committerDmitry Stogov <dmitry@zend.com>2016-06-23 15:01:23 +0300
commitd0460d8f6be04fc9493fc7db99d29168b46f3e72 (patch)
tree3951381c23545f2ef03d4ca5faf3f50402ffc9f3
parentadc95c511495f00cd1a90feff5fff7968e38fc4a (diff)
downloadphp-git-d0460d8f6be04fc9493fc7db99d29168b46f3e72.tar.gz
Turn safe timeout handling into general interrupt handling ability.
-rw-r--r--Zend/zend.c3
-rw-r--r--Zend/zend.h1
-rw-r--r--Zend/zend_execute.c10
-rw-r--r--Zend/zend_execute_API.c19
-rw-r--r--Zend/zend_globals.h1
-rw-r--r--Zend/zend_vm_def.h13
-rw-r--r--Zend/zend_vm_execute.h18
-rw-r--r--Zend/zend_vm_gen.php6
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");
}