67 throw new RuntimeException(
"MediaWiki\Maintenance\ForkController cannot be used from the web." );
68 } elseif ( !extension_loaded(
'pcntl' ) ) {
69 throw new RuntimeException(
70 'MediaWiki\Maintenance\ForkController requires pcntl extension to be installed.'
72 } elseif ( !extension_loaded(
'posix' ) ) {
73 throw new RuntimeException(
74 'MediaWiki\Maintenance\ForkController requires posix extension to be installed.'
77 $this->procsToStart = $numProcs;
81 self::$RESTARTABLE_SIGNALS = [
82 SIGFPE, SIGILL, SIGSEGV, SIGBUS,
83 SIGABRT, SIGSYS, SIGPIPE, SIGXCPU, SIGXFSZ,
100 pcntl_signal( SIGTERM, [ $this,
'handleTermSignal' ],
false );
104 if ( $this->procsToStart ) {
105 if ( $this->
forkWorkers( $this->procsToStart ) ==
'child' ) {
108 $this->procsToStart = 0;
113 $deadPid = pcntl_wait( $status );
115 if ( $deadPid > 0 ) {
117 unset( $this->children[$deadPid] );
118 if ( $this->flags & self::RESTART_ON_ERROR ) {
119 if ( pcntl_wifsignaled( $status ) ) {
122 $signal = pcntl_wtermsig( $status );
123 if ( in_array( $signal, self::$RESTARTABLE_SIGNALS ) ) {
124 echo
"Worker exited with signal $signal, restarting\n";
125 $this->procsToStart++;
127 } elseif ( pcntl_wifexited( $status ) ) {
129 $exitStatus = pcntl_wexitstatus( $status );
130 if ( $exitStatus != 0 ) {
131 echo
"Worker exited with status $exitStatus, restarting\n";
132 $this->procsToStart++;
134 echo
"Worker exited normally\n";
139 if ( $this->procsToStart ) {
145 if ( function_exists(
'pcntl_signal_dispatch' ) ) {
146 pcntl_signal_dispatch();
154 if ( $this->termReceived ) {
155 foreach ( $this->children as $childPid => $unused ) {
156 posix_kill( $childPid, SIGTERM );
158 $this->termReceived =
false;
160 }
while ( count( $this->children ) );
161 pcntl_signal( SIGTERM, SIG_DFL );