Fixes for pcntl - class support.

From: Date: Mon, 21 Jan 2002 08:59:13 +0000
Subject: Fixes for pcntl - class support.
Groups: php.dev 
Request: Send a blank email to php-dev+get-77648@lists.php.net to get a copy of this message
Well, after half a dozen bug reports that didnt actually work... - this one should, could somebody comment/commit etc. The patch includes a number of changes... - pcntl_zend_extension_active does not appear to be getting set when using modules this little magic trick to get the zval stored in the hash table for callbacks + MAKE_STD_ZVAL(handle_copy);
+        *handle_copy = **handle;
+        zval_copy_ctor(handle_copy);
I deleted this as it was confusing me alot :) - obviously not essential to the patch old_pcntl_signal_handler(int signo) added a new function pcntl_doevents = works a bit like gtk::do_events(); basically calls any pending signal callbacks. - as the pcntl_zend_extension_statement_handler did not appear to get called when running from a module. best regards alan Index: pcntl.c =================================================================== RCS file: /repository/php4/ext/pcntl/pcntl.c,v retrieving revision 1.18 diff -u -r1.18 pcntl.c
--- pcntl.c    4 Jan 2002 14:08:25 -0000    1.18
+++ pcntl.c    21 Jan 2002 08:36:05 -0000
@@ -18,7 +18,7 @@ /* $Id: pcntl.c,v 1.18 2002/01/04 14:08:25 hholzgra Exp $ */ -#define PCNTL_DEBUG 0 +#define PCNTL_DEBUG 0 #if PCNTL_DEBUG #define DEBUG_OUT printf("DEBUG: ");printf @@ -51,6 +51,7 @@
    PHP_FE(pcntl_wtermsig, NULL)
    PHP_FE(pcntl_wstopsig, NULL)
    PHP_FE(pcntl_exec, NULL)
+        PHP_FE(pcntl_doevents, NULL)
    {NULL, NULL, NULL}   };
@@ -208,7 +209,7 @@ PHP_FUNCTION(pcntl_fork) {
    pid_t id;
-
+        pcntl_zend_extension_active=1;
    id=fork();
    if (id == -1) {
        php_error(E_ERROR, "Error %d in %s", errno, get_active_function_name(TSRMLS_C));
@@ -463,8 +464,9 @@ PHP_FUNCTION(pcntl_signal) {
    zval **signo, **handle;
+        zval *handle_copy;
       char *func_name;
-
+          if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &signo, &handle) == FAILURE) {
        WRONG_PARAM_COUNT;
    }
@@ -474,7 +476,7 @@
    /* Special long value case for SIG_DFL and SIG_IGN */
    if (Z_TYPE_PP(handle)==IS_LONG) {
         if (Z_LVAL_PP(handle)!= (long) SIG_DFL && Z_LVAL_PP(handle) != (long) SIG_IGN) {
-             php_error(E_WARNING, "Invalid value for handle argument specifEied in %s", get_active_function_name(TSRMLS_C));
+             php_error(E_WARNING, "Invalid value for handle argument specified in %s", get_active_function_name(TSRMLS_C));
        }
        if (php_signal(Z_LVAL_PP(signo), (Sigfunc *) Z_LVAL_PP(handle))==SIG_ERR) {
            php_error(E_WARNING, "Error assigning singal in %s", get_active_function_name(TSRMLS_C));
@@ -483,22 +485,18 @@
        RETURN_TRUE;
    }
   -        if (Z_TYPE_PP(handle)!=IS_STRING) {
-        php_error(E_WARNING, "Invalid type specified for handle argument in %s", get_active_function_name(TSRMLS_C));
-        RETURN_FALSE;
-    }
-
-    convert_to_string_ex(handle); /* Just in case */
-    if (!zend_is_callable(*handle, 0, &func_name)) {
-        php_error(E_WARNING, "%s: %s is not a callable function name error", get_active_function_name(TSRMLS_C), func_name);
+       if (!zend_is_callable(*handle, 0, &func_name)) {
+        php_error(E_WARNING, "%s: Argument is not a callable function or method", get_active_function_name(TSRMLS_C), func_name);
           efree(func_name);
        RETURN_FALSE;
    }
       efree(func_name);
-
-        /* Add the function name to our signal table */
-    zend_hash_index_update(&PCNTL_G(php_signal_table), Z_LVAL_PP(signo), Z_STRVAL_PP(handle),  (Z_STRLEN_PP(handle) + 1) * sizeof(char), NULL);
-   +        MAKE_STD_ZVAL(handle_copy);
+        *handle_copy = **handle;
+        zval_copy_ctor(handle_copy);
+       +        zend_hash_index_update(&PCNTL_G(php_signal_table), Z_LVAL_PP(signo),  &handle_copy , sizeof(zval *), NULL);
+            if (php_signal(Z_LVAL_PP(signo), pcntl_signal_handler)==SIG_ERR) {
             php_error(E_WARNING, "Error assigning singal in %s", get_active_function_name(TSRMLS_C));
               RETURN_FALSE;
@@ -507,43 +505,14 @@ } /* }}} */ -/* Note Old */ -static void old_pcntl_signal_handler(int signo) -{
-    char *func_name;
-    zval *param, *call_name, *retval;
-    TSRMLS_FETCH();
-
-    DEBUG_OUT("Caught signal: %d\n", signo);
-    if (zend_hash_index_find(&PCNTL_G(php_signal_table), (long) signo, (void *) &func_name)==FAILURE) {
-        DEBUG_OUT("Signl handler not fount");
-        return;
-    }
-    /* DEBUG_OUT("Signal handler found, Calling %s\n", func_name); */   -    MAKE_STD_ZVAL(param);
-    MAKE_STD_ZVAL(call_name);
-    MAKE_STD_ZVAL(retval);
-    ZVAL_LONG(param, signo);
-     ZVAL_STRING(call_name, func_name, 1);
-
-    /* Call php singal handler - Note that we do not report errors, and we ignore the return value */
-    call_user_function(EG(function_table), NULL, call_name, retval, 1, &param TSRMLS_CC);
-   -     zval_dtor(call_name);
-    efree(call_name);
-    efree(param); -    efree(retval);
-
-    return;
-} - + /* Our custom signal handler that calls the appropriate php_function */ static void pcntl_signal_handler(int signo) {
    long signal_num=signo;
    TSRMLS_FETCH();
-    DEBUG_OUT("Caught signo %d\n", signo);
+    DEBUG_OUT("Caught signo %d,%d,%d\n", signo,PCNTL_G(processing_signal_queue),pcntl_zend_extension_active);
    if (! PCNTL_G(processing_signal_queue) && pcntl_zend_extension_active ) {
        zend_llist_add_element(&PCNTL_G(php_signal_queue), &signal_num);
        PCNTL_G(signal_queue_ready)=1;
@@ -588,59 +557,91 @@
    return;
} + /* Custom hook to ensure signals only get called at a safe poing in Zend's execute process */ void pcntl_zend_extension_statement_handler(zend_op_array *op_array) {
    zend_llist_element *element;
-    zval *param, *call_name, *retval;
+    zval *param, *retval;
+        zval **callback;
    char *func_name;
+        int   error;
    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))
        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;
    }
-      +
    /* Disable queue so this function is not infinate */
    PCNTL_G(processing_signal_queue)=1;         /* Allocate */
    MAKE_STD_ZVAL(param);
-    MAKE_STD_ZVAL(call_name);
-    MAKE_STD_ZVAL(retval);
+     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 *) &func_name)==FAILURE) {
+                DEBUG_OUT("sig %d\n",*signal_num);
+              +
+        if (zend_hash_index_find(&PCNTL_G(php_signal_table), *signal_num,  (void **) &callback)==FAILURE) {
+                        php_error(E_WARNING, "%s: Signal callback for %d Not found", get_active_function_name(TSRMLS_C),*signal_num);
+                        DEBUG_OUT("NOT FOUND");
            continue;
        }
+                if (!zend_is_callable( *callback, 0, &func_name)) {
+                    php_error(E_WARNING, "%s: %s is not a callable function or method", func_name, get_active_function_name(TSRMLS_C));
+                    continue;
+                }   +                       convert_to_long_ex(&param);
-        convert_to_string_ex(&call_name);
-        ZVAL_LONG(param, *signal_num);
-        ZVAL_STRING(call_name, func_name, 0);
-      -        /* Call php singal handler - Note that we do not report errors, and we ignore the return value */
-        call_user_function(EG(function_table), NULL, call_name, retval, 1, &param TSRMLS_CC);
+            ZVAL_LONG(param, *signal_num);
+         +         /* Call php singal handler - Note that we do not report errors, and we ignore the return value */
+        error = call_user_function(EG(function_table), NULL,   *callback,  retval, 1, &param   TSRMLS_CC);
+                if (error == FAILURE) {
+            php_error(E_WARNING, "Couldn't call the SIGNAL FUNCTION");
+             +        }
    }
+    +       +           /* Clear */
-    zend_llist_clean(&PCNTL_G(php_signal_queue));
-
+     zend_llist_clean(&PCNTL_G(php_signal_queue));
+
    /* Re-enable queue */
    PCNTL_G(processing_signal_queue)=0;
    /* Clean up */
    efree(param);
-    efree(call_name);
+     //efree(callback);
    efree(retval);
+     +       +}
+ + +/* {{{ proto bool pcntl_doevents() + Calls any pending events - if you compile pcntl as a module, the + statement handler does not work, you have to do it manually */ +PHP_FUNCTION(pcntl_doevents) +{
+    zend_op_array *op_array=NULL;
+    TSRMLS_FETCH();
+
+    pcntl_zend_extension_statement_handler(op_array);
+   +    RETURN_TRUE;   }
+/* }}} */ /* * Local variables: -------------------------- Class example -------------------- #!/opt/devel/php4/php -q <? dl("pcntl.so"); class test { var $run=1; function alarm_handle($signal){
                 if ($signal==SIGALRM) {
               print "Caught SIGALRM!!!\n";
                        }
} function usr1_handle($signal){
            if ($signal==SIGUSR1) {
                print "Caught SIGUSR1!!!\n";
                 $this->run = 0;
            }       }
     function start() {
       //$options=NULL;
       //$status=NULL;
       print "This test will demonstrate a fork followed by ipc via signals.\n";
             $pid=pcntl_fork();
       if ($pid==0) {
          pcntl_signal(SIGUSR1, array(&$this,"usr1_handle"));
          pcntl_signal(SIGALRM, array(&$this,"alarm_handle"));
          $this->run =1;
          while($this->run) {
              echo $this->run;
              usleep(1);
              pcntl_doevents();
                     }
           print "ChildDone\n";
          pcntl_signal(SIGALRM, SIG_IGN); // kill parent!
           posix_kill($pid,SIGTERM); // kill myself
       } else {
          print "Parent: Waiting 10 seconds....\n";
          usleep(2);
          print "Parent: Sending SIGALRM to Child\n";
          posix_kill($pid,SIGALRM);
           sleep(2);
          print "Parent: Senging SIGUSR1 to Child\n";
          posix_kill($pid,SIGUSR1);
           sleep(2);
          print "Parent: Sending SIGALRM to Child\n";
                    @pcntl_waitpid($pid,  $status, $options);
       }
} } $test = new test(); $test->start(); posix_kill(posix_getpid(),SIGTERM);

« previous php.dev (#77648) next »