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, &param 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, &param 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

Reply via email to