stream: permit read after seeing EOF (#3361)

On some streams (notably TTYs), it is permitted to continue reading
after getting EOF. So still stop reading on EOF, but allow the user to
reset the stream and try to read again (which may just get EOF).

This relaxes the constraint added in ce15b8405e.
Refs: https://github.com/libuv/libuv/pull/3006
This commit is contained in:
Jameson Nash 2021-11-24 19:25:47 -05:00 committed by GitHub
parent e592ebe9d3
commit b2614a10a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 39 additions and 37 deletions

View File

@ -502,7 +502,6 @@ if(LIBUV_BUILD_TESTS)
test/test-multiple-listen.c
test/test-mutexes.c
test/test-not-readable-nor-writable-on-read-error.c
test/test-not-readable-on-eof.c
test/test-not-writable-after-shutdown.c
test/test-osx-select.c
test/test-pass-always.c
@ -530,6 +529,7 @@ if(LIBUV_BUILD_TESTS)
test/test-process-title.c
test/test-queue-foreach-delete.c
test/test-random.c
test/test-readable-on-eof.c
test/test-ref.c
test/test-run-nowait.c
test/test-run-once.c

View File

@ -206,7 +206,6 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-multiple-listen.c \
test/test-mutexes.c \
test/test-not-readable-nor-writable-on-read-error.c \
test/test-not-readable-on-eof.c \
test/test-not-writable-after-shutdown.c \
test/test-osx-select.c \
test/test-pass-always.c \
@ -234,6 +233,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-process-title-threadsafe.c \
test/test-queue-foreach-delete.c \
test/test-random.c \
test/test-readable-on-eof.c \
test/test-ref.c \
test/test-run-nowait.c \
test/test-run-once.c \

View File

@ -1010,7 +1010,6 @@ uv_handle_type uv__handle_type(int fd) {
static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
stream->flags |= UV_HANDLE_READ_EOF;
stream->flags &= ~UV_HANDLE_READING;
stream->flags &= ~UV_HANDLE_READABLE;
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream);
@ -1550,15 +1549,12 @@ int uv__read_start(uv_stream_t* stream,
assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
stream->type == UV_TTY);
/* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
* expresses the desired state of the user.
*/
/* The UV_HANDLE_READING flag is irrelevant of the state of the stream - it
* just expresses the desired state of the user. */
stream->flags |= UV_HANDLE_READING;
stream->flags &= ~UV_HANDLE_READ_EOF;
/* TODO: try to do the read inline? */
/* TODO: keep track of tcp state. If we've gotten a EOF then we should
* not start the IO watcher.
*/
assert(uv__stream_fd(stream) >= 0);
assert(alloc_cb);

View File

@ -1796,7 +1796,6 @@ static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
* it. */
eof_timer_destroy(handle);
handle->flags &= ~UV_HANDLE_READABLE;
uv_read_stop((uv_stream_t*) handle);
handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf);

View File

@ -1044,7 +1044,6 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
}
handle->flags &= ~UV_HANDLE_READABLE;
buf.base = 0;
buf.len = 0;
@ -1081,7 +1080,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
}
} else {
/* Connection closed */
handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE);
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf);

View File

@ -509,7 +509,7 @@ TEST_DECLARE (getters_setters)
TEST_DECLARE (not_writable_after_shutdown)
TEST_DECLARE (not_readable_nor_writable_on_read_error)
TEST_DECLARE (not_readable_on_eof)
TEST_DECLARE (readable_on_eof)
#ifndef _WIN32
TEST_DECLARE (fork_timer)
@ -1145,8 +1145,8 @@ TASK_LIST_START
TEST_HELPER (not_writable_after_shutdown, tcp4_echo_server)
TEST_ENTRY (not_readable_nor_writable_on_read_error)
TEST_HELPER (not_readable_nor_writable_on_read_error, tcp4_echo_server)
TEST_ENTRY (not_readable_on_eof)
TEST_HELPER (not_readable_on_eof, tcp4_echo_server)
TEST_ENTRY (readable_on_eof)
TEST_HELPER (readable_on_eof, tcp4_echo_server)
TEST_ENTRY (metrics_idle_time)
TEST_ENTRY (metrics_idle_time_thread)

View File

@ -35,7 +35,7 @@ static int close_cb_called;
static void write_cb(uv_write_t* req, int status) {
write_cb_called++;
ASSERT(status == 0);
ASSERT_EQ(status, 0);
}
static void alloc_cb(uv_handle_t* handle,
@ -51,12 +51,20 @@ static void close_cb(uv_handle_t* handle) {
}
static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
read_cb_called++;
int r;
ASSERT(nread == UV_EOF);
ASSERT(0 == uv_is_readable(handle));
ASSERT_EQ(nread, UV_EOF);
ASSERT_EQ(uv_is_readable(handle), 1);
ASSERT_EQ(uv_is_writable(handle), 1);
uv_close((uv_handle_t*) handle, close_cb);
if (++read_cb_called == 3) {
uv_close((uv_handle_t*) handle, close_cb);
ASSERT_EQ(uv_is_readable(handle), 0);
ASSERT_EQ(uv_is_writable(handle), 0);
} else {
r = uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb);
ASSERT_EQ(r, 0);
}
}
static void connect_cb(uv_connect_t* req, int status) {
@ -64,10 +72,9 @@ static void connect_cb(uv_connect_t* req, int status) {
uv_buf_t close_me;
connect_cb_called++;
ASSERT(status == 0);
ASSERT_EQ(status, 0);
r = uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb);
ASSERT(r == 0);
read_cb((uv_stream_t*) &tcp_client, UV_EOF, NULL);
close_me = uv_buf_init(close_me_cmd, sizeof(close_me_cmd));
@ -77,26 +84,27 @@ static void connect_cb(uv_connect_t* req, int status) {
1,
write_cb);
ASSERT(r == 0);
ASSERT_EQ(r, 0);
}
TEST_IMPL(not_readable_on_eof) {
TEST_IMPL(readable_on_eof) {
struct sockaddr_in sa;
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa));
ASSERT(0 == uv_loop_init(&loop));
ASSERT(0 == uv_tcp_init(&loop, &tcp_client));
ASSERT_EQ(uv_ip4_addr("127.0.0.1", TEST_PORT, &sa), 0);
ASSERT_EQ(uv_loop_init(&loop), 0);
ASSERT_EQ(uv_tcp_init(&loop, &tcp_client), 0);
ASSERT(0 == uv_tcp_connect(&connect_req,
&tcp_client,
(const struct sockaddr*) &sa,
connect_cb));
ASSERT_EQ(uv_tcp_connect(&connect_req,
&tcp_client,
(const struct sockaddr*) &sa,
connect_cb),
0);
ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
ASSERT_EQ(uv_run(&loop, UV_RUN_DEFAULT), 0);
ASSERT(connect_cb_called == 1);
ASSERT(read_cb_called == 1);
ASSERT(write_cb_called == 1);
ASSERT(close_cb_called == 1);
ASSERT_EQ(connect_cb_called, 1);
ASSERT_EQ(read_cb_called, 3);
ASSERT_EQ(write_cb_called, 1);
ASSERT_EQ(close_cb_called, 1);
MAKE_VALGRIND_HAPPY();
return 0;