PHP IPC Signal Example

Mai 24th, 2013

There are several pitfalls when using POSIX signal handling with php. The following example should help to get around them.

The example forks a child process and afterwards sends the SIGTERM signal to the child. I’ll guide you through the important sections:

<?php
declare(ticks=1);

Declare ticks is essential for signal handling in PHP. If not declared, signals will not being passed to the script.

$term = FALSE;

Define a flag which will later being used to determine if SIGTERM has been arrived.

function handler() {
    global $term;
    $term = TRUE;
}

The signal handler method. The handler should contain as less actions as possible. This is a general advice for signal handlers (not just for PHP). If the signal handler contains much actions and will take long to process, it may happen that following signals get blocked.

pcntl_signal(SIGTERM, 'handler');

Register the signal handler for SIGTERM

$pid = pcntl_fork();

For current process

if($pid === 0) {
    echo "child: started\n";
    while(TRUE) {
        if($term) {
            echo "child: exit\n";
            exit(2);
        }   
        usleep(100000);
    }   

In the child process $pid will be „ after forking. The code above is the child code. It runs in a infinite loop and checks if the $term flag was set. If so, it terminates itself.

It follows the father’s code:

} else {
    echo "father: started $pid\n";
    // kill the child
    echo "father: send SIGTERM\n";
    posix_kill($pid, SIGTERM);

Use posix_kill() to send SIGTERM to child.

    $pid = pcntl_waitpid($pid, $status);
    echo "father: child exited $status\n";
}

Now wait until the child has exited to grab it’s return value.


Here comes the complete solution:

<?php

declare(ticks=1);

$term = FALSE;
function handler() {
    global $term;
    $term = TRUE;
}

pcntl_signal(SIGTERM, 'handler');

$pid = pcntl_fork();
if($pid === 0) {
    echo "child: started\n";
    while(TRUE) {
        if($term) {
            echo "child: exit\n";
            exit(2);
        }
        usleep(100000);
    }
} else {
    echo "father: started $pid\n";
    // kill the child
    echo "father: send SIGTERM\n";
    posix_kill($pid, SIGTERM);
    // wait until child exit
    $pid = pcntl_waitpid($pid, $status);
    echo "father: child exited $status\n";
}

Leave a Reply