/Workshop3/OpenIdWithTorrents/lib/PHPTracker/Threading/Forker.php
https://github.com/oskarp/4ME102 · PHP · 201 lines · 84 code · 27 blank · 90 comment · 12 complexity · ea4c6dc148770c0a82ec81bb312a23a1 MD5 · raw file
- <?php
- /**
- * Declaring ticks to pass between callbacks.
- *
- * Setting this higher than 1 to always listen to process exists even if they
- * happen quickly after each other, ie. always having pcntl_wait being executed
- * when a child process exists.
- * Therefore this is more or less the ticks elapsed between pcntl_fork and pcntl_wait.
- */
- declare( ticks = 10 );
- /**
- * Class to fork its process to N childprocesses executing the same code.
- *
- * Ideal for maintaining one listening socket and accept connections in multiple
- * processes.
- *
- * @package PHPTracker
- * @subpackage Threading
- */
- abstract class PHPTracker_Threading_Forker
- {
- /**
- * Number of child processes wanted.
- *
- * @var integer
- */
- protected $wanted_children;
- /**
- * Array of active child processes' PIDs. Keys represent "slot" indexes.
- *
- * @var array
- */
- protected $children = array();
- /**
- * Executing setup method of the inheriting class, then fork child processes.
- *
- * The number of children forked is a number returned by the constructorParentProcess
- * method of the inheriting class. If it's negative, processea re automatically recreated.
- * The method passes all its parameters to the setup method of the inheriting
- * class.
- */
- final public function start()
- {
- $arguments = func_get_args();
- // Calling parent set-up method with the same parameters as this constructor.
- $this->wanted_children = call_user_func_array( array( $this, 'startParentProcess' ), $arguments );
- // If children are negative, they are automatically recreated when terminate.
- $permanent = $this->wanted_children < 0;
- $this->wanted_children = abs( $this->wanted_children );
- $this->forkChildren( $this->wanted_children, $permanent );
- }
- /**
- * Detaches process from console and starts forking.
- *
- * Requires php-posix!
- *
- * @see self::start()
- */
- final public function startDetached()
- {
- // Forking one child process and closing the parent,
- // because if the parent is already a session leader, it cannot leave it.
- // It is because session group an dprocess group has the same ID as their
- // leader process. Now if you assign the leader process to another
- // session/process group, the IDs will collide.
- $pid = $this->fork();
- if ( $pid > 0 )
- {
- // We are in the parent, so we terminate.
- exit( 0 );
- }
- // Becoming leader of a new session/process group - detaching from shell.
- $sid = posix_setsid();
- if ( false === $sid )
- {
- throw new PHPTracker_Threading_Error( 'Unable to become session leader (detaching).' );
- }
- // We have to handle hangup signals (send when session leader terminates), otherwise it makes child process to stop.
- pcntl_signal( SIGHUP, SIG_IGN );
- // Forking again for not being session/process group leaders will disallow the process
- // to "accidentally" open a controlling terminal for itself (System V OSs).
- $pid = $this->fork();
- if ( $pid > 0 )
- {
- // We are in the parent, so we terminate.
- exit( 0 );
- }
- // Releasing current directory and closing open file descriptors (standard IO).
- chdir( '/' );
- fclose( STDIN );
- fclose( STDOUT );
- // PHP still thinks we are a webpage, and since we closed standard output,
- // whenever we echo, it will assume that the client abandoned the connection,
- // so it silently stops running.
- // We can tell it here not to do it.
- ignore_user_abort( true );
- // Let the world know about our process ID in a standard way.
- file_put_contents( '/var/run/phptracker', getmypid() );
- // Finally we start the procedure as we would without detaching.
- $arguments = func_get_args();
- return call_user_func_array( array( $this, 'start' ), $arguments );
- }
- /**
- * Initializing method to call before forking. Gets params from constructor.
- *
- * @return Number of forks to create. If negative, forks are recreated when exiting and absolute values is used.
- */
- abstract public function startParentProcess();
- /**
- * Initializing method to call after forking. Called on each children.
- *
- * @param integer $slot The slot (numbered index) of the fork. Reused when recreating process.
- */
- abstract public function startChildProcess( $slot );
- /**
- * Forking N childprocesses, initializing them and maintaining their number.
- *
- * This method constantly monitors exiting child processes and recreates them.
- *
- * @throws PHPTracker_Threading_Error When forking is unsuccessful.
- * @param boolean $permanent If true, exiting prpocesses will be recreated.
- * @param integer $n_children Number of children to fork first.
- */
- public function forkChildren( $n_children, $permanent )
- {
- if ( 0 >= $n_children ) return;
- do
- {
- for ( $slot = 0; $slot < $n_children; ++$slot )
- {
- if ( isset( $this->children[$slot] ) )
- {
- // Process already running in this slot.
- continue;
- }
- $pid = $this->fork();
- if ( $pid )
- {
- $this->children[$slot] = $pid;
- }
- else
- {
- return $this->startChildProcess( $slot );
- }
- }
- while( !$permanent && pcntl_wait( $status ) )
- {
- // If we don't need to recreate child processes on exit
- // we just wait for them to die to avoid zombies.
- }
- $pid_exit = pcntl_wait( $status ); // Check the status?
- if ( false !== ( $slot = array_search( $pid_exit, $this->children ) ) )
- {
- unset( $this->children[$slot] );
- }
- } while ( true );
- }
- /**
- * Forks the currently running process.
- *
- * @throws PHPTracker_Threading_Error if the forking is unsuccessful.
- * @return integer Forked process ID or 0 if you are in the child already.
- */
- protected function fork()
- {
- $pid = pcntl_fork();
- if( -1 == $pid )
- {
- throw new PHPTracker_Threading_Error( 'Unable to fork.' );
- }
- return $pid;
- }
- }
- ?>