@@ -162,17 +162,13 @@ void php_register_signal_constants(INIT_FUNC_ARGS)
162
162
163
163
static void php_pcntl_init_globals (zend_pcntl_globals * pcntl_globals )
164
164
{
165
- /* Just in case ... */
166
- memset (& pcntl_globals -> php_signal_queue ,0 ,sizeof (pcntl_globals -> php_signal_queue ));
167
-
168
- zend_llist_init (& pcntl_globals -> php_signal_queue , sizeof (long ), NULL , 1 );
169
- pcntl_globals -> signal_queue_ready = 0 ;
170
- pcntl_globals -> processing_signal_queue = 0 ;
165
+ memset (pcntl_globals , 0 , sizeof (* pcntl_globals ));
171
166
}
172
167
173
168
PHP_RINIT_FUNCTION (pcntl )
174
169
{
175
- zend_hash_init (& PCNTL_G (php_signal_table ), 16 , NULL , ZVAL_PTR_DTOR , 1 );
170
+ zend_hash_init (& PCNTL_G (php_signal_table ), 16 , NULL , ZVAL_PTR_DTOR , 0 );
171
+ PCNTL_G (head ) = PCNTL_G (tail ) = PCNTL_G (spares ) = NULL ;
176
172
return SUCCESS ;
177
173
}
178
174
@@ -187,13 +183,26 @@ PHP_MINIT_FUNCTION(pcntl)
187
183
188
184
PHP_MSHUTDOWN_FUNCTION (pcntl )
189
185
{
190
- zend_llist_destroy (& PCNTL_G (php_signal_queue ));
191
186
return SUCCESS ;
192
187
}
193
188
194
189
PHP_RSHUTDOWN_FUNCTION (pcntl )
195
190
{
191
+ struct php_pcntl_pending_signal * sig ;
192
+
193
+ /* FIXME: if a signal is delivered after this point, things will go pear shaped;
194
+ * need to remove signal handlers */
196
195
zend_hash_destroy (& PCNTL_G (php_signal_table ));
196
+ while (PCNTL_G (head )) {
197
+ sig = PCNTL_G (head );
198
+ PCNTL_G (head ) = sig -> next ;
199
+ efree (sig );
200
+ }
201
+ while (PCNTL_G (spares )) {
202
+ sig = PCNTL_G (spares );
203
+ PCNTL_G (spares ) = sig -> next ;
204
+ efree (sig );
205
+ }
197
206
return SUCCESS ;
198
207
}
199
208
@@ -520,6 +529,19 @@ PHP_FUNCTION(pcntl_signal)
520
529
return ;
521
530
}
522
531
532
+ if (!PCNTL_G (spares )) {
533
+ /* since calling malloc() from within a signal handler is not portable,
534
+ * pre-allocate a few records for recording signals */
535
+ int i ;
536
+ for (i = 0 ; i < 32 ; i ++ ) {
537
+ struct php_pcntl_pending_signal * psig ;
538
+
539
+ psig = emalloc (sizeof (* psig ));
540
+ psig -> next = PCNTL_G (spares );
541
+ PCNTL_G (spares ) = psig ;
542
+ }
543
+ }
544
+
523
545
/* Special long value case for SIG_DFL and SIG_IGN */
524
546
if (Z_TYPE_P (handle )== IS_LONG ) {
525
547
if (Z_LVAL_P (handle )!= (long ) SIG_DFL && Z_LVAL_P (handle ) != (long ) SIG_IGN ) {
@@ -631,57 +653,63 @@ PHP_FUNCTION(pcntl_setpriority)
631
653
/* Our custom signal handler that calls the appropriate php_function */
632
654
static void pcntl_signal_handler (int signo )
633
655
{
634
- long signal_num = signo ;
656
+ struct php_pcntl_pending_signal * psig ;
635
657
TSRMLS_FETCH ();
636
658
637
- IF_DEBUG (DEBUG_OUT ("Caught signo %d\n" , signo ));
638
- if (! PCNTL_G (processing_signal_queue )) {
639
- zend_llist_add_element (& PCNTL_G (php_signal_queue ), & signal_num );
640
- PCNTL_G (signal_queue_ready ) = 1 ;
641
- IF_DEBUG (DEBUG_OUT ("Added queue entry\n" ));
659
+ psig = PCNTL_G (spares );
660
+ if (!psig ) {
661
+ /* oops, too many signals for us to track, so we'll forget about this one */
662
+ return ;
663
+ }
664
+ PCNTL_G (spares ) = psig -> next ;
665
+
666
+ psig -> signo = signo ;
667
+ psig -> next = NULL ;
668
+
669
+ /* the head check is important, as the tick handler cannot atomically clear both
670
+ * the head and tail */
671
+ if (PCNTL_G (head ) && PCNTL_G (tail )) {
672
+ PCNTL_G (tail )-> next = psig ;
673
+ } else {
674
+ PCNTL_G (head ) = psig ;
642
675
}
643
- return ;
676
+ PCNTL_G ( tail ) = psig ;
644
677
}
645
678
646
679
void pcntl_tick_handler ()
647
680
{
648
- zend_llist_element * element ;
649
681
zval * param , * * handle , * retval ;
682
+ struct php_pcntl_pending_signal * queue , * next ;
650
683
TSRMLS_FETCH ();
651
684
652
685
/* Bail if the queue is empty or if we are already playing the queue*/
653
- if (! PCNTL_G (signal_queue_ready ) || PCNTL_G (processing_signal_queue ))
686
+ if (! PCNTL_G (head ) || PCNTL_G (processing_signal_queue ))
654
687
return ;
655
688
656
- /* Mark our queue empty */
657
- PCNTL_G (signal_queue_ready ) = 0 ;
658
-
659
- /* If for some reason our signal queue is empty then return */
660
- if (zend_llist_count (& PCNTL_G (php_signal_queue )) <= 0 ) {
661
- return ;
662
- }
663
-
664
689
/* Prevent reentrant handler calls */
665
690
PCNTL_G (processing_signal_queue ) = 1 ;
666
691
692
+ queue = PCNTL_G (head );
693
+ PCNTL_G (head ) = NULL ; /* simple stores are atomic */
694
+
667
695
/* Allocate */
668
696
MAKE_STD_ZVAL (param );
669
697
MAKE_STD_ZVAL (retval );
670
698
671
- /* Traverse through our signal queue and call the appropriate php functions */
672
- for (element = (& PCNTL_G (php_signal_queue ))-> head ; element ; element = element -> next ) {
673
- long * signal_num = (long * )& element -> data ;
674
- if (zend_hash_index_find (& PCNTL_G (php_signal_table ), * signal_num , (void * * ) & handle )== FAILURE ) {
675
- continue ;
699
+ while (queue ) {
700
+ if (zend_hash_index_find (& PCNTL_G (php_signal_table ), queue -> signo , (void * * ) & handle )== SUCCESS ) {
701
+ ZVAL_LONG (param , queue -> signo );
702
+
703
+ /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
704
+ /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
705
+ call_user_function (EG (function_table ), NULL , * handle , retval , 1 , & param TSRMLS_CC );
676
706
}
677
707
678
- ZVAL_LONG ( param , * signal_num ) ;
679
-
680
- /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
681
- call_user_function ( EG ( function_table ), NULL , * handle , retval , 1 , & param TSRMLS_CC ) ;
708
+ next = queue -> next ;
709
+ queue -> next = PCNTL_G ( spares );
710
+ PCNTL_G ( spares ) = queue ;
711
+ queue = next ;
682
712
}
683
- /* Clear */
684
- zend_llist_clean (& PCNTL_G (php_signal_queue ));
685
713
686
714
/* Re-enable queue */
687
715
PCNTL_G (processing_signal_queue ) = 0 ;
@@ -691,6 +719,8 @@ void pcntl_tick_handler()
691
719
efree (retval );
692
720
}
693
721
722
+
723
+
694
724
/*
695
725
* Local variables:
696
726
* tab-width: 4
0 commit comments