OpenSwoole Coroutine System: waitSignal

Latest version: pecl install openswoole-22.1.2 | composer require openswoole/core:22.1.5

Declaration

<?php OpenSwoole\Coroutine\System::waitSignal(int $signalNum, float $timeout = -1): bool

Parameters

signalNum

The Linux signal type, this can be something like SIGTERM, SIGKILL etc. The specified signal is what the process will wait for until the signal is triggered.

timeout

A float in seconds defining how long the process should wait before giving up and returning control. Because a float is used, it means that 2.5 is 2.5 seconds. Minimum value is 0.001 and the default -1 means to never time out, wait for the other process to finish.

Return

Returns true when the specified signal is received and false when the signal was not received or if it timed out.

Description

Wait for a process to finish based on the specified signal type, until the signal type is received, the parent process will wait, allowing you to listen for a specific signal.

To learn more about Linux signal types, checkout this post as there are a whole range of different signals for different situations.

As an alternative you can use OpenSwoole\Process::signal but the pcntl_signal function should NOT be used within a coroutine context, it is not supported.


Example

Using SIGUSR1 to kill the main process

<?php

use OpenSwoole\Process;
use OpenSwoole\Coroutine;
use OpenSwoole\Coroutine\System;

// Get the main thread process ID
$pid = getmypid();

// Create the process only outside a coroutine
$process = new OpenSwoole\Process(function() use ($pid)
{
    echo "Child process start.\n";

    sleep(1);

    // Send a signal to kill the main process but let the process handle the kill event...
    OpenSwoole\Process::kill($pid, SIGUSR1);

    echo "Child process exit.\n";
});

// Begin the process
$process->start();

// Entering a coroutine context
co::run(function()
{
    // Wait for a user defined kill signal to handle, wait 3 seconds at max
    $info = OpenSwoole\Coroutine\System::waitSignal(SIGUSR1, 3);
    var_dump($info);
});

Output:

Child process start
Child process exit
bool(true)

The above code works and does not kill the parent before it can wait for the signal because the kill signal SIGUSR1 allows us to handle the kill event. The signal SIGUSR1 is used for when you want to allow the process to handle the signal event itself, so in our example, the main process can wait for the signal to be triggered. Allowing a developer to write their own signal handler.


Using SIGUSR1 to kill the child process from the main process

<?php

use OpenSwoole\Process;
use OpenSwoole\Coroutine;
use OpenSwoole\Coroutine\System;

// Creating the process outside of a coroutine
$process = new Process(function()
{
    // Using a coroutine context inside of a child process
    co::run(function()
    {
      echo "Inside child process...\n";

        // Signal handler
        $status = System::waitSignal(SIGUSR1);
        var_dump($status);

        echo "End of child process.\n";
    });
});

// Start the child process...
$process->start();

sleep(1);

echo "Sending kill signal to child process...\n";

// Send a signal to the child process but let it handle the event using SIGUSR1
OpenSwoole\Process::kill($process->pid, SIGUSR1);

echo "End of main process.\n";

Output:

Inside child process...
Sending kill signal to child process...
End of main process.
bool(true)
End of child process.

Again this works because the kill signal SIGUSR1 allows us to use our own custom signal handler. If no handler is set then the process will just be terminated, that is why the waitSignal call is important. The main process does not use a co::run coroutine container because it is not needed in this example but you could use one if you wanted, just make sure to pass in the $process object so it has access to it.

Last updated on September 1, 2022