2

I'm having some problems with pcntl_signal not receiving a signal sent from another process. I have a script that forks a new process, fires up 2 background threads and then loops the controller (main) thread until it receives a stop signal (SIGUSR1) but the signal is never received. Here's my thread code (simply logs in a loop for demo purposes).

declare(ticks = 100);

class Background1 extends Thread {

    public function __construct() {

    }

    public function run() {

        echo "Starting Background 1 thread";

        while( $this->running ) {

            echo "Background 1 looping...\n";

            sleep(5);
        }

        echo "Exiting Background 1 thread";
    }

    public function play() {
        $this->running = true;
        $this->start();
    }

    public function stop() {
        $this->notify();
        $this->join();
    }
}

class Background2 extends Thread {

    public function __construct() {

    }

    public function run() {

        echo "Starting Background 2 thread";

        while( $this->running ) {

            echo "Background 2 looping...\n";

            sleep(5);
        }

        echo "Exiting Background 2 thread";
    }

    public function play() {
        $this->running = true;
        $this->start();
    }

    public function stop() {
        $this->running = false;
        $this->join();
    }
}

class ControllerThread {

    function __construct() {

    }

    function handleSignal($signo) {

        echo "Received signal $signo";

        switch ($signo) {
            case SIGUSR1:
                $this->running = true;
                break;

             default:
                // handle all other signals
        }
    }

    public function run() {

        pcntl_signal(SIGUSR1, array(&$this, "handleSignal"), true);

        $this->running = true;

        while( $this->running ) {

            echo "Starting controller loop";

            $background1 = new Background1;
            $background2 = new Background2;

            $background1->play();
            $background2->play();

            while( $this->running ) {

                echo "Controller looping...";

                sleep(5);

                pcntl_signal_dispatch();
            }

            $background1->stop();
            $background2->stop();

            echo "Exiting controller loop";
        }
    }
}

date_default_timezone_set('Europe/London');

$child_pid = pcntl_fork();
if ($child_pid) {
    pcntl_waitpid($child_pid, $status);
    $child_pid = posix_getpid();
    echo "PID running: $child_pid";
    exit;
}

echo "Starting main app thread";

$controller = new ControllerThread();
$controller->run();

echo "Exiting main app thread";

In a separate process we signal the other process like this:

posix_kill($pid, SIGUSR1); // $pid being the $child_pid from the other process.

The signal handler is never called.

What am I doing wrong?

alk
  • 69,737
  • 10
  • 105
  • 255
JWood
  • 2,804
  • 2
  • 39
  • 64

1 Answers1

0

I think you just have a slight logic error in handleSignal(), to get your loop to stop in run() you should be setting running=false.

For example:

function handleSignal($signo) {

    echo "Received signal $signo";

    switch ($signo) {
        case SIGUSR1:
            $this->running = false;
            break;

         default:
            // handle all other signals
    }
}
dalevink
  • 284
  • 4
  • 9