@@ -66,12 +66,12 @@ class Process
6666
6767 private static $ sigchild ;
6868 private static $ posixSignals = array (
69- 1 => 1 , // SIGHUP
70- 2 => 2 , // SIGINT
71- 3 => 3 , // SIGQUIT
72- 6 => 6 , // SIGABRT
73- 14 => 14 , // SIGALRM
74- 15 => 15 , // SIGTERM
69+ 1 , // SIGHUP
70+ 2 , // SIGINT
71+ 3 , // SIGQUIT
72+ 6 , // SIGABRT
73+ 14 , // SIGALRM
74+ 15 , // SIGTERM
7575 );
7676
7777 /**
@@ -242,27 +242,34 @@ public function start($callback = null)
242242 if (!isset ($ this ->options ['bypass_shell ' ])) {
243243 $ this ->options ['bypass_shell ' ] = true ;
244244 }
245- }
245+ } elseif (!$ this ->useFileHandles && $ this ->enhanceSigchildCompatibility && $ this ->isSigchildEnabled ()) {
246+ // last exit code is output on the fourth pipe and caught to work around --enable-sigchild
247+ $ descriptors [3 ] = array ('pipe ' , 'w ' );
248+
249+ $ commandline = '' ;
250+ foreach (self ::$ posixSignals as $ s ) {
251+ $ commandline .= "trap 'echo s $ s >&3' $ s; " ;
252+ }
246253
247- $ ptsWorkaround = null ;
254+ // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
255+ $ commandline .= '{ ( ' .$ this ->commandline .') <&3 3<&- 3>/dev/null & } 3<&0; ' ;
256+ $ commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo x$code >&3; exit $code ' ;
248257
249- if (!$ this ->useFileHandles && $ this ->enhanceSigchildCompatibility && $ this ->isSigchildEnabled ()) {
250258 // Workaround for the bug, when PTS functionality is enabled.
251259 // @see : https://bugs.php.net/69442
252260 $ ptsWorkaround = fopen (__FILE__ , 'r ' );
253261 }
254262
255263 $ this ->process = proc_open ($ commandline , $ descriptors , $ this ->processPipes ->pipes , $ this ->cwd , $ this ->env , $ this ->options );
256264
257- if ($ ptsWorkaround ) {
258- fclose ($ ptsWorkaround );
259- }
260-
261265 if (!is_resource ($ this ->process )) {
262266 throw new RuntimeException ('Unable to launch a new process. ' );
263267 }
264268 $ this ->status = self ::STATUS_STARTED ;
265269
270+ if (isset ($ descriptors [3 ])) {
271+ $ this ->fallbackStatus ['pid ' ] = (int ) fgets ($ this ->processPipes ->pipes [3 ]);
272+ }
266273 $ this ->processPipes ->unblock ();
267274
268275 if ($ this ->tty ) {
@@ -468,8 +475,6 @@ public function getIncrementalErrorOutput()
468475 public function getExitCode ()
469476 {
470477 if (!$ this ->enhanceSigchildCompatibility && $ this ->isSigchildEnabled ()) {
471- $ this ->stop (0 );
472-
473478 throw new RuntimeException ('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. ' );
474479 }
475480
@@ -523,8 +528,6 @@ public function hasBeenSignaled()
523528 $ this ->requireProcessIsTerminated (__FUNCTION__ );
524529
525530 if (!$ this ->enhanceSigchildCompatibility && $ this ->isSigchildEnabled ()) {
526- $ this ->stop (0 );
527-
528531 throw new RuntimeException ('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. ' );
529532 }
530533
@@ -546,8 +549,6 @@ public function getTermSignal()
546549 $ this ->requireProcessIsTerminated (__FUNCTION__ );
547550
548551 if ($ this ->isSigchildEnabled () && (!$ this ->enhanceSigchildCompatibility || -1 === $ this ->processInformation ['termsig ' ])) {
549- $ this ->stop (0 );
550-
551552 throw new RuntimeException ('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. ' );
552553 }
553554
@@ -990,22 +991,8 @@ public function checkTimeout()
990991 private function getDescriptors ()
991992 {
992993 $ this ->processPipes = new ProcessPipes ($ this ->useFileHandles , $ this ->tty );
993- $ descriptors = $ this ->processPipes ->getDescriptors ();
994-
995- if (!$ this ->useFileHandles && $ this ->enhanceSigchildCompatibility && $ this ->isSigchildEnabled ()) {
996- // last exit code is output on the fourth pipe and caught to work around --enable-sigchild
997- $ descriptors [3 ] = array ('pipe ' , 'w ' );
998-
999- $ trap = '' ;
1000- foreach (self ::$ posixSignals as $ s ) {
1001- $ trap .= "trap 'echo s $ s >&3' $ s; " ;
1002- }
1003994
1004- $ this ->commandline = $ trap .'{ ( ' .$ this ->commandline .') <&3 3<&- 3>/dev/null & } 3<&0; ' ;
1005- $ this ->commandline .= 'pid=$!; echo p$pid >&3; wait $pid; code=$?; echo x$code >&3; exit $code ' ;
1006- }
1007-
1008- return $ descriptors ;
995+ return $ this ->processPipes ->getDescriptors ();
1009996 }
1010997
1011998 /**
@@ -1106,8 +1093,11 @@ private function readPipes($blocking, $close)
11061093 $ this ->fallbackStatus ['signaled ' ] = true ;
11071094 $ this ->fallbackStatus ['exitcode ' ] = -1 ;
11081095 $ this ->fallbackStatus ['termsig ' ] = (int ) substr ($ data , 1 );
1109- } elseif ('x ' === $ data [0 ] && !isset ($ this ->fallbackStatus ['signaled ' ])) {
1110- $ this ->fallbackStatus ['exitcode ' ] = (int ) substr ($ data , 1 );
1096+ } elseif ('x ' === $ data [0 ]) {
1097+ $ this ->fallbackStatus ['running ' ] = false ;
1098+ if (!isset ($ this ->fallbackStatus ['signaled ' ])) {
1099+ $ this ->fallbackStatus ['exitcode ' ] = (int ) substr ($ data , 1 );
1100+ }
11111101 }
11121102 }
11131103 } else {
@@ -1189,14 +1179,6 @@ private function doSignal($signal, $throwException)
11891179 return false ;
11901180 }
11911181
1192- if ($ this ->enhanceSigchildCompatibility && $ this ->isSigchildEnabled () && !isset (self ::$ posixSignals [$ signal ]) && !(function_exists ('posix_kill ' ) && @posix_kill ($ this ->getPid (), $ signal ))) {
1193- if ($ throwException ) {
1194- throw new RuntimeException ('This PHP has been compiled with --enable-sigchild and posix_kill() is not available. ' );
1195- }
1196-
1197- return false ;
1198- }
1199-
12001182 if ('\\' === DIRECTORY_SEPARATOR ) {
12011183 exec (sprintf ('taskkill /F /T /PID %d 2>&1 ' , $ this ->getPid ()), $ output , $ exitCode );
12021184 if ($ exitCode && $ this ->isRunning ()) {
@@ -1206,14 +1188,21 @@ private function doSignal($signal, $throwException)
12061188
12071189 return false ;
12081190 }
1209- }
1210-
1211- if (true !== @proc_terminate ($ this ->process , $ signal ) && '\\' !== DIRECTORY_SEPARATOR ) {
1212- if ($ throwException ) {
1213- throw new RuntimeException (sprintf ('Error while sending signal `%s`. ' , $ signal ));
1191+ } else {
1192+ if (!$ this ->enhanceSigchildCompatibility || !$ this ->isSigchildEnabled ()) {
1193+ $ ok = @proc_terminate ($ this ->process , $ signal );
1194+ } elseif (function_exists ('posix_kill ' )) {
1195+ $ ok = @posix_kill ($ this ->getPid (), $ signal );
1196+ } elseif ($ ok = proc_open (sprintf ('kill -%d %d ' , $ signal , $ this ->getPid ()), array (2 => array ('pipe ' , 'w ' )), $ pipes )) {
1197+ $ ok = false === fgets ($ pipes [2 ]);
12141198 }
1199+ if (!$ ok ) {
1200+ if ($ throwException ) {
1201+ throw new RuntimeException (sprintf ('Error while sending signal `%s`. ' , $ signal ));
1202+ }
12151203
1216- return false ;
1204+ return false ;
1205+ }
12171206 }
12181207
12191208 $ this ->latestSignal = (int ) $ signal ;
0 commit comments