]> granicus.if.org Git - php/commitdiff
MFB: Fix for #32974
authorWez Furlong <wez@php.net>
Sat, 7 May 2005 14:58:02 +0000 (14:58 +0000)
committerWez Furlong <wez@php.net>
Sat, 7 May 2005 14:58:02 +0000 (14:58 +0000)
ext/pcntl/pcntl.c
ext/pcntl/php_pcntl.h
ext/pcntl/test-pcntl.php

index 6a9c304f2f2f6144fca747a5420ad2e0dc7f714f..b3a0efb768436edc475a49713b0a1d730bd6e813 100755 (executable)
@@ -162,17 +162,13 @@ void php_register_signal_constants(INIT_FUNC_ARGS)
 
 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;
 }
 
@@ -187,13 +183,26 @@ PHP_MINIT_FUNCTION(pcntl)
 
 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;
 }
 
@@ -520,6 +529,19 @@ PHP_FUNCTION(pcntl_signal)
                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) {
@@ -631,57 +653,63 @@ PHP_FUNCTION(pcntl_setpriority)
 /* 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;
+       }
+       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;
        }
-       return;
+       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 return 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;
@@ -691,6 +719,8 @@ void pcntl_tick_handler()
        efree(retval);
 }
 
+
+
 /*
  * Local variables:
  * tab-width: 4
index 590d5779bd40b8c694db3983fdcca7d323df6c54..762d2498681b156c284248ec1ba50772f1ed71d6 100644 (file)
@@ -58,12 +58,17 @@ PHP_FUNCTION(pcntl_getpriority);
 PHP_FUNCTION(pcntl_setpriority);
 #endif
 
+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
index 6b3ee5649ef98e6b2b1ceb0d886a941ea223c1f8..01d44fcad45ca62f779586ab9a5e4eb9697b5cbf 100755 (executable)
@@ -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 @@ if ($pid==0) {
        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 @@ if ($pid==0) {
        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);
 }