php process learning

Keywords: PHP Linux

1. What signals are in the Linux operating system
1. Brief introduction of signal

Signals are a mechanism for notifying a process when an event occurs, sometimes referred to as software interrupts. A process can send a signal to another process, such as SIGCHLD (signal 17) to the parent process at the end of a child process, to notify the parent process, so sometimes the signal is also used as a mechanism for inter-process communication.
Under linux system, we usually use kill-9 XXPID to end a process. In fact, the essence of this command is to send SIGKILL (signal 9) to a process. For foreground processes, we usually use Ctrl+c shortcut to end running. The essence of this shortcut is to send SIGINT (signal 2) to the current process. The default behavior for a process to receive this signal is to end running.

2. Common Signals
The signals below can be viewed using the kill-l command

Below are several important and commonly used signals:

2. Processing signal correlation functions in PHP
The pcntl and posix extensions of PHP provide us with several ways to manipulate signals (these extensions need to be installed before using these functions)
Below are a few specific ways that I have used in this task:
declare
The declare structure is used to set execution instructions for a piece of code. The syntax of declare is similar to other process control structures.

declare (directive)
statement

The directive section allows you to set the behavior of the declare snippet. Only two directives are currently known: ticks and encoding. The statement portion of the declare snippet will be executed - how it is executed and what side effects it will have depending on the directive
Ticks
Tick (clock cycle) is an event that occurs every N Timeable low-level statements executed by the interpreter in the declare code snippet. The value of N is specified in ticks=N in the directive part of the declare. Not all statements are Timeable. Normally conditional and parameter expressions are not Timeable. Events occurring in each tick are regist_tick_function()To specify, note that multiple events can occur in each tick in more detail, you can view the official documents:https://www.php.net/manual/zh/control-structures.declare.php

<?php
declare(ticks=1);//Trigger a register_tick_function() registered function every time an item is executed
$a=1;//Not before registration
function test(){//Define a function
 echo "implement\n";
}
register_tick_function('test');//This registration function is executed as a low-level statement
for($i=0;$i<=2;$i++){//for calculates a low-level statement
 $i=$i;//Assignment evaluates to one
}

Output: Six Executions
pcntl_signal
pcntl_signal, install a signal processor

 pcntl_signal ( int $signo , callback $handler [, bool $restart_syscalls = true ] ) : bool

The function pcntl_signal() installs a new signal processor for the signal specified by signo

 declare(ticks = 1);
pcntl_signal(SIGINT,function(){
 echo "You pressed Ctrl+C".PHP_EOL;
});
while(1){
    sleep(1);//Dead-loop running low-level statements
}

Output: When Ctrl+C is pressed, the output "You pressed Ctrl+C"
posix_kill
posix_kill, sends a signal to the process

posix_kill ( int $pid , int $sig ) : bool
The first parameter is the process ID and the second is the signal you want to send

a.php

<?php
declare(ticks = 1);
echo getmypid();//Get the current process id
pcntl_signal(SIGINT,function(){
 echo "You sent it to me SIGINT signal";
});
while(1){
    sleep(1);
}

b.php

<?php
posix_kill(Execution 1.php Process output when id, SIGINT);
pcntl_signal_dispatch
pcntl_signal_dispatch,Call the processor waiting for the signal

pcntl_signal_dispatch ( void ) : bool
The function pcntl_signal_dispatch() calls each processor that waits for a signal to be installed via pcntl_signal()

 <?php
echo "Install signal processor...\n";
pcntl_signal(SIGHUP,  function($signo) {
 echo "Signal processor called\n";
});
echo "Generate for yourself SIGHUP signal...\n";
posix_kill(posix_getpid(), SIGHUP);
echo "distribute...\n";
pcntl_signal_dispatch();
echo "complete\n";
?>

Output:
Install signal processor...
Generate SIGHUP signal for yourself...
Distribute...
Signal processor called
complete
pcntl_async_signals()

Asynchronous signal processing, used to enable asynchronous signal processing without ticks (which incurs a lot of extra overhead). (PHP>=7.1)

 <?php
pcntl_async_signals(true); // turn on async signals

pcntl_signal(SIGHUP,  function($sig) {
 echo "SIGHUP\n";
});

posix_kill(posix_getpid(), SIGHUP);

Output:
SIGHUP
3. Ways of handling semaphores in PHP
Previously, we knew that we could listen for signals in a combination of declare(ticks=1) and pcntl_signal, that is, each PHP low-level statement would check once for unprocessed signals from the current process, which is very performance-intensive.

pcntl_signal is implemented by adding the signal to a queue after triggering the signal, then checking the ticks callback function in PHP for signals, executing the callback function specified in PHP if there is a signal, or jumping out of the function if there is no signal.

 PHP_MINIT_FUNCTION(pcntl)
{
 php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
 php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
 php_add_tick_function(pcntl_signal_dispatch TSRMLS_CC);

 return SUCCESS;
}

After PHP 5.3, there is the pcntl_signal_dispatch function. At this point, declare is not required, just add the function in the loop to call the signal through:

 <?php
echo getmypid();//Get the current process id
pcntl_signal(SIGUSR1,function(){
 echo "Trigger Signal User-defined Signal 1";
});
while(1){
    pcntl_signal_dispatch();
    sleep(1);//Dead-loop running low-level statements
}

It is well known that ticks=1 for PHP calls back this function for every line of PHP code executed. In fact, there is no signal generated for most of the time, but ticks functions are always executed. If a server program receives 1000 requests in a second, the average number of PHP lines per request is executed. Then pcntl_signal for PHP brings in an additional 1000 *1000, or 1 million empty function calls. This wastes a lot of CPU resources. It is better to remove ticks and use pcntl_signal_dispatch instead to process the signals in the code loop. Implementation of the pcntl_signal_dispatch function:

 void pcntl_signal_dispatch()
{
 //....Omit a part of the code here, queue is the signal queue
 while (queue) {
 if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {
   ZVAL_NULL(&retval);
   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_ptr_dtor(&param);
   zval_ptr_dtor(&retval);
  }
  next = queue->next;
  queue->next = PCNTL_G(spares);
  PCNTL_G(spares) = queue;
  queue = next;
 }
}

But there's also a nausea about the above: it has to be placed in an endless loop. After PHP7.1 comes out a function that completes asynchronous signal reception and processing: pcntl_async_signals

 <?php
//a.php
echo getmypid();
pcntl_async_signals(true);//Turn on asynchronous listening signal
pcntl_signal(SIGUSR1,function(){
 echo "Trigger signal";
    posix_kill(getmypid(),SIGSTOP);
});
posix_kill(getmypid(),SIGSTOP);//Send pause signal to process

//b.php
posix_kill(File 1 Process, SIGCONT);//Send a continuation signal to the process
posix_kill(File 1 Process, SIGUSR1);//Send user1 signal to process
 adopt pcntl_async_signals Method, there is no need to write dead loop.

Package for monitoring signals:

composer require rain-life/monitor-signal

Posted by akumakeenta on Mon, 20 Sep 2021 01:23:46 -0700