68 throw new RuntimeException(
"MediaWiki\Maintenance\ForkController cannot be used from the web." );
69 } elseif ( !extension_loaded(
'pcntl' ) ) {
70 throw new RuntimeException(
71 'MediaWiki\Maintenance\ForkController requires pcntl extension to be installed.'
73 } elseif ( !extension_loaded(
'posix' ) ) {
74 throw new RuntimeException(
75 'MediaWiki\Maintenance\ForkController requires posix extension to be installed.'
78 $this->procsToStart = $numProcs;
82 self::$RESTARTABLE_SIGNALS = [
83 SIGFPE, SIGILL, SIGSEGV, SIGBUS,
84 SIGABRT, SIGSYS, SIGPIPE, SIGXCPU, SIGXFSZ,
101 pcntl_signal( SIGTERM, [ $this,
'handleTermSignal' ],
false );
105 if ( $this->procsToStart ) {
106 if ( $this->
forkWorkers( $this->procsToStart ) ==
'child' ) {
109 $this->procsToStart = 0;
114 $deadPid = pcntl_wait( $status );
116 if ( $deadPid > 0 ) {
118 unset( $this->children[$deadPid] );
119 if ( $this->flags & self::RESTART_ON_ERROR ) {
120 if ( pcntl_wifsignaled( $status ) ) {
123 $signal = pcntl_wtermsig( $status );
124 if ( in_array( $signal, self::$RESTARTABLE_SIGNALS ) ) {
125 echo
"Worker exited with signal $signal, restarting\n";
126 $this->procsToStart++;
128 } elseif ( pcntl_wifexited( $status ) ) {
130 $exitStatus = pcntl_wexitstatus( $status );
131 if ( $exitStatus != 0 ) {
132 echo
"Worker exited with status $exitStatus, restarting\n";
133 $this->procsToStart++;
135 echo
"Worker exited normally\n";
140 if ( $this->procsToStart ) {
146 if ( function_exists(
'pcntl_signal_dispatch' ) ) {
147 pcntl_signal_dispatch();
155 if ( $this->termReceived ) {
156 foreach ( $this->children as $childPid => $unused ) {
157 posix_kill( $childPid, SIGTERM );
159 $this->termReceived =
false;
161 }
while ( count( $this->children ) );
162 pcntl_signal( SIGTERM, SIG_DFL );