63 throw new MWException(
"ForkController cannot be used from the web." );
64 } elseif ( !extension_loaded(
'pcntl' ) ) {
65 throw new MWException(
'ForkController requires pcntl extension to be installed.' );
66 } elseif ( !extension_loaded(
'posix' ) ) {
67 throw new MWException(
'ForkController requires posix extension to be installed.' );
69 $this->procsToStart = $numProcs;
73 self::$RESTARTABLE_SIGNALS = [
74 SIGFPE, SIGILL, SIGSEGV, SIGBUS,
75 SIGABRT, SIGSYS, SIGPIPE, SIGXCPU,SIGXFSZ,
92 pcntl_signal( SIGTERM, [ $this,
'handleTermSignal' ],
false );
96 if ( $this->procsToStart ) {
97 if ( $this->
forkWorkers( $this->procsToStart ) ==
'child' ) {
100 $this->procsToStart = 0;
105 $deadPid = pcntl_wait( $status );
107 if ( $deadPid > 0 ) {
109 unset( $this->children[$deadPid] );
110 if ( $this->flags & self::RESTART_ON_ERROR ) {
111 if ( pcntl_wifsignaled( $status ) ) {
114 $signal = pcntl_wtermsig( $status );
115 if ( in_array( $signal, self::$RESTARTABLE_SIGNALS ) ) {
116 echo
"Worker exited with signal $signal, restarting\n";
117 $this->procsToStart++;
119 } elseif ( pcntl_wifexited( $status ) ) {
121 $exitStatus = pcntl_wexitstatus( $status );
122 if ( $exitStatus != 0 ) {
123 echo
"Worker exited with status $exitStatus, restarting\n";
124 $this->procsToStart++;
126 echo
"Worker exited normally\n";
131 if ( $this->procsToStart ) {
137 if ( function_exists(
'pcntl_signal_dispatch' ) ) {
138 pcntl_signal_dispatch();
140 declare( ticks = 1 ) {
146 if ( $this->termReceived ) {
147 foreach ( $this->children as $childPid => $unused ) {
148 posix_kill( $childPid, SIGTERM );
150 $this->termReceived =
false;
152 }
while ( count( $this->children ) );
153 pcntl_signal( SIGTERM, SIG_DFL );