Alan,

First of all, thanks for submitting a patch. I alwyas like getting
patches : ) 

I need to spend some time reviewing this, unfortunately my time has been
very limited lately (working 90-100 hour weeks with my current
employer). I should be able to get to this sometime tonight.

I do have some initital questions:


On Mon, 2002-01-21 at 02:59, Alan Knowles wrote:
> 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

Can you explain what you mean by modules, are you refering to building
as a dynamic .so?

> 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)
>

Yes, that was the unsafe async callback : ) I should remove it, but I
left it there for reference.
 
> 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.

Can you explain how you are/would be using this function. The reason why
pcntl_zend_extension_statement_handler is set to s zend_statement_handle
is becuase there is the possibiilty that PHP/Zend could be in the
process of chaging an internal datastructure when a signal is recieved,
and if another php routine is executed at that state of time, corruption
could possibly occur, resulting in a segfault. Insuring that a php
signal handle is only executed between opcodes makes pcntl async safe.

> 
> 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);
>  
> 
> 
> 
> 
> 
> 
> 
> 
> 






-- 
Jason T. Greene
Internet Software Engineer

<[EMAIL PROTECTED]>
<[EMAIL PROTECTED]> 
<[EMAIL PROTECTED]>

Use PHP: http://www.php.net



-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]

Reply via email to