]> granicus.if.org Git - php/commitdiff
exit_on_timeout patch
authorRasmus Lerdorf <rasmus@php.net>
Tue, 18 Mar 2008 21:42:50 +0000 (21:42 +0000)
committerRasmus Lerdorf <rasmus@php.net>
Tue, 18 Mar 2008 21:42:50 +0000 (21:42 +0000)
After the sigsetjmp change, this is patch #2 in an effort to get some
sanity restored to signal handling in PHP.

This patch does two things.  First, it makes it possible to reset the
timeout without resetting the signal handlers.  This is important for
cases where an extension may have deferred signals in its MINIT in order
to implement critical sections. It also lays the groundwork for cleaning
up our signal handling and perhaps eventually implementing our own
signal deferring mechanism so we can have true critical sections.

The second thing this does is to make it possible to terminate the current
child process (only for Apache1 at the moment) on a timeout.  There are
a number of extensions that are unhappy about being longjmp'ed out of
and when this happens on a timeout they are left in an inconsistent state.
By turning on exit_on_timeout you can now force the process to terminate
on a timeout which will clean up any hanging locks and/or memory left
hanging after the longjmp.

Zend/zend_execute.h
Zend/zend_execute_API.c
main/SAPI.c
main/SAPI.h
main/main.c
main/php_globals.h
sapi/apache/mod_php5.c

index 147d98546b077f21ae02a766c597d2b80c9542df..8cb6523e6e80e25c687d3d4358b6f13565430ead 100644 (file)
@@ -300,7 +300,7 @@ ZEND_API char *zend_get_executed_filename(TSRMLS_D);
 ZEND_API uint zend_get_executed_lineno(TSRMLS_D);
 ZEND_API zend_bool zend_is_executing(TSRMLS_D);
 
-ZEND_API void zend_set_timeout(long seconds);
+ZEND_API void zend_set_timeout(long seconds, int reset_signals);
 ZEND_API void zend_unset_timeout(TSRMLS_D);
 ZEND_API void zend_timeout(int dummy);
 ZEND_API zend_class_entry *zend_fetch_class(const char *class_name, uint class_name_len, int fetch_type TSRMLS_DC);
index 34b9957bb7e77ad0626ea33ee9db69ed943b2584..59f3e61400a9d635ae9c6f177af2c44b1f425f58 100644 (file)
@@ -1527,7 +1527,7 @@ void zend_shutdown_timeout_thread(void) /* {{{ */
 #define SIGPROF 27
 #endif
 
-void zend_set_timeout(long seconds) /* {{{ */
+void zend_set_timeout(long seconds, int reset_signals) /* {{{ */
 {
        TSRMLS_FETCH();
 
@@ -1554,16 +1554,22 @@ void zend_set_timeout(long seconds) /* {{{ */
 
 #      ifdef __CYGWIN__
                setitimer(ITIMER_REAL, &t_r, NULL);
-               signal(SIGALRM, zend_timeout);
-               sigemptyset(&sigset);
-               sigaddset(&sigset, SIGALRM);
+               if(reset_signals) {
+                       signal(SIGALRM, zend_timeout);
+                       sigemptyset(&sigset);
+                       sigaddset(&sigset, SIGALRM);
+               }
 #      else
                setitimer(ITIMER_PROF, &t_r, NULL);
-               signal(SIGPROF, zend_timeout);
-               sigemptyset(&sigset);
-               sigaddset(&sigset, SIGPROF);
+               if(reset_signals) {
+                       signal(SIGPROF, zend_timeout);
+                       sigemptyset(&sigset);
+                       sigaddset(&sigset, SIGPROF);
+               }
 #      endif
-               sigprocmask(SIG_UNBLOCK, &sigset, NULL);
+               if(reset_signals) {
+                       sigprocmask(SIG_UNBLOCK, &sigset, NULL);
+               }
        }
 #      endif
 #endif
index a5699252b1f4dd4a87cf16fda468400bce4a35d9..feabcef549787e528e370ff8111d10a8dc0174a5 100644 (file)
@@ -1002,6 +1002,12 @@ SAPI_API time_t sapi_get_request_time(TSRMLS_D)
        return SG(global_request_time);
 }
 
+SAPI_API void sapi_terminate_process(TSRMLS_D) {
+       if (sapi_module.terminate_process) {
+               sapi_module.terminate_process(TSRMLS_C);
+       }
+}
+
 /*
  * Local variables:
  * tab-width: 4
index 39a9a85b2663627358e1cfcfac89bb96753467a1..d4a558e3e7b5a3b27e3917adb5f173805a28eec8 100644 (file)
@@ -207,6 +207,7 @@ SAPI_API int sapi_force_http_10(TSRMLS_D);
 SAPI_API int sapi_get_target_uid(uid_t * TSRMLS_DC);
 SAPI_API int sapi_get_target_gid(gid_t * TSRMLS_DC);
 SAPI_API time_t sapi_get_request_time(TSRMLS_D);
+SAPI_API void sapi_terminate_process(TSRMLS_D);
 END_EXTERN_C()
 
 struct _sapi_module_struct {
@@ -236,6 +237,7 @@ struct _sapi_module_struct {
        void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);
        void (*log_message)(char *message);
        time_t (*get_request_time)(TSRMLS_D);
+       void (*terminate_process)(TSRMLS_D);
 
        char *php_ini_path_override;
 
index 5b8e334ed88d8bdcc18cc2c2c19b599d473d5427..e86ca796b3b08614b33709296e7f24af1b5bc6c6 100644 (file)
@@ -209,7 +209,7 @@ static PHP_INI_MH(OnUpdateTimeout)
                return SUCCESS;
        }
        zend_unset_timeout(TSRMLS_C);
-       zend_set_timeout(EG(timeout_seconds));
+       zend_set_timeout(EG(timeout_seconds), 0);
        return SUCCESS;
 }
 /* }}} */
@@ -461,6 +461,7 @@ PHP_INI_BEGIN()
 
        STD_PHP_INI_ENTRY("user_ini.filename",          ".user.ini",    PHP_INI_SYSTEM,         OnUpdateString,         user_ini_filename,      php_core_globals,               core_globals)
        STD_PHP_INI_ENTRY("user_ini.cache_ttl",         "300",                  PHP_INI_SYSTEM,         OnUpdateLong,           user_ini_cache_ttl,     php_core_globals,               core_globals)
+       STD_PHP_INI_BOOLEAN("exit_on_timeout",          "0",            PHP_INI_ALL,            OnUpdateBool,                   exit_on_timeout,                        php_core_globals,       core_globals)
 PHP_INI_END()
 /* }}} */
 
@@ -1229,7 +1230,8 @@ static void php_message_handler_for_zend(long message, void *data)
 void php_on_timeout(int seconds TSRMLS_DC)
 {
        PG(connection_status) |= PHP_CONNECTION_TIMEOUT;
-       zend_set_timeout(EG(timeout_seconds));
+       zend_set_timeout(EG(timeout_seconds), 0);
+       if(PG(exit_on_timeout)) sapi_terminate_process(TSRMLS_C);
 }
 
 #if PHP_SIGCHILD
@@ -1259,7 +1261,7 @@ static int php_start_sapi(TSRMLS_D)
                        PG(connection_status) = PHP_CONNECTION_NORMAL;
 
                        zend_activate(TSRMLS_C);
-                       zend_set_timeout(EG(timeout_seconds));
+                       zend_set_timeout(EG(timeout_seconds), 1);
                        zend_activate_modules(TSRMLS_C);
                        PG(modules_activated)=1;
                } zend_catch {
@@ -1303,9 +1305,9 @@ int php_request_startup(TSRMLS_D)
                sapi_activate(TSRMLS_C);
 
                if (PG(max_input_time) == -1) {
-                       zend_set_timeout(EG(timeout_seconds));
+                       zend_set_timeout(EG(timeout_seconds), 1);
                } else {
-                       zend_set_timeout(PG(max_input_time));
+                       zend_set_timeout(PG(max_input_time), 1);
                }
 
                /* Disable realpath cache if safe_mode or open_basedir are set */
@@ -2070,7 +2072,7 @@ PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC)
 #ifdef PHP_WIN32
                        zend_unset_timeout(TSRMLS_C);
 #endif
-                       zend_set_timeout(INI_INT("max_execution_time"));
+                       zend_set_timeout(EG(timeout_seconds), 0);
                }
                retval = (zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 3, prepend_file_p, primary_file, append_file_p) == SUCCESS);
 
index 0c9ccff5dffc06791d75eead5083ea9ba60e1757..53863104c69fcb892b7220e9e510a5f01efea82c 100644 (file)
@@ -154,6 +154,7 @@ struct _php_core_globals {
        char *disable_functions;
        char *disable_classes;
        zend_bool allow_url_include;
+       zend_bool exit_on_timeout;
 #ifdef PHP_WIN32
        zend_bool com_initialized;
 #endif
index d84b11e548e29b8d1b39ab1a45526aef8101023a..381fa919d2868d5f3e5ade0301fdbacfbda5c778 100644 (file)
@@ -434,6 +434,14 @@ static time_t php_apache_get_request_time(TSRMLS_D)
 }
 /* }}} */
 
+/* {{{ sapi_apache_child_terminate
+ */
+static void sapi_apache_child_terminate(TSRMLS_D)
+{
+       ap_child_terminate((request_rec *)SG(server_context));
+}
+/* }}} */
+
 /* {{{ sapi_module_struct apache_sapi_module
  */
 static sapi_module_struct apache_sapi_module = {
@@ -463,6 +471,7 @@ static sapi_module_struct apache_sapi_module = {
        sapi_apache_register_server_variables,          /* register server variables */
        php_apache_log_message,                 /* Log message */
        php_apache_get_request_time,    /* Get request time */
+       sapi_apache_child_terminate,
 
        NULL,                                                   /* php.ini path override */