wez Sat May 7 10:55:40 2005 EDT Modified files: (Branch: PHP_4_3) /php-src NEWS /php-src/ext/pcntl pcntl.c php_pcntl.h test-pcntl.php Log: Fix #32974
http://cvs.php.net/diff.php/php-src/NEWS?r1=1.1247.2.894&r2=1.1247.2.895&ty=u Index: php-src/NEWS diff -u php-src/NEWS:1.1247.2.894 php-src/NEWS:1.1247.2.895 --- php-src/NEWS:1.1247.2.894 Thu May 5 22:19:03 2005 +++ php-src/NEWS Sat May 7 10:55:39 2005 @@ -7,6 +7,7 @@ them sort based on the current locale. (Derick) - Changed sha1_file() and md5_file() functions to use streams instead of low level IO. (Uwe) +- Fixed bug #32974 (pcntl calls malloc() from a signal handler). (Wez) - Fixed bug #32936 (http redirects URLs are not checked for control chars). (Ilia) - Fixed bug #32813 (parse_url() does not handle scheme-only urls properly). (Ilia) - Fixed bug #32802 (General cookie overrides more specific cookie). (Ilia) http://cvs.php.net/diff.php/php-src/ext/pcntl/pcntl.c?r1=1.28.4.5&r2=1.28.4.6&ty=u Index: php-src/ext/pcntl/pcntl.c diff -u php-src/ext/pcntl/pcntl.c:1.28.4.5 php-src/ext/pcntl/pcntl.c:1.28.4.6 --- php-src/ext/pcntl/pcntl.c:1.28.4.5 Tue Jun 29 21:12:09 2004 +++ php-src/ext/pcntl/pcntl.c Sat May 7 10:55:39 2005 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: pcntl.c,v 1.28.4.5 2004/06/30 01:12:09 iliaa Exp $ */ +/* $Id: pcntl.c,v 1.28.4.6 2005/05/07 14:55:39 wez Exp $ */ #define PCNTL_DEBUG 0 @@ -139,17 +139,13 @@ static void php_pcntl_init_globals(zend_pcntl_globals *pcntl_globals) { - /* Just in case ... */ - memset(&pcntl_globals->php_signal_queue,0,sizeof(pcntl_globals->php_signal_queue)); - - zend_llist_init(&pcntl_globals->php_signal_queue, sizeof (long), NULL, 1); - pcntl_globals->signal_queue_ready = 0; - pcntl_globals->processing_signal_queue = 0; + memset(pcntl_globals, 0, sizeof(*pcntl_globals)); } PHP_RINIT_FUNCTION(pcntl) { - zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 1); + zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0); + PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL; return SUCCESS; } @@ -164,13 +160,26 @@ PHP_MSHUTDOWN_FUNCTION(pcntl) { - zend_llist_destroy(&PCNTL_G(php_signal_queue)); return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(pcntl) { + struct php_pcntl_pending_signal *sig; + + /* FIXME: if a signal is delivered after this point, things will go pear shaped; + * need to remove signal handlers */ zend_hash_destroy(&PCNTL_G(php_signal_table)); + while (PCNTL_G(head)) { + sig = PCNTL_G(head); + PCNTL_G(head) = sig->next; + efree(sig); + } + while (PCNTL_G(spares)) { + sig = PCNTL_G(spares); + PCNTL_G(spares) = sig->next; + efree(sig); + } return SUCCESS; } @@ -467,6 +476,19 @@ return; } + if (!PCNTL_G(spares)) { + /* since calling malloc() from within a signal handler is not portable, + * pre-allocate a few records for recording signals */ + int i; + for (i = 0; i < 32; i++) { + struct php_pcntl_pending_signal *psig; + + psig = emalloc(sizeof(*psig)); + psig->next = PCNTL_G(spares); + PCNTL_G(spares) = psig; + } + } + /* Special long value case for SIG_DFL and SIG_IGN */ if (Z_TYPE_P(handle)==IS_LONG) { if (Z_LVAL_P(handle)!= (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) { @@ -501,57 +523,63 @@ /* Our custom signal handler that calls the appropriate php_function */ static void pcntl_signal_handler(int signo) { - long signal_num = signo; + struct php_pcntl_pending_signal *psig; TSRMLS_FETCH(); - IF_DEBUG(DEBUG_OUT("Caught signo %d\n", signo)); - if (! PCNTL_G(processing_signal_queue)) { - zend_llist_add_element(&PCNTL_G(php_signal_queue), &signal_num); - PCNTL_G(signal_queue_ready) = 1; - IF_DEBUG(DEBUG_OUT("Added queue entry\n")); + psig = PCNTL_G(spares); + if (!psig) { + /* oops, too many signals for us to track, so we'll forget about this one */ + return; } - return; + PCNTL_G(spares) = psig->next; + + psig->signo = signo; + psig->next = NULL; + + /* the head check is important, as the tick handler cannot atomically clear both + * the head and tail */ + if (PCNTL_G(head) && PCNTL_G(tail)) { + PCNTL_G(tail)->next = psig; + } else { + PCNTL_G(head) = psig; + } + PCNTL_G(tail) = psig; } void pcntl_tick_handler() { - zend_llist_element *element; zval *param, **handle, *retval; + struct php_pcntl_pending_signal *queue, *next; TSRMLS_FETCH(); /* Bail if the queue is empty or if we are already playing the queue*/ - if (! PCNTL_G(signal_queue_ready) || PCNTL_G(processing_signal_queue)) + if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue)) return; - /* Mark our queue empty */ - PCNTL_G(signal_queue_ready) = 0; - - /* If for some reason our signal queue is empty then return */ - if (zend_llist_count(&PCNTL_G(php_signal_queue)) <= 0) { - return; - } - /* Prevent reentrant handler calls */ PCNTL_G(processing_signal_queue) = 1; + queue = PCNTL_G(head); + PCNTL_G(head) = NULL; /* simple stores are atomic */ + /* Allocate */ MAKE_STD_ZVAL(param); MAKE_STD_ZVAL(retval); - /* Traverse through our signal queue and call the appropriate php functions */ - for (element = (&PCNTL_G(php_signal_queue))->head; element; element = element->next) { - long *signal_num = (long *)&element->data; - if (zend_hash_index_find(&PCNTL_G(php_signal_table), *signal_num, (void **) &handle)==FAILURE) { - continue; + while (queue) { + if (zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo, (void **) &handle)==SUCCESS) { + ZVAL_LONG(param, queue->signo); + + /* Call php signal handler - Note that we do not report errors, and we ignore the return value */ + /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */ + call_user_function(EG(function_table), NULL, *handle, retval, 1, ¶m TSRMLS_CC); } - ZVAL_LONG(param, *signal_num); - - /* Call php signal handler - Note that we do not report errors, and we ignore the eturn value */ - call_user_function(EG(function_table), NULL, *handle, retval, 1, ¶m TSRMLS_CC); + next = queue->next; + queue->next = PCNTL_G(spares); + PCNTL_G(spares) = queue; + queue = next; } - /* Clear */ - zend_llist_clean(&PCNTL_G(php_signal_queue)); /* Re-enable queue */ PCNTL_G(processing_signal_queue) = 0; http://cvs.php.net/diff.php/php-src/ext/pcntl/php_pcntl.h?r1=1.11.4.2&r2=1.11.4.3&ty=u Index: php-src/ext/pcntl/php_pcntl.h diff -u php-src/ext/pcntl/php_pcntl.h:1.11.4.2 php-src/ext/pcntl/php_pcntl.h:1.11.4.3 --- php-src/ext/pcntl/php_pcntl.h:1.11.4.2 Thu Jun 5 19:48:17 2003 +++ php-src/ext/pcntl/php_pcntl.h Sat May 7 10:55:39 2005 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_pcntl.h,v 1.11.4.2 2003/06/05 23:48:17 iliaa Exp $ */ +/* $Id: php_pcntl.h,v 1.11.4.3 2005/05/07 14:55:39 wez Exp $ */ #ifndef PHP_PCNTL_H #define PHP_PCNTL_H @@ -51,12 +51,17 @@ PHP_FUNCTION(pcntl_signal); PHP_FUNCTION(pcntl_exec); +struct php_pcntl_pending_signal { + struct php_pcntl_pending_signal *next; + long signo; +}; + ZEND_BEGIN_MODULE_GLOBALS(pcntl) HashTable php_signal_table; - zend_llist php_signal_queue; - int signal_queue_ready; int processing_signal_queue; + struct php_pcntl_pending_signal *head, *tail, *spares; ZEND_END_MODULE_GLOBALS(pcntl) + #ifdef ZTS #define PCNTL_G(v) TSRMG(pcntl_globals_id, zend_pcntl_globals *, v) #else http://cvs.php.net/diff.php/php-src/ext/pcntl/test-pcntl.php?r1=1.3&r2=1.3.4.1&ty=u Index: php-src/ext/pcntl/test-pcntl.php diff -u php-src/ext/pcntl/test-pcntl.php:1.3 php-src/ext/pcntl/test-pcntl.php:1.3.4.1 --- php-src/ext/pcntl/test-pcntl.php:1.3 Thu Aug 22 00:20:10 2002 +++ php-src/ext/pcntl/test-pcntl.php Sat May 7 10:55:39 2005 @@ -4,11 +4,11 @@ declare(ticks=1); function alarm_handle($signal){ - if ($signal==SIGALRM) print "Caught SIGALRM!!!\n"; + if ($signal==SIGALRM) print "Child: Caught SIGALRM!!!\n"; } function usr1_handle($signal){ - if ($signal==SIGUSR1) print "Caught SIGUSR1!!!\n"; + if ($signal==SIGUSR1) print "Child: Caught SIGUSR1!!!\n"; } print "This test will demonstrate a fork followed by ipc via signals.\n"; @@ -23,6 +23,7 @@ sleep(100); print "Child: Resetting Alarm handler to Ignore....\n"; pcntl_signal(SIGALRM, SIG_IGN); + print "Child: sleeping for 10 seconds....\n"; sleep(10); print "Done\n"; } else { @@ -33,7 +34,7 @@ sleep(1); print "Parent: Senging SIGUSR1 to Child\n"; posix_kill($pid,SIGUSR1); - sleep(1); + sleep(2); print "Parent: Sending SIGALRM to Child\n"; pcntl_waitpid($pid, &$status, $options); }
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php