pipe: allow queueing pending handles
If multiple handles arrive to the IPC pipe at the same time (happens on some platforms), libuv will queue them internally, and call `read2_cb` multiple times with a null-buffer and proper `handle_type`.
This commit is contained in:
parent
f166d6d705
commit
08aeaf6193
@ -229,6 +229,7 @@ typedef struct {
|
|||||||
uv_connection_cb connection_cb; \
|
uv_connection_cb connection_cb; \
|
||||||
int delayed_error; \
|
int delayed_error; \
|
||||||
int accepted_fd; \
|
int accepted_fd; \
|
||||||
|
int* queued_fds; \
|
||||||
UV_STREAM_PRIVATE_PLATFORM_FIELDS \
|
UV_STREAM_PRIVATE_PLATFORM_FIELDS \
|
||||||
|
|
||||||
#define UV_TCP_PRIVATE_FIELDS /* empty */
|
#define UV_TCP_PRIVATE_FIELDS /* empty */
|
||||||
|
|||||||
@ -376,6 +376,9 @@ typedef void (*uv_read_cb)(uv_stream_t* stream,
|
|||||||
* Just like the uv_read_cb except that if the pending parameter is true
|
* Just like the uv_read_cb except that if the pending parameter is true
|
||||||
* then you can use uv_accept() to pull the new handle into the process.
|
* then you can use uv_accept() to pull the new handle into the process.
|
||||||
* If no handle is pending then pending will be UV_UNKNOWN_HANDLE.
|
* If no handle is pending then pending will be UV_UNKNOWN_HANDLE.
|
||||||
|
*
|
||||||
|
* NOTE: The buffer may be a null buffer if multiple fds were accepted and
|
||||||
|
* read2_cb is called for pending ones.
|
||||||
*/
|
*/
|
||||||
typedef void (*uv_read2_cb)(uv_pipe_t* pipe,
|
typedef void (*uv_read2_cb)(uv_pipe_t* pipe,
|
||||||
ssize_t nread,
|
ssize_t nread,
|
||||||
|
|||||||
@ -119,6 +119,7 @@ void uv__stream_init(uv_loop_t* loop,
|
|||||||
stream->connect_req = NULL;
|
stream->connect_req = NULL;
|
||||||
stream->shutdown_req = NULL;
|
stream->shutdown_req = NULL;
|
||||||
stream->accepted_fd = -1;
|
stream->accepted_fd = -1;
|
||||||
|
stream->queued_fds = NULL;
|
||||||
stream->delayed_error = 0;
|
stream->delayed_error = 0;
|
||||||
QUEUE_INIT(&stream->write_queue);
|
QUEUE_INIT(&stream->write_queue);
|
||||||
QUEUE_INIT(&stream->write_completed_queue);
|
QUEUE_INIT(&stream->write_completed_queue);
|
||||||
@ -559,6 +560,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
|||||||
if (server->accepted_fd == -1)
|
if (server->accepted_fd == -1)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
switch (client->type) {
|
switch (client->type) {
|
||||||
case UV_NAMED_PIPE:
|
case UV_NAMED_PIPE:
|
||||||
case UV_TCP:
|
case UV_TCP:
|
||||||
@ -568,8 +570,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
/* TODO handle error */
|
/* TODO handle error */
|
||||||
uv__close(server->accepted_fd);
|
uv__close(server->accepted_fd);
|
||||||
server->accepted_fd = -1;
|
goto done;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -577,8 +578,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
|||||||
err = uv_udp_open((uv_udp_t*) client, server->accepted_fd);
|
err = uv_udp_open((uv_udp_t*) client, server->accepted_fd);
|
||||||
if (err) {
|
if (err) {
|
||||||
uv__close(server->accepted_fd);
|
uv__close(server->accepted_fd);
|
||||||
server->accepted_fd = -1;
|
goto done;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -586,9 +586,31 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uv__io_start(server->loop, &server->io_watcher, UV__POLLIN);
|
done:
|
||||||
|
/* Process queued fds */
|
||||||
|
if (server->queued_fds != NULL) {
|
||||||
|
/* Read first */
|
||||||
|
server->accepted_fd = server->queued_fds[2];
|
||||||
|
|
||||||
|
/* All read, free */
|
||||||
|
if (--server->queued_fds[0] == 0) {
|
||||||
|
free(server->queued_fds);
|
||||||
|
server->queued_fds = NULL;
|
||||||
|
} else {
|
||||||
|
/* Shift rest */
|
||||||
|
memmove(server->queued_fds + 2,
|
||||||
|
server->queued_fds + 3,
|
||||||
|
server->queued_fds[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Invoke read_cb one more time */
|
||||||
|
uv__io_feed(server->loop, &server->io_watcher);
|
||||||
|
} else {
|
||||||
server->accepted_fd = -1;
|
server->accepted_fd = -1;
|
||||||
return 0;
|
if (err == 0)
|
||||||
|
uv__io_start(server->loop, &server->io_watcher, UV__POLLIN);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -951,6 +973,41 @@ static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
|
||||||
|
int queue_offset;
|
||||||
|
int queue_len;
|
||||||
|
|
||||||
|
if (stream->queued_fds == NULL) {
|
||||||
|
queue_offset = 0;
|
||||||
|
queue_len = 8;
|
||||||
|
stream->queued_fds = malloc((queue_len + 2) * sizeof(*stream->queued_fds));
|
||||||
|
if (stream->queued_fds == NULL)
|
||||||
|
return UV_ENOMEM;
|
||||||
|
stream->queued_fds[1] = queue_len;
|
||||||
|
} else {
|
||||||
|
queue_offset = stream->queued_fds[0];
|
||||||
|
queue_len = stream->queued_fds[1];
|
||||||
|
|
||||||
|
/* Grow */
|
||||||
|
if (queue_offset == queue_len) {
|
||||||
|
queue_len += 8;
|
||||||
|
stream->queued_fds = realloc(stream->queued_fds,
|
||||||
|
(queue_len + 2) *
|
||||||
|
sizeof(*stream->queued_fds));
|
||||||
|
if (stream->queued_fds == NULL)
|
||||||
|
return UV_ENOMEM;
|
||||||
|
stream->queued_fds[1] = queue_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put fd in a queue */
|
||||||
|
stream->queued_fds[0] = queue_offset;
|
||||||
|
stream->queued_fds[2 + queue_offset++] = fd;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void uv__read(uv_stream_t* stream) {
|
static void uv__read(uv_stream_t* stream) {
|
||||||
uv_buf_t buf;
|
uv_buf_t buf;
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
@ -958,6 +1015,16 @@ static void uv__read(uv_stream_t* stream) {
|
|||||||
struct cmsghdr* cmsg;
|
struct cmsghdr* cmsg;
|
||||||
char cmsg_space[64];
|
char cmsg_space[64];
|
||||||
int count;
|
int count;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* Has queued fds */
|
||||||
|
if (stream->accepted_fd != -1) {
|
||||||
|
static uv_buf_t buf = { NULL, 0 };
|
||||||
|
stream->read2_cb((uv_pipe_t*) stream,
|
||||||
|
0,
|
||||||
|
&buf,
|
||||||
|
uv__handle_type(stream->accepted_fd));
|
||||||
|
}
|
||||||
|
|
||||||
stream->flags &= ~UV_STREAM_READ_PARTIAL;
|
stream->flags &= ~UV_STREAM_READ_PARTIAL;
|
||||||
|
|
||||||
@ -1046,17 +1113,20 @@ static void uv__read(uv_stream_t* stream) {
|
|||||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||||
|
|
||||||
if (cmsg->cmsg_type == SCM_RIGHTS) {
|
if (cmsg->cmsg_type == SCM_RIGHTS) {
|
||||||
if (stream->accepted_fd != -1) {
|
|
||||||
fprintf(stderr, "(libuv) ignoring extra FD received\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* silence aliasing warning */
|
/* silence aliasing warning */
|
||||||
{
|
|
||||||
void* pv = CMSG_DATA(cmsg);
|
void* pv = CMSG_DATA(cmsg);
|
||||||
int* pi = pv;
|
int* pi = pv;
|
||||||
|
|
||||||
|
/* Already has accepted fd, queue now */
|
||||||
|
if (stream->accepted_fd != -1) {
|
||||||
|
err = uv__stream_queue_fd(stream, *pi);
|
||||||
|
if (err != 0) {
|
||||||
|
uv__stream_read_cb(stream, err, NULL, UV_UNKNOWN_HANDLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
stream->accepted_fd = *pi;
|
stream->accepted_fd = *pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
|
fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
|
||||||
cmsg->cmsg_type);
|
cmsg->cmsg_type);
|
||||||
@ -1493,6 +1563,8 @@ void uv__stream_close(uv_stream_t* handle) {
|
|||||||
handle->accepted_fd = -1;
|
handle->accepted_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(handle->queued_fds);
|
||||||
|
|
||||||
assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
|
assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user