stream: fix select() race condition

Call `uv__read()`/`uv__write()` before re-entering `select` thread.
Otherwise we might get second event from it, and will block indefinitely
on `uv__read()`/`uv__write()`.

Fix: https://github.com/libuv/libuv/issues/304
PR-URL: https://github.com/libuv/libuv/pull/365
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
Fedor Indutny 2015-05-25 22:08:04 +02:00
parent a62c2d5928
commit 7005d29514

View File

@ -231,7 +231,6 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) {
/* Get and reset stream's events */
events = s->events;
ACCESS_ONCE(int, s->events) = 0;
uv_sem_post(&s->async_sem);
assert(events != 0);
assert(events == (events & (UV__POLLIN | UV__POLLOUT)));
@ -242,6 +241,14 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) {
if ((events & UV__POLLOUT) && uv__io_active(&stream->io_watcher, UV__POLLOUT))
uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLOUT);
if (stream->flags & UV_CLOSING)
return;
/* NOTE: It is important to do it here, otherwise `select()` might be called
* before the actual `uv__read()`, leading to the blocking syscall
*/
uv_sem_post(&s->async_sem);
}