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;
}

Reply via email to