Io\Poll: data buffered by the stream layer is not reported, and a stream closed while watched is never reported
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 48/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Área
- api, backend, operating-systems
Línea de trabajo
Start by tracing Io\Poll Context::wait(), StreamPollHandle, and the Linux epoll backend, then reproduce both cases from the issue: buffered stream data and a watched stream closed during a wait. Done means wait() reports buffered reads and reports a watcher retired by close, with behavior comparable to stream_select().
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Description
@bukka — I've been writing a poller for phasync (a coroutine library) on top of Io\Poll, next to our stream_select() one, and ran our test suite against master. Two behaviours make a correct event loop hard to build on it, and both differ from stream_select():
1. Data already in the stream's read buffer isn't reported. After a read that buffered more than it returned (typical with fgets()), the socket is empty but the stream has unread data. stream_select() counts that stream as readable; Io\Poll only looks at the fd, so a loop that waits for readability before its next read never wakes.
use Io\Poll\{Context, Event};
[$a, $b] = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
fwrite($b, "first\nsecond\n");
fgets($a); // "first\n"; "second\n" is now in $a's read buffer, the socket is empty
$r = [$a]; $w = $e = null;
var_dump(stream_select($r, $w, $e, 0)); // int(1)
$poll = new Context();
$poll->add(new StreamPollHandle($a), [Event::Read]);
var_dump(count($poll->wait(Time\Duration::fromMilliseconds(100)))); // int(0)
We work around it by checking stream_get_meta_data($s)['unread_bytes'] before every wait, but every user of the API will hit this. Perhaps wait() could return the watchers of streams with buffered read data at once (as stream_select() does through stream_array_emulate_read_fd_set()), with Event::Read triggered.
2. A stream closed while watched is never reported. Since #23822, fclose() retires the watcher (which fixed the use-after-free), but wait() never tells the loop. A coroutine or callback waiting on that stream waits forever, unless the loop scans every watcher's isActive() periodically and caps its waits to do so:
use Io\Poll\{Context, Event};
[$a, $b] = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
$poll = new Context();
$watcher = $poll->add(new StreamPollHandle($a), [Event::Read]);
fclose($a); // elsewhere in the program, while something waits on $a
var_dump($watcher->isActive()); // bool(false)
var_dump(count($poll->wait(Time\Duration::fromMilliseconds(100)))); // int(0): nobody is told
With stream_select() the next call throws on the closed stream (TypeError, or ValueError when it was the only one), so the loop can find and wake its waiter. Perhaps the next wait() could return a watcher retired by a close once, inactive, (e.g. with Event::HangUp triggered), so the loop wakes its waiter without scanning.
Let me know if you'd like me to write a PR for either.
PHP Version
PHP 8.7.0-dev (master)
Operating System
Linux (epoll backend)
- Lenguaje dominante
- C
- Estrellas
- 41.7k
- Forks
- 8.5k
- Merge medio
- 2 d 10 h
- PR fusionados (30 d)
- 158
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de php/php-src
-
Windows CLI: get_ps_title() passes bytes to GetConsoleTitleW() instead of characters, overflowing the 260-wchar_t bufferPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 79/100
Los mantenedores suelen responder en 1 día
-
zend_set_local_var() overwrites existing compiled variable (CV) zval without calling zval_ptr_dtor()Posiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. AbiertoBug Status: Needs Triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
Los mantenedores suelen responder en 1 día
-
master: part of the mbstring bailout fix got lost in a mergePosiblemente ocupada @lazerg la tomó hace 7 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
Bug Status: Needs Triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 64/100
Los mantenedores suelen responder en 1 día
-
quoted_printable_encode() produces lines longer than 76 characters for bytes 0xF5 to 0xFFPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
Todos los issues de php/php-src
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
libsdl-org/SDL#16607 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
PowerShell/Win32-OpenSSH#2482 · 1 reacción ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
zephyrproject-rtos/zephyr#123881 ·
Los mantenedores suelen responder en 2 días