@@ -226,6 +226,28 @@ static void _php_free_envp(php_process_env env)
226
226
}
227
227
/* }}} */
228
228
229
+ #if HAVE_SYS_WAIT_H
230
+ static pid_t waitpid_cached (php_process_handle * proc , int * wait_status , int options )
231
+ {
232
+ if (proc -> has_cached_exit_wait_status ) {
233
+ * wait_status = proc -> cached_exit_wait_status_value ;
234
+ return proc -> child ;
235
+ }
236
+
237
+ pid_t wait_pid = waitpid (proc -> child , wait_status , options );
238
+
239
+ /* The "exit" status is the final status of the process.
240
+ * If we were to cache the status unconditionally,
241
+ * we would return stale statuses in the future after the process continues. */
242
+ if (wait_pid > 0 && WIFEXITED (* wait_status )) {
243
+ proc -> has_cached_exit_wait_status = true;
244
+ proc -> cached_exit_wait_status_value = * wait_status ;
245
+ }
246
+
247
+ return wait_pid ;
248
+ }
249
+ #endif
250
+
229
251
/* {{{ proc_open_rsrc_dtor
230
252
* Free `proc` resource, either because all references to it were dropped or because `pclose` or
231
253
* `proc_close` were called */
@@ -270,7 +292,7 @@ static void proc_open_rsrc_dtor(zend_resource *rsrc)
270
292
waitpid_options = WNOHANG ;
271
293
}
272
294
do {
273
- wait_pid = waitpid (proc -> child , & wstatus , waitpid_options );
295
+ wait_pid = waitpid_cached (proc , & wstatus , waitpid_options );
274
296
} while (wait_pid == -1 && errno == EINTR );
275
297
276
298
if (wait_pid <= 0 ) {
@@ -382,8 +404,12 @@ PHP_FUNCTION(proc_get_status)
382
404
running = wstatus == STILL_ACTIVE ;
383
405
exitcode = running ? -1 : wstatus ;
384
406
407
+ /* The status is always available on Windows and will always read the same,
408
+ * even if the child has already exited. This is because the result stays available
409
+ * until the child handle is closed. Hence no caching is used on Windows. */
410
+ add_assoc_bool (return_value , "cached" , false);
385
411
#elif HAVE_SYS_WAIT_H
386
- wait_pid = waitpid (proc -> child , & wstatus , WNOHANG |WUNTRACED );
412
+ wait_pid = waitpid_cached (proc , & wstatus , WNOHANG |WUNTRACED );
387
413
388
414
if (wait_pid == proc -> child ) {
389
415
if (WIFEXITED (wstatus )) {
@@ -404,6 +430,8 @@ PHP_FUNCTION(proc_get_status)
404
430
* looking for either does not exist or is not a child of this process */
405
431
running = 0 ;
406
432
}
433
+
434
+ add_assoc_bool (return_value , "cached" , proc -> has_cached_exit_wait_status );
407
435
#endif
408
436
409
437
add_assoc_bool (return_value , "running" , running );
@@ -1250,6 +1278,9 @@ PHP_FUNCTION(proc_open)
1250
1278
proc -> childHandle = childHandle ;
1251
1279
#endif
1252
1280
proc -> env = env ;
1281
+ #if HAVE_SYS_WAIT_H
1282
+ proc -> has_cached_exit_wait_status = false;
1283
+ #endif
1253
1284
1254
1285
/* Clean up all the child ends and then open streams on the parent
1255
1286
* ends, where appropriate */
0 commit comments