@@ -66,12 +66,12 @@ class Process
66
66
67
67
private static $ sigchild ;
68
68
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
75
75
);
76
76
77
77
/**
@@ -242,27 +242,34 @@ public function start($callback = null)
242
242
if (!isset ($ this ->options ['bypass_shell ' ])) {
243
243
$ this ->options ['bypass_shell ' ] = true ;
244
244
}
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
+ }
246
253
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 ' ;
248
257
249
- if (!$ this ->useFileHandles && $ this ->enhanceSigchildCompatibility && $ this ->isSigchildEnabled ()) {
250
258
// Workaround for the bug, when PTS functionality is enabled.
251
259
// @see : https://bugs.php.net/69442
252
260
$ ptsWorkaround = fopen (__FILE__ , 'r ' );
253
261
}
254
262
255
263
$ this ->process = proc_open ($ commandline , $ descriptors , $ this ->processPipes ->pipes , $ this ->cwd , $ this ->env , $ this ->options );
256
264
257
- if ($ ptsWorkaround ) {
258
- fclose ($ ptsWorkaround );
259
- }
260
-
261
265
if (!is_resource ($ this ->process )) {
262
266
throw new RuntimeException ('Unable to launch a new process. ' );
263
267
}
264
268
$ this ->status = self ::STATUS_STARTED ;
265
269
270
+ if (isset ($ descriptors [3 ])) {
271
+ $ this ->fallbackStatus ['pid ' ] = (int ) fgets ($ this ->processPipes ->pipes [3 ]);
272
+ }
266
273
$ this ->processPipes ->unblock ();
267
274
268
275
if ($ this ->tty ) {
@@ -468,8 +475,6 @@ public function getIncrementalErrorOutput()
468
475
public function getExitCode ()
469
476
{
470
477
if (!$ this ->enhanceSigchildCompatibility && $ this ->isSigchildEnabled ()) {
471
- $ this ->stop (0 );
472
-
473
478
throw new RuntimeException ('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. ' );
474
479
}
475
480
@@ -523,8 +528,6 @@ public function hasBeenSignaled()
523
528
$ this ->requireProcessIsTerminated (__FUNCTION__ );
524
529
525
530
if (!$ this ->enhanceSigchildCompatibility && $ this ->isSigchildEnabled ()) {
526
- $ this ->stop (0 );
527
-
528
531
throw new RuntimeException ('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. ' );
529
532
}
530
533
@@ -546,8 +549,6 @@ public function getTermSignal()
546
549
$ this ->requireProcessIsTerminated (__FUNCTION__ );
547
550
548
551
if ($ this ->isSigchildEnabled () && (!$ this ->enhanceSigchildCompatibility || -1 === $ this ->processInformation ['termsig ' ])) {
549
- $ this ->stop (0 );
550
-
551
552
throw new RuntimeException ('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. ' );
552
553
}
553
554
@@ -990,22 +991,8 @@ public function checkTimeout()
990
991
private function getDescriptors ()
991
992
{
992
993
$ 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
- }
1003
994
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 ();
1009
996
}
1010
997
1011
998
/**
@@ -1106,8 +1093,11 @@ private function readPipes($blocking, $close)
1106
1093
$ this ->fallbackStatus ['signaled ' ] = true ;
1107
1094
$ this ->fallbackStatus ['exitcode ' ] = -1 ;
1108
1095
$ 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
+ }
1111
1101
}
1112
1102
}
1113
1103
} else {
@@ -1189,14 +1179,6 @@ private function doSignal($signal, $throwException)
1189
1179
return false ;
1190
1180
}
1191
1181
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
-
1200
1182
if ('\\' === DIRECTORY_SEPARATOR ) {
1201
1183
exec (sprintf ('taskkill /F /T /PID %d 2>&1 ' , $ this ->getPid ()), $ output , $ exitCode );
1202
1184
if ($ exitCode && $ this ->isRunning ()) {
@@ -1206,14 +1188,21 @@ private function doSignal($signal, $throwException)
1206
1188
1207
1189
return false ;
1208
1190
}
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 ]);
1214
1198
}
1199
+ if (!$ ok ) {
1200
+ if ($ throwException ) {
1201
+ throw new RuntimeException (sprintf ('Error while sending signal `%s`. ' , $ signal ));
1202
+ }
1215
1203
1216
- return false ;
1204
+ return false ;
1205
+ }
1217
1206
}
1218
1207
1219
1208
$ this ->latestSignal = (int ) $ signal ;
0 commit comments