Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg

PHP : Function Reference : Process Control Functions

Process Control Functions


Process Control support in PHP implements the Unix style of process creation, program execution, signal handling and process termination. Process Control should not be enabled within a web server environment and unexpected results may happen if any Process Control functions are used within a web server environment.

This documentation is intended to explain the general usage of each of the Process Control functions. For detailed information about Unix process control you are encouraged to consult your systems documentation including fork(2), waitpid(2) and signal(2) or a comprehensive reference such as Advanced Programming in the UNIX Environment by W. Richard Stevens (Addison-Wesley).

PCNTL now uses ticks as the signal handle callback mechanism, which is much faster than the previous mechanism. This change follows the same semantics as using "user ticks". You use the declare() statement to specify the locations in your program where callbacks are allowed to occur. This allows you to minimize the overhead of handling asynchronous events. In the past, compiling PHP with pcntl enabled would always incur this overhead, whether or not your script actually used pcntl.

There is one adjustment that all pcntl scripts prior to PHP 4.3.0 must make for them to work which is to either to use declare() on a section where you wish to allow callbacks or to just enable it across the entire script using the new global syntax of declare().


This extension is not available on Windows platforms.


No external libraries are needed to build this extension.


Process Control support in PHP is not enabled by default. You have to compile the CGI or CLI version of PHP with --enable-pcntl configuration option when compiling PHP to enable Process Control support.


Currently, this module will not function on non-Unix platforms (Windows).

Runtime Configuration

This extension has no configuration directives defined in php.ini.

Resource Types

This extension has no resource types defined.

Predefined Constants

The following list of signals are supported by the Process Control functions. Please see your systems signal(7) man page for details of the default behavior of these signals.

WNOHANG (integer)
WUNTRACED (integer)
SIG_IGN (integer)
SIG_DFL (integer)
SIG_ERR (integer)
SIGHUP (integer)
SIGINT (integer)
SIGQUIT (integer)
SIGILL (integer)
SIGTRAP (integer)
SIGABRT (integer)
SIGIOT (integer)
SIGBUS (integer)
SIGFPE (integer)
SIGKILL (integer)
SIGUSR1 (integer)
SIGSEGV (integer)
SIGUSR2 (integer)
SIGPIPE (integer)
SIGALRM (integer)
SIGTERM (integer)
SIGSTKFLT (integer)
SIGCLD (integer)
SIGCHLD (integer)
SIGCONT (integer)
SIGSTOP (integer)
SIGTSTP (integer)
SIGTTIN (integer)
SIGTTOU (integer)
SIGURG (integer)
SIGXCPU (integer)
SIGXFSZ (integer)
SIGVTALRM (integer)
SIGPROF (integer)
SIGWINCH (integer)
SIGPOLL (integer)
SIGIO (integer)
SIGPWR (integer)
SIGSYS (integer)
SIGBABY (integer)


This example forks off a daemon process with a signal handler.

Example 1710. Process Control Example


$pid = pcntl_fork();
if (
$pid == -1) {
"could not fork");
} else if (
$pid) {
// we are the parent
} else {
// we are the child

// detatch from the controlling terminal
if (posix_setsid() == -1) {
"could not detach from terminal");

// setup signal handlers
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP, "sig_handler");

// loop forever performing tasks
while (1) {

// do something interesting here



    switch (
$signo) {
// handle shutdown tasks
// handle restart tasks
// handle all other signals



See Also

A look at the section about POSIX functions may be useful.

Table of Contents

pcntl_alarm — Set an alarm clock for delivery of a signal
pcntl_exec — Executes specified program in current process space
pcntl_fork — Forks the currently running process
pcntl_getpriority — Get the priority of any process
pcntl_setpriority — Change the priority of any process
pcntl_signal — Installs a signal handler
pcntl_wait — Waits on or returns the status of a forked child
pcntl_waitpid — Waits on or returns the status of a forked child
pcntl_wexitstatus — Returns the return code of a terminated child
pcntl_wifexited — Checks if status code represents a normal exit
pcntl_wifsignaled — Checks whether the status code represents a termination due to a signal
pcntl_wifstopped — Checks whether the child process is currently stopped
pcntl_wstopsig — Returns the signal which caused the child to stop
pcntl_wtermsig — Returns the signal which caused the child to terminate

Code Examples / Notes » ref.pcntl


You have to use socket_select before socket_accept, so your code will wait for connection with select. socket_select can be interrupted by signals easily. Below is an example from my library (methods of class TNetSocket):
 //-- select
 function select($aread=NULL,$awrite=NULL,$aexcept=NULL,$timeout=NULL)
     $res=socket_select($aread, $awrite, $aexcept, $timeout);
     // if errno===0 it means what select was interrrupted by SysV signal
     if($res===false && socket_last_error($this->socket())!==0)
     { // error occured, interrupted not by a signal
 //-- accept, wait for incomming connection
 function accept()
   if ($this->select($a=&$aread)===false)
   if($child_socket <= 0)
   { // error occured
   if($res <= 0)
   { // error occured
   TLogManager::phpserv("Connection accepted. ADDRESS $this->address, PORT $this->port","net_socket",__FILE__,__LINE__);
   return(true); // return new object of TNetSocket type


To get rid of the zombies when child processes terminate you do not have to write a lot of code that uses complex stuff like message queues.
Instead you only set a signal handler:
pcntl_signal(SIGCHLD, SIG_IGN);


This piece of code helped me to find out what signals are being sent to my process:
function sig_identify($signo) {
 switch($signo) {
   case SIGFPE:    return 'SIGFPE';
   case SIGSTOP:   return 'SIGSTOP';
   case SIGHUP:    return 'SIGHUP';
   case SIGINT:    return 'SIGINT';
   case SIGQUIT:   return 'SIGQUIT';
   case SIGILL:    return 'SIGILL';
   case SIGTRAP:   return 'SIGTRAP';
   case SIGABRT:   return 'SIGABRT';
   case SIGIOT:    return 'SIGIOT';
   case SIGBUS:    return 'SIGBUS';
   case SIGPOLL:   return 'SIGPOLL';
   case SIGSYS:    return 'SIGSYS';
   case SIGCONT:   return 'SIGCONT';
   case SIGUSR1:   return 'SIGUSR1';
   case SIGUSR2:   return 'SIGUSR2';
   case SIGSEGV:   return 'SIGSEGV';
   case SIGPIPE:   return 'SIGPIPE';
   case SIGALRM:   return 'SIGALRM';
   case SIGTERM:   return 'SIGTERM';
   case SIGSTKFLT: return 'SIGSTKFLT';
   case SIGCHLD:   return 'SIGCHLD';
   case SIGCLD:    return 'SIGCLD';
   case SIGIO:     return 'SIGIO';
   case SIGKILL:   return 'SIGKILL';
   case SIGTSTP:   return 'SIGTSTP';
   case SIGTTIN:   return 'SIGTTIN';
   case SIGTTOU:   return 'SIGTTOU';
   case SIGURG:    return 'SIGURG';
   case SIGXCPU:   return 'SIGXCPU';
   case SIGXFSZ:   return 'SIGXFSZ';
   case SIGVTALRM: return 'SIGVTALRM';
   case SIGPROF:   return 'SIGPROF';
   case SIGWINCH:  return 'SIGWINCH';
   case SIGPWR:    return 'SIGPWR';
function sig_handler($signo) {
 echo "Caught " . sig_identify($signo) . " (" . $signo  . ") on " . posix_getpid() . "\n";
pcntl_signal(SIGFPE, "sig_handler");
pcntl_signal(SIGHUP, "sig_handler");
// pcntl_signal(SIGINT, "sig_handler");
pcntl_signal(SIGQUIT, "sig_handler");
pcntl_signal(SIGILL, "sig_handler");
pcntl_signal(SIGTRAP, "sig_handler");
pcntl_signal(SIGABRT, "sig_handler");
pcntl_signal(SIGIOT, "sig_handler");
pcntl_signal(SIGBUS, "sig_handler");
pcntl_signal(SIGPOLL, "sig_handler");
pcntl_signal(SIGSYS, "sig_handler");
pcntl_signal(SIGCONT, "sig_handler");
pcntl_signal(SIGUSR1, "sig_handler");
pcntl_signal(SIGUSR2, "sig_handler");
pcntl_signal(SIGSEGV, "sig_handler");
pcntl_signal(SIGPIPE, "sig_handler");
pcntl_signal(SIGALRM, "sig_handler");
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGSTKFLT, "sig_handler");
pcntl_signal(SIGCHLD, "sig_handler");
pcntl_signal(SIGCLD, "sig_handler");
pcntl_signal(SIGIO, "sig_handler");
pcntl_signal(SIGTSTP, "sig_handler");
pcntl_signal(SIGTTIN, "sig_handler");
pcntl_signal(SIGTTOU, "sig_handler");
pcntl_signal(SIGURG, "sig_handler");
pcntl_signal(SIGXCPU, "sig_handler");
pcntl_signal(SIGXFSZ, "sig_handler");
pcntl_signal(SIGVTALRM, "sig_handler");
pcntl_signal(SIGPROF, "sig_handler");
pcntl_signal(SIGWINCH, "sig_handler");
pcntl_signal(SIGPWR, "sig_handler");
I commented out SIGNIT, as it is the signal which is sent to your process when you press CTRL-C. If you catch this signal, you must handle it properly:
function sig_handler($signo) {
 switch($signo) {
   case SIGINT:
     // customized cleanup code
     exit; // now exit
Otherwise the only possibility to stop your process is by sending a SIGKILL signal - you can do this on the shell by typing "kill -9 PID" (where -9 is the numerical value for SIGKILL).
Note: You cannot add a handler (i.e. ignore signals) for SIGSTOP and SIGKILL - for obvious reasons.


Suppose you want to fork off children to handle a few hundred different targets (like, say, SNMP polling, but that's just one example).  Since you don't want to fork-bomb yourself, here's one method of limiting the number of children you have in play at any one time:
#!/usr/bin/php -q
declare(ticks = 1);
// function for signal handler
function sig_handler($signo) {
 global $child;
 switch ($signo) {
   case SIGCHLD:
     echo "SIGCHLD received\n";
     $child -= 1;
// install signal handler for dead kids
pcntl_signal(SIGCHLD, "sig_handler");
for ($i=1;$i<=20;$i++) {
       while ($child >= $max) {
               sleep(5); echo "\t Maximum children allowed\n";
       if ($pid == -1) {
               die("could not fork");
       } else if ($pid) {
               // we are the parent
       } else {
               // we are the child
               echo "child number $i\n";
               // presumably doing something interesting

patrice levesque

So, you want to create multiple child processes and don't want any zombies, don't you?
You can use IPC to achieve just that.  Every child that is spawned has to tell its parent that time has come for him to be terminated.  So, yes, zombies will be created, but once in a while the parent will 'clean up' after his kids.  Code:
 declare(ticks = 1);
 // create a IPC message queue
 $msgqueue = msg_get_queue(ftok("/tmp/php_msgqueue.stat", 'R'),0666 | IPC_CREAT);
 // loop for 1000 children
 for ($c = 0; $c < 1000; $c++) {
   // fork
   $pcid = pcntl_fork();
   if ($pcid == -1) {
     die("Could not fork!");
   elseif ($pcid) { // we are the parent, look for zombie kids and terminate 'em
     // look in the IPC message queue if there are any entries
     $currentqueue = msg_stat_queue($msgqueue);
     $n = $currentqueue['msg_qnum']; // number of messages (number of kids to terminate)
     if ($n > 0) {
       echo "There are $n kids to terminate.\n";
       for ($i = 0; $i < $n; $i++) {
         // pop the kid's PID from the IPC message queue
         if (!msg_receive ($msgqueue, 1, $msg_type, 16384, $msg, true, 0, $msg_error)) {
           echo "MSG_RECV ERROR: $errmsg \n"; // something has gone wrong
         else {
           pcntl_waitpid($msg, $tmpstat, 0); // terminate kid for real.
   else { // we are the child!
     if (!posix_setsid()) { die ("Could not detach"); }; // detach
     echo "I am child number $c\n";
     sleep(5); // do something useful
     // tell dad I'm finished via IPC: send him my PID
     if (!msg_send($msgqueue, 1, posix_getpid(), true, true, $errmsg)) {
       echo "MSG_SEND ERROR: $errmsg \n";
     exit(); // become a zombie until dad kills me                            


ok, heres what ya do to handle child process's ... :>
you want to pfork your main program, and let it exit,
allowing the new child to become the main program (parent process).
example psudo code :
main program start;
    if pfork'd child ok
         then exit ;
   // now your new child process is in control...
   // use a signal handler to make it exit (sigkill or sigterm probably)
   // when this new process pforks, store the new child PID's in an
   // array.   when your process  catch's the sigterm  signal
   // loop thru the array of its child PID's sending each child
   // sigkill , then call  pwait on them to wait for them to exit.
   // this will make sure any child process are cleaned up ok
   // THEN .. now here's the trick....
   // reset yer sigterm handler BACK to its original default handler,
  // thennnnn   raise sigterm , main program will exit ok now tooooo :>
when your pfork'd main process gets sigterm ... then do something
like this :
foreach ($this->pForkList as $kiddie) {
$deadPID = 0;
do {
$deadPID = pcntl_waitpid(-1,WNOHANG);
if ($deadPID > 0) {
// kiddie has exited now ...
unset($this->pForkList[ array_search($deadPID,$this->pForkList)]);
} // end if
} while ($deadPID == 0);
} // end for
// now reset sigterm ...
// RAISE sigterm now ...
this will allow your main process and all its child process's to exit properly and not leave and zombies or other bad stuff behind !


In the example of the documentation we need to put the pctnl_signal statements BEFORE the while loop.
In that way we can execute whatever we put in the signal handler functions.

04-dec-2003 11:52

in example 1, i found unless i create function sig_handler _BEFORE_ pcnt_signal, it wouldnt work.. and would just fall to the floor bleeding to death
(note for people having these kinda probs)


I'm currently working on some code for this, but in case I forget to come back to post to the board, or in case it takes me a while, why not just have a separate background job running (started up via the shell) that tracks which sockets are available to clients ?  Then all you'd have to do is communicate with the one job (or perhaps its own mini-server) run in the background that keeps an array of the available sockets for the server.  This seems the most natural alternative since PHP disclaims that process control functionality should not be used in a web-server environment.  I would hate to build a server, especially one with high traffic, that had to run through a loop in order to find an available socket.

david koopman

I had a hard time finding a complete example of using PHP as a multi-process (or multi-threaded - I don't understand the difference in these two terms) daemon using connection pooling.  I put pieces of the puzzle together and came up with the program below.  I hope it helps someone.  Notes about making this work:
1) I rebuilt PHP on my machine with these config options:
./configure --enable-sockets --enable-pcntl --enable-sigchild
make install
2) I have problems when tried to handle SIGTERM and SIGHUP myself, so I removed these from my code, don't use them unless you have a special need for this:
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP, "sig_handler");
What I do is:
1. start the program, then fork to detach from the terminal (kill the parent and make the child the session leader).
2. bind to address and port and start listening.
3. fork $poolNum times, creating $poolNum children (this is the pool of daemons running.  The children handle the incoming connections).
4. keep the parent process running in a loop, constantly checking to see if it should create a new child.  It will always keep $poolNum spare children ready (as long as the total pooled connections doesn't exceed $maxDaemon).  As connections come in, more children are spawned.
5. When a new connection comes in, it is handed off to the first child.  This child then sends a SIGUSR1 signal back to the parent.  The parent has a signal handler for SIGUSR1, which will increment the $numActive variable by one.  The loop that is running (see 4 above) will note the increment in $numActive and automatically create a new child process to keep the process pool going.
I have to post the code in the next note, the note engine on this site won't allow such a long note to be posted, but I think this code example is well worth a comment on this...

luca dot mariano

Hi folks,
if someone uses PHP-CLI onWin32 and wants to experiment the PCNTL stuff, I've packed a binary version of PHP with built-in pcntl, shmop, sysvshm and other typical Unix extensions... (thanks to Cygwin DLLs).
Download it:


Forking your PHP daemon will cause it to zombie on exit.
...or so I've seen on:
FreeBSD (PHP4.2.x)
Debian (PHP4.3.0-dev)
Darwin (PHP4.3.0-dev)
This was tested with the example code above and other scripts created for evaluation.
Seems adding --enable-sigchild to your configure will get rid of the problem.
Hope that saves some hair tearing :]


An easier way than what was first suggested in the first comment, to retrieve what signal your application is being sent would be to use get_defined_constants() to list all constants, loop through and strip out those that are not signals, and to check if it matches the value.
Here is my code for doing this, written for PHP5 only.
// php5 Specfic
function pcntl_sig_identify ( $sig_no ) {
   $get_constants = get_defined_constants(true);
   $pcntl_contstants = $get_constants["pcntl"];
   $keys = array_keys( $pcntl_contstants );
     foreach($keys as $key){
       if(strstr($key, "SIG") && !strstr($key, "_") && $pcntl_contstants[$key] == $sig_no){
 return $key;
     } // end loop
} // end function pcntl_sig_identify
// This example will output "SIGTERM"
print pcntl_sig_identify(15) . "\n";


(PHP 5.2.4)
This is an example of multithreading keeping different connections to a mysql database: when children exit they close the connection and others can't use it any more generating problems. In this example I used variable variables to make a different connection per each child.
This scripts loops forever with one mother detached from the terminal and five children 'named' from 1 to 5. When one children sees it's name in the database (one table 'test.tb' with only one field 'test') he lets himself die. To kill children insert their value in the db. The mother suicides only when all children are dead.
What a sad but interesting story...
if ($npid==-1) die("Error: impossible to pcntl_fork()\n");
else if ($npid) exit(0); // THE GRANPA DIES
$children = 5;
for ($i=1; $i<=$children; $i++)
$pid = pcntl_fork();
if ($pid==-1) die("Error: impossible to pcntl_fork()\n");
else if ($pid)
$pid_arr[$i] = $pid;
if (!$pid) // CHILDREN
global $vconn;
$vconn = "vconn$i";
global $$vconn;
$$vconn = @mysql_connect("mydbhost","mydbuser","mydbpwd");
if (!($$vconn)) echo mysql_error();
if (!($$vconn)) exit;
while (1)
$query = "SELECT test FROM test.tb";
$rs = mysql_query($query,$$vconn);
$rw = mysql_fetch_row($rs);
if ($rw[0]==$i) exit;
echo "Database is $rw[0] and I am $i, it's not my time, I will wait....\n";
       foreach ($pid_arr as $pid)
           // we are the parent and we wait for all children to die
           pcntl_waitpid($pid, $status);
       echo "All my children died, I will suicide...\n";


#!/usr/local/bin/php -q
# Jeremy Brand <>
# ./configure --enable-pcntl --enable-sigchild
# make
# make install
# This code example shows how to use a script to do multiprocessing.  Each time
# this script is ran, the result is 5 (in this example) processes running to
# accomplish a specified task.
# Examples could be a messaging queue.  You could get the number of messages in
# a queue and handle any or all of them asynchronously.
# Get the number of children you want to be born by running this
# script once.
$children = 5; # likely a function call here.
for ($i=1; $i<=$children; $i++)
 $pid = pcntl_fork();
 if ($pid == -1)
   die("could not fork\n");
 else if ($pid)
   # If we are the parent, we did our job of giving birth,
   # now lets finish our job and die!
   # Since we are the child, fork so that init will become our parent.  Init
   # is good at wait()ing on children - ie: reaping.
   $cpid = pcntl_fork();
   if ($cpid == -1)
     die("could not fork in child process\n");
   if (!$cpid)
     # We have now forked off from our parent and also are not waiting on any
     # other children to process, however other children are running
     # simutaniously to us.  Make sure the code you write here is safe to run
     # in this environment of multiprocessing - ie: proper locking, etc.
     # Write the custom code here that you want to multiprocess.
     print "we are child number $i\n";
     # Don't forget to exit after the child processing is done.  Certainly
     # change this exit code if you need to however.

Change Language

Follow Navioo On Twitter
.NET Functions
Apache-specific Functions
Alternative PHP Cache
Advanced PHP debugger
Array Functions
Aspell functions [deprecated]
BBCode Functions
BCMath Arbitrary Precision Mathematics Functions
PHP bytecode Compiler
Bzip2 Compression Functions
Calendar Functions
CCVS API Functions [deprecated]
Class/Object Functions
Classkit Functions
ClibPDF Functions [deprecated]
COM and .Net (Windows)
Crack Functions
Character Type Functions
Cybercash Payment Functions
Credit Mutuel CyberMUT functions
Cyrus IMAP administration Functions
Date and Time Functions
DB++ Functions
Database (dbm-style) Abstraction Layer Functions
dBase Functions
DBM Functions [deprecated]
dbx Functions
Direct IO Functions
Directory Functions
DOM Functions
DOM XML Functions
enchant Functions
Error Handling and Logging Functions
Exif Functions
Expect Functions
File Alteration Monitor Functions
Forms Data Format Functions
Fileinfo Functions
filePro Functions
Filesystem Functions
Filter Functions
Firebird/InterBase Functions
Firebird/Interbase Functions (PDO_FIREBIRD)
FriBiDi Functions
FrontBase Functions
FTP Functions
Function Handling Functions
GeoIP Functions
Gettext Functions
GMP Functions
gnupg Functions
Haru PDF Functions
hash Functions
Hyperwave Functions
Hyperwave API Functions
i18n Functions
IBM Functions (PDO_IBM)
iconv Functions
ID3 Functions
IIS Administration Functions
Image Functions
Imagick Image Library
Informix Functions
Informix Functions (PDO_INFORMIX)
Ingres II Functions
IRC Gateway Functions
PHP / Java Integration
JSON Functions
LDAP Functions
libxml Functions
Lotus Notes Functions
LZF Functions
Mail Functions
Mailparse Functions
Mathematical Functions
MaxDB PHP Extension
MCAL Functions
Mcrypt Encryption Functions
MCVE (Monetra) Payment Functions
Memcache Functions
Mhash Functions
Mimetype Functions
Ming functions for Flash
Miscellaneous Functions
mnoGoSearch Functions
Microsoft SQL Server Functions
Microsoft SQL Server and Sybase Functions (PDO_DBLIB)
Mohawk Software Session Handler Functions
mSQL Functions
Multibyte String Functions
muscat Functions
MySQL Functions
MySQL Functions (PDO_MYSQL)
MySQL Improved Extension
Ncurses Terminal Screen Control Functions
Network Functions
Newt Functions
NSAPI-specific Functions
Object Aggregation/Composition Functions
Object property and method call overloading
Oracle Functions
ODBC Functions (Unified)
ODBC and DB2 Functions (PDO_ODBC)
OpenAL Audio Bindings
OpenSSL Functions
Oracle Functions [deprecated]
Oracle Functions (PDO_OCI)
Output Control Functions
Ovrimos SQL Functions
Paradox File Access
Parsekit Functions
Process Control Functions
Regular Expression Functions (Perl-Compatible)
PDF Functions
PDO Functions
Phar archive stream and classes
PHP Options&Information
POSIX Functions
Regular Expression Functions (POSIX Extended)
PostgreSQL Functions
PostgreSQL Functions (PDO_PGSQL)
Printer Functions
Program Execution Functions
PostScript document creation
Pspell Functions
qtdom Functions
Rar Functions
GNU Readline
GNU Recode Functions
RPM Header Reading Functions
runkit Functions
SAM - Simple Asynchronous Messaging
Satellite CORBA client extension [deprecated]
SCA Functions
SDO Functions
SDO XML Data Access Service Functions
SDO Relational Data Access Service Functions
SESAM Database Functions
PostgreSQL Session Save Handler
Session Handling Functions
Shared Memory Functions
SimpleXML functions
SNMP Functions
SOAP Functions
Socket Functions
Standard PHP Library (SPL) Functions
SQLite Functions
SQLite Functions (PDO_SQLITE)
Secure Shell2 Functions
Statistics Functions
Stream Functions
String Functions
Subversion Functions
Shockwave Flash Functions
Swish Functions
Sybase Functions
TCP Wrappers Functions
Tidy Functions
Tokenizer Functions
Unicode Functions
URL Functions
Variable Handling Functions
Verisign Payflow Pro Functions
vpopmail Functions
W32api Functions
WDDX Functions
win32ps Functions
win32service Functions
xattr Functions
xdiff Functions
XML Parser Functions
XML-RPC Functions
XMLReader functions
XMLWriter Functions
XSL functions
XSLT Functions
YAZ Functions
YP/NIS Functions
Zip File Functions
Zlib Compression Functions
eXTReMe Tracker