Skip to content

Improve fix for GH-16889 #17174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions ext/standard/tests/general_functions/proc_open_multiplex.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
Multiplexing of child output
--FILE--
<?php
$php = getenv("TEST_PHP_EXECUTABLE");
$desc = [
["null"],
["pipe", "w"],
["null"]
];
$read_pipes = [];
for ($i = 0; $i < 10; $i++) {
$procs[] = proc_open([$php, "-r", "usleep(100000 * (10 - $i)); echo 'hello$i';"], $desc, $pipes);
$read_pipes[] = $pipes[1];
}
$rset = $read_pipes;
$wset = null;
$eset = null;
while (!empty($read_pipes) && stream_select($rset, $wset, $eset, 2) > 0) {
foreach ($rset as $pipe) {
echo fread($pipe, 6), "\n";
unset($read_pipes[array_search($pipe, $read_pipes)]);
}
$rset = $read_pipes;
}
?>
--EXPECT--
hello9
hello8
hello7
hello6
hello5
hello4
hello3
hello2
hello1
hello0
14 changes: 12 additions & 2 deletions win32/select.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@

#include "php.h"
#include "php_network.h"
#include "win32/time.h"

/* Win32 select() will only work with sockets, so we roll our own implementation here.
* - If you supply only sockets, this simply passes through to winsock select().
* - If you supply file handles, there is no way to distinguish between
* ready for read/write or OOB, so any set in which the handle is found will
* be marked as ready. Pipes will be checked if they are ready for read, though.
* be marked as ready.
* - If you supply only pipe handles in rfds, and no handles in wfds or efds,
* the pipes will only be marked as ready if there is data available.
* - If you supply a mixture of handles and sockets, the system will interleave
* calls between select() and WaitForMultipleObjects(). The time slicing may
* cause this function call to take up to 100 ms longer than you specified.
Expand All @@ -34,6 +37,7 @@ PHPAPI int php_select(php_socket_t max_fd, fd_set *rfds, fd_set *wfds, fd_set *e
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
int handle_slot_to_fd[MAXIMUM_WAIT_OBJECTS];
int n_handles = 0, i;
int num_read_pipes = 0;
fd_set sock_read, sock_write, sock_except;
fd_set aread, awrite, aexcept;
int sock_max_fd = -1;
Expand Down Expand Up @@ -78,6 +82,9 @@ PHPAPI int php_select(php_socket_t max_fd, fd_set *rfds, fd_set *wfds, fd_set *e
sock_max_fd = i;
}
} else {
if (SAFE_FD_ISSET(i, rfds) && GetFileType(handles[n_handles]) == FILE_TYPE_PIPE) {
num_read_pipes++;
}
handle_slot_to_fd[n_handles] = i;
n_handles++;
}
Expand Down Expand Up @@ -136,7 +143,7 @@ PHPAPI int php_select(php_socket_t max_fd, fd_set *rfds, fd_set *wfds, fd_set *e
if (WAIT_OBJECT_0 == WaitForSingleObject(handles[i], 0)) {
if (SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) {
DWORD avail_read = 0;
if (GetFileType(handles[i]) != FILE_TYPE_PIPE
if (num_read_pipes < n_handles
|| !PeekNamedPipe(handles[i], NULL, 0, NULL, &avail_read, NULL)
|| avail_read > 0
) {
Expand All @@ -156,6 +163,9 @@ PHPAPI int php_select(php_socket_t max_fd, fd_set *rfds, fd_set *wfds, fd_set *e
}
}
}
if (retcode == 0 && num_read_pipes == n_handles && sock_max_fd < 0) {
usleep(100);
}
} while (retcode == 0 && (ms_total == INFINITE || GetTickCount64() < limit));

if (rfds) {
Expand Down
Loading