Rename all the files to camelCase and update the class name in the files
This commit is contained in:
266
src/Fork.php
Normal file
266
src/Fork.php
Normal file
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** 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);
|
||||
if (function_exists ("pcntl_async_signals"))
|
||||
pcntl_async_signals (true);
|
||||
else
|
||||
declare (ticks=1);
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
/** Create a detached child. The terminal is closed. All the displayed
|
||||
* messages from the child are silently dropped.
|
||||
* If some parameters are provided, the called child method will receive them
|
||||
* This function fork and return the child PID
|
||||
* @param string $name The name displayed in the processus list
|
||||
* @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 startDetachedChild ($name, $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
|
||||
$sid = posix_setsid();
|
||||
|
||||
// Will catch all the text messages from the application to not crash if
|
||||
// there is an "echo"
|
||||
ob_start ();
|
||||
|
||||
// Catch the error messages from the application to not hang if triggered
|
||||
// An other handler can be set in function to execute
|
||||
set_error_handler (function () {});
|
||||
|
||||
// Close the file handlers STDOUT/STDIN
|
||||
fclose (STDIN);
|
||||
fclose (STDOUT);
|
||||
fclose (STDERR);
|
||||
if (function_exists ("cli_set_process_title"))
|
||||
cli_set_process_title ($name);
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
/** Clean the childs which are finished. Do not block the process
|
||||
*/
|
||||
public function cleanEndChild ()
|
||||
{
|
||||
$stoppedPid = pcntl_wait ($status, WNOHANG);
|
||||
while ($stoppedPid > 0)
|
||||
{
|
||||
unset ($this->pidList[$stoppedPid]);
|
||||
$stoppedPid = pcntl_wait ($status, WNOHANG);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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)
|
||||
{
|
||||
if (! key_exists ($pid, $this->pidList))
|
||||
throw new \Exception ("Can't stop pid '$pid' : not in the fork list",
|
||||
500);
|
||||
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)
|
||||
{
|
||||
if (! key_exists ($pid, $this->pidList))
|
||||
throw new \Exception ("Can't kill pid '$pid' : not in the fork list",
|
||||
500);
|
||||
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)
|
||||
{
|
||||
posix_kill ($pid, $signal);
|
||||
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