Add fork support
git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@4006 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
195
fork.php
Normal file
195
fork.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
/** Manage the fork of children in Posix mode
|
||||
*/
|
||||
class fork
|
||||
{
|
||||
/** The PID list of childs
|
||||
*/
|
||||
private $pidList = array ();
|
||||
|
||||
/** The constructor check if the posix functions exists
|
||||
*/
|
||||
public function __construct ()
|
||||
{
|
||||
if (! function_exists ("pcntl_fork"))
|
||||
throw new \Exception ("Can't fork as PHP doesn't have the pcntl_fork",
|
||||
500);
|
||||
}
|
||||
|
||||
/** Return the number of active PID
|
||||
*/
|
||||
public function childCount ()
|
||||
{
|
||||
return count ($this->pidList);
|
||||
}
|
||||
|
||||
/** Return the list of the active PID
|
||||
*/
|
||||
public function childList ()
|
||||
{
|
||||
return $this->pidList;
|
||||
}
|
||||
|
||||
/** Create a child
|
||||
* If some parameters are provided, the called child method will receive them
|
||||
* This function fork and return the child PID
|
||||
* @param callable $callable The callback method to use in child
|
||||
* @param mixed|null $params The params to provide to child method
|
||||
* @return The child PID
|
||||
*/
|
||||
public function startChild ($callable, $params = array ())
|
||||
{
|
||||
$pid = pcntl_fork ();
|
||||
if ($pid === -1)
|
||||
throw new \Exception ("Can't fork the child", 500);
|
||||
elseif ($pid)
|
||||
{
|
||||
// The parent
|
||||
$this->pidList[$pid] = $pid;
|
||||
return $pid;
|
||||
}
|
||||
// Call the child method
|
||||
$args = func_get_args ();
|
||||
unset ($args[0]);
|
||||
call_user_func_array ($callable, $args);
|
||||
exit;
|
||||
}
|
||||
|
||||
/** Wait the end of one child
|
||||
* Return the PID of the dead child
|
||||
*/
|
||||
public function waitEndChild ()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
$stoppedPid = pcntl_wait ($status, WNOHANG);
|
||||
if ($stoppedPid > 0)
|
||||
{
|
||||
unset ($this->pidList[$stoppedPid]);
|
||||
return $stoppedPid;
|
||||
}
|
||||
usleep (100);
|
||||
}
|
||||
}
|
||||
|
||||
/** Stop (SIGTERM) a specific child.
|
||||
* If the $maxWait parameter is set, wait the dead of the child for $maxWait
|
||||
* seconds. If $maxWait is not set, do not wait the child, only send it the
|
||||
* signal
|
||||
* @param integer $pid The PID of the child to stop
|
||||
* @param integer|null $maxWait The maximum time to wait the child if set
|
||||
* @return $pid if the child is dead correctely. Return false if the child is
|
||||
* not dead in the $maxWait time
|
||||
*/
|
||||
public function stopChild ($pid, $maxWait = null)
|
||||
{
|
||||
return $this->sendSignalToChild (SIGTERM, $pid, $maxWait);
|
||||
}
|
||||
|
||||
/** Kill (SIGKILL) a specific child.
|
||||
* If the $maxWait parameter is set, wait the dead of the child for $maxWait
|
||||
* seconds. If $maxWait is not set, do not wait the child, only send it the
|
||||
* signal
|
||||
* @param integer $pid The PID of the child to stop
|
||||
* @param integer|null $maxWait The maximum time to wait the child if set
|
||||
* @return $pid if the child is dead correctely. Return false if the child is
|
||||
* not dead in the $maxWait time
|
||||
*/
|
||||
public function killChild ($pid, $maxWait = null)
|
||||
{
|
||||
return $this->sendSignalToChild (SIGKILL, $pid, $maxWait);
|
||||
}
|
||||
|
||||
/** Send a signal to a specific child.
|
||||
* If the $maxWait parameter is set, wait the dead of the child for $maxWait
|
||||
* seconds. If $maxWait is not set, do not wait the child, only send it the
|
||||
* signal
|
||||
* @param integer $signal The signal to send to child (SIGTERM or SIGKILL)
|
||||
* @param integer $pid The PID of the child to stop
|
||||
* @param integer|null $maxWait The maximum time to wait the child if set
|
||||
* @return $pid if the child is dead correctely. Return false if the child is
|
||||
* not dead in the $maxWait time
|
||||
*/
|
||||
private function sendSignalToChild ($signal, $pid, $maxWait = null)
|
||||
{
|
||||
if (! key_exists ($pid, $this->pidList))
|
||||
throw new \Exception ("Can't stop/kill pid '$pid' : not in the fork list",
|
||||
500);
|
||||
posix_kill ($pid, SIGKILL);
|
||||
if ($maxWait !== null)
|
||||
{
|
||||
$startWait = time ();
|
||||
while (time () < $startWait + $maxWait)
|
||||
{
|
||||
if (pcntl_waitpid ($pid, $status, WNOHANG) > 0)
|
||||
{
|
||||
unset ($this->pidList[$pid]);
|
||||
return $pid;
|
||||
}
|
||||
usleep (100);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return $pid;
|
||||
}
|
||||
|
||||
/** Stop all the existing children.
|
||||
* If the $maxWait parameter is set, wait the dead of the child for $maxWait
|
||||
* seconds. If $maxWait is not set, do not wait the child, only send it the
|
||||
* signal
|
||||
* @param integer|null $maxWait The maximum time to wait the child if set
|
||||
* @return true if all the children are dead correctely. Return false if at
|
||||
* least one child isnot dead in the $maxWait time
|
||||
*/
|
||||
public function stopAll ($maxWait = null)
|
||||
{
|
||||
return $this->sendSigToAll (SIGTERM, $maxWait);
|
||||
}
|
||||
|
||||
/** Kill all the existing children.
|
||||
* If the $maxWait parameter is set, wait the dead of the child for $maxWait
|
||||
* seconds. If $maxWait is not set, do not wait the child, only send it the
|
||||
* signal
|
||||
* @param integer|null $maxWait The maximum time to wait the child if set
|
||||
* @return true if all the children are dead correctely. Return false if at
|
||||
* least one child isnot dead in the $maxWait time
|
||||
*/
|
||||
public function killAll ($maxWait = null)
|
||||
{
|
||||
return $this->sendSigToAll (SIGKILL, $maxWait);
|
||||
}
|
||||
|
||||
/** Send a stop or kill signal to all the existing children.
|
||||
* If the $maxWait parameter is set, wait the dead of the child for $maxWait
|
||||
* seconds. If $maxWait is not set, do not wait the child, only send it the
|
||||
* signal
|
||||
* @param integer $signal The signal to send to child (SIGTERM or SIGKILL)
|
||||
* @param integer|null $maxWait The maximum time to wait the child if set
|
||||
* @return true if all the children are dead correctely. Return false if at
|
||||
* least one child isnot dead in the $maxWait time
|
||||
*/
|
||||
private function sendSigToAll ($signal, $maxWait = null)
|
||||
{
|
||||
foreach ($this->pidList as $pid)
|
||||
{
|
||||
posix_kill ($pid, $signal);
|
||||
}
|
||||
if ($maxWait !== null)
|
||||
{
|
||||
$startWait = time ();
|
||||
while (time () < $startWait + $maxWait)
|
||||
{
|
||||
$pid = pcntl_wait ($status, WNOHANG);
|
||||
if ($pid > 0)
|
||||
{
|
||||
unset ($this->pidList[$pid]);
|
||||
if (empty ($this->pidList))
|
||||
return true;
|
||||
}
|
||||
usleep (100);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user