]> granicus.if.org Git - php/commitdiff
Turn safe timeout handling into general interrupt handling ability.
authorDmitry Stogov <dmitry@zend.com>
Thu, 23 Jun 2016 12:01:23 +0000 (15:01 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 23 Jun 2016 12:01:23 +0000 (15:01 +0300)
Zend/zend.c
Zend/zend.h
Zend/zend_execute.c
Zend/zend_execute_API.c
Zend/zend_globals.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_gen.php

index 89db3c9f69c07db24b38bac12c83e1bbbc9211e0..91f5cd696600ada1e32d82c815088d551474e3ee 100644 (file)
@@ -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;
index f473e2cc215f01a2caf041fcde5dd1c4768c2c03..94f2fbdcf4d6f9d2cc3e751456e60cb491aece04 100644 (file)
@@ -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);
index c8d2f7c51318fdf234bbe7d14dc087292f2bfb50..670dcd24427e5d99ace9824268cc0c302799d14c 100644 (file)
@@ -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)
 
index d292de19e49e0869b3b5018f44576a7da6048079..4c7946f69017de794471276797f4ff9c2659af9d 100644 (file)
@@ -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;
index b560038b7a09c3f58fece01abb2ced3088361dd3..3a4f0c19400721bee5355fbf9bcbd81cf20d2323 100644 (file)
@@ -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;
 
index add7028c6d59d37b132de62f8e800fd9fdc16e17..feded0a9374db7711b60a407d6f8849b2663383d 100644 (file)
@@ -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();
+}
index 19d06bdd17d4b05a50a28dbc620a7fa606369584..1943dc553a8015c1da61279264c0b5d86198bede 100644 (file)
@@ -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
index 8775716753d783987aa27e5263e4ccc1742b4d2c..6086237c39c0151c8b96f0031a6b072e793a2359 100644 (file)
@@ -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");
        }