In libuv v1.x (963ecc82) in Windows 10, I noticed that if I
'uv_shutdown' a 'uv_pipe_t' being read, it will cause its 'uv_read_cb'
to be called, and without calling 'uv_alloc_cb' first. Is this
expected?
I was surprised because it is not what happens in Linux, nor in
Windows if we use a 'uv_tcp_t' instead of a `uv_pipe`, which keeps
being read even after shutdown, as stated in the docs: "Shutdown the
outgoing (write) side of a duplex stream."
Finally, my code didn't expect to have 'uv_read_cb' called without
first calling the 'uv_alloc_cb', even though it will just report an
error (UV_EOF?) and therefore the buffer allocation is not necessary.
Since this seems to only happen in very rare cases
(win32+pipe+shutdown) I just wanted to check here if it was actually
expected.
I attached a small example to reproduce this scenario The output for
Linux is below, and only the server reading side is ended:
```
libuv_pipeshutdown.c:91:main(err >= 0)
libuv_pipeshutdown.c:94:main(err >= 0)
libuv_pipeshutdown.c:97:main(err >= 0)
libuv_pipeshutdown.c:99:main(err >= 0)
libuv_pipeshutdown.c:103:main(err >= 0)
libuv_pipeshutdown.c:32:on_server_accept(server_stream)
libuv_pipeshutdown.c:33:on_server_accept(err >= 0)
libuv_pipeshutdown.c:36:on_server_accept(err >= 0)
libuv_pipeshutdown.c:39:on_server_accept(err >= 0)
libuv_pipeshutdown.c:41:on_server_accept(err >= 0)
libuv_pipeshutdown.c:69:on_client_connect(shutdown_req)
libuv_pipeshutdown.c:70:on_client_connect(err >= 0)
libuv_pipeshutdown.c:72:on_client_connect(err >= 0)
libuv_pipeshutdown.c:60:on_client_shutdown(err >= 0)
libuv_pipeshutdown.c:62:on_client_shutdown(err >= 0)
libuv_pipeshutdown.c:22:on_server_alloc(handle->data == NULL)
libuv_pipeshutdown.c:15:on_server_read(stream->data == server_buffer)
libuv_pipeshutdown.c:17:on_server_read(nread == UV_EOF)
```
The ouput on Windows 10 is:
```
libuv_pipeshutdown.c:91:main(err >= 0)
libuv_pipeshutdown.c:94:main(err >= 0)
libuv_pipeshutdown.c:97:main(err >= 0)
libuv_pipeshutdown.c:99:main(err >= 0)
libuv_pipeshutdown.c:103:main(err >= 0)
libuv_pipeshutdown.c:69:on_client_connect(shutdown_req)
libuv_pipeshutdown.c:70:on_client_connect(err >= 0)
libuv_pipeshutdown.c:72:on_client_connect(err >= 0)
libuv_pipeshutdown.c:32:on_server_accept(server_stream)
libuv_pipeshutdown.c:33:on_server_accept(err >= 0)
libuv_pipeshutdown.c:36:on_server_accept(err >= 0)
libuv_pipeshutdown.c:39:on_server_accept(err >= 0)
libuv_pipeshutdown.c:41:on_server_accept(err >= 0)
libuv_pipeshutdown.c:60:on_client_shutdown(err >= 0)
libuv_pipeshutdown.c:62:on_client_shutdown(err >= 0)
libuv_pipeshutdown.c:46:on_client_read(stream->data == client_buffer)
Assertion failed: stream->data == client_buffer, file
libuv_pipeshutdown.c, line 46
```
Thanks in advance.
--
Renato Maia
--
You received this message because you are subscribed to the Google Groups
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/libuv/CAB-PuDog31wxVU64zfKPLFGgL2CXW5NmGQGVLcYxYOFh0DJM_A%40mail.gmail.com.
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <uv.h>
#define BUFFER_SIZE 1024
#define log(F,V) printf("%s:%d:%s("F")\n",__FILE__,__LINE__,__func__, V)
#define log_assert(C) {log("%s",#C);assert(C);}
char server_buffer[BUFFER_SIZE];
char client_buffer[BUFFER_SIZE];
static void on_server_read (uv_stream_t *stream, ssize_t nread, const uv_buf_t
*buffer)
{
log_assert(stream->data == server_buffer);
stream->data = NULL;
log_assert(nread == UV_EOF);
}
static void on_server_alloc (uv_handle_t *handle, size_t suggested_size,
uv_buf_t *buffer)
{
log_assert(handle->data == NULL);
handle->data = server_buffer;
buffer->base = server_buffer;
buffer->len = BUFFER_SIZE;
}
static void on_server_accept (uv_stream_t *server_passive, int err)
{
uv_pipe_t *server_stream = (uv_pipe_t *)server_passive->data;
log_assert(server_stream);
log_assert(err >= 0);
server_passive->data = NULL;
err = uv_pipe_init(server_passive->loop, server_stream, 0);
log_assert(err >= 0);
server_stream->data = NULL;
err = uv_accept(server_passive, (uv_stream_t *)server_stream);
log_assert(err >= 0);
err = uv_read_start((uv_stream_t *)server_stream, on_server_alloc,
on_server_read);
log_assert(err >= 0);
}
static void on_client_read (uv_stream_t *stream, ssize_t nread, const uv_buf_t
*buffer)
{
log_assert(stream->data == client_buffer);
stream->data = NULL;
}
static void on_client_alloc (uv_handle_t *handle, size_t suggested_size,
uv_buf_t *buffer)
{
log_assert(handle->data);
handle->data = client_buffer;
buffer->base = client_buffer;
buffer->len = BUFFER_SIZE;
}
static void on_client_shutdown (uv_shutdown_t *request, int err)
{
log_assert(err >= 0);
err = uv_read_start((uv_stream_t *)request->handle, on_client_alloc,
on_client_read);
log_assert(err >= 0);
}
static void on_client_connect (uv_connect_t *request, int err)
{
uv_shutdown_t *shutdown_req = (uv_shutdown_t *)request->data;
log_assert(shutdown_req);
log_assert(err >= 0);
err = uv_shutdown(shutdown_req, (uv_stream_t *)request->handle,
on_client_shutdown);
log_assert(err >= 0);
request->data = NULL;
}
#ifdef _WIN32
#define PIPE_ADDRRESS "\\\\?\\pipe\\localaddress.pipe"
#else
#define PIPE_ADDRRESS "localaddress.pipe"
#endif
int main(int argc, char const *argv[])
{
uv_loop_t loop;
uv_pipe_t server_passive, server_stream, client_stream;
uv_connect_t connect_req;
uv_shutdown_t shutdown_req;
int err;
err = uv_loop_init(&loop);
log_assert(err >= 0);
err = uv_pipe_init(&loop, &server_passive, 0);
log_assert(err >= 0);
server_passive.data = &server_passive;
err = uv_pipe_bind(&server_passive, PIPE_ADDRRESS);
log_assert(err >= 0);
err = uv_listen((uv_stream_t *)&server_passive, 3, on_server_accept);
log_assert(err >= 0);
server_passive.data = &server_stream;
err = uv_pipe_init(&loop, &client_stream, 0);
log_assert(err >= 0);
uv_pipe_connect(&connect_req, &client_stream, PIPE_ADDRRESS,
on_client_connect);
connect_req.data = &shutdown_req;
err = uv_run(&loop, UV_RUN_DEFAULT);
log_assert(err >= 0);
return 0;
}