Page 1 of 1

pcntl_signal(). Not sure why this doesn't work.

Posted: Thu May 10, 2007 6:19 am
by Chris Corbyn
Running a continuous process on command line you can hit CTRL+C to end it. I want to catch the SIGINT (CTRL+C) and display some stats before the process ends. However, despite reading the manual several times over and placing my call to pcntl_signal() everywhere I can think of this seems to prvent me from sending a SIGINT completely.

The Daemon::stop() function never runs (never displays anything) and the while(true) loop continues to run. I have to forcibly kill the process with SIGKILL.

Does anyone know why this is behaving this way?

Code: Select all

#!/usr/bin/php
<?php

/**
 * Configuration values.
 */
class Config
{
	const DB_HOST = "localhost";
	const DB_USER = "xxxxx";
	const DB_PASS = "xxxxx";
	const DB_NAME = "xxxxxx";
}

/**
 * Database handler.
 */
class DB
{
	/**
	 * A MySQL resource, lazy loaded
	 * @var resource
	 */
	private static $connection = null;
	
	/**
	 * Get the MySQL connection.
	 * @return resource
	 */
	public static function getConnection()
	{
		if (self::$connection === null)
		{
			self::$connection = mysql_connect(
				Config::DB_HOST, Config::DB_USER, Config::DB_PASS) or die (mysql_error());
			mysql_select_db(Config::DB_NAME, self::$connection) or die (mysql_error(self::$connection));;
		}
		return self::$connection;
	}
	/**
	 * Run a query against the connection.
	 * @param string Query to run.
	 * @return ResultSet
	 */
	public static function executeQuery($query)
	{
		$conn = self::getConnection();
		$result = mysql_query($query, $conn) or die(mysql_error($conn));
		//create a resultset iterator and return it....
	}
}

/**
 * The main deamon layer.
 */
class Daemon
{
	/**
	 * The UNIX timestamp when the process began.
	 * @var int
	 */
	protected static $timestarted;
	/**
	 * The number of emails sent since the process began.
	 * @var int
	 */
	protected static $emailsProcessed = 0;
	
	/**
	 * Ctor.
	 * This class can only be invoked publically using Daemon::start().
	 */
	private function __construct()
	{
		self::$timestarted = time();
	}
	/**
	 * Displays usage information at end of script execution.
	 */
	public static function stop()
	{
		$total_time = time() - self::$timestarted;
		fwrite(STDOUT, "SIGINT caught." . PHP_EOL .
			"Closing down. Process ran for " . $total_time . " seconds, and sent " .
			self::$emailsProcessed . " emails." . PHP_EOL . "BYE!" . PHP_EOL);
		//posix_kill(posix_getpid(), SIGKILL);
		exit(0);
	}
	/**
	 * Read from the database and try sending out a single batch.
	 */
	public function runBatch()
	{
		fwrite(STDOUT, "Running a batch..." . PHP_EOL);
	}
	/**
	 * Start the daemon running.
	 * The daemon can only be stopped by using ^C to kill the process.
	 */
	public static function start()
	{
		set_time_limit(0);
		$daemon = new self();
		while (true)
		{
			$daemon->runBatch();
			sleep(1);
		}
	}
}

//Catch CTRL+C calls
pcntl_signal(SIGINT, array("Daemon", "stop"));
//Start it running
Daemon::start();
I can CTRL+C to end the script when I have not registered this signal handler :(