Signed-off-by: Guillaume Charifi guillaume.charifi@sfr.fr --- dlls/ntdll/unix/socket.c | 6 ++--- include/wine/afd.h | 2 +- server/protocol.def | 1 + server/sock.c | 52 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 8469def786a..b1b90b363ee 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -747,12 +747,11 @@ static NTSTATUS sock_poll( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi || in_size < offsetof( struct afd_poll_params, sockets[params->count] )) return STATUS_INVALID_PARAMETER;
- TRACE( "timeout %s, count %u, unknown %#x, padding (%#x, %#x, %#x), sockets[0] {%04lx, %#x}\n", - wine_dbgstr_longlong(params->timeout), params->count, params->unknown, + TRACE( "timeout %s, count %u, exclusive %u, padding (%#x, %#x, %#x), sockets[0] {%04lx, %#x}\n", + wine_dbgstr_longlong(params->timeout), params->count, params->exclusive, params->padding[0], params->padding[1], params->padding[2], params->sockets[0].socket, params->sockets[0].flags );
- if (params->unknown) FIXME( "unknown boolean is %#x\n", params->unknown ); if (params->padding[0]) FIXME( "padding[0] is %#x\n", params->padding[0] ); if (params->padding[1]) FIXME( "padding[1] is %#x\n", params->padding[1] ); if (params->padding[2]) FIXME( "padding[2] is %#x\n", params->padding[2] ); @@ -793,6 +792,7 @@ static NTSTATUS sock_poll( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi SERVER_START_REQ( poll_socket ) { req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) ); + req->exclusive = !!params->exclusive; req->timeout = params->timeout; wine_server_add_data( req, input, params->count * sizeof(*input) ); wine_server_set_reply( req, async->sockets, params->count * sizeof(async->sockets[0]) ); diff --git a/include/wine/afd.h b/include/wine/afd.h index e67ecae25a9..f4682f464e8 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -104,7 +104,7 @@ struct afd_poll_params { LONGLONG timeout; unsigned int count; - BOOLEAN unknown; + BOOLEAN exclusive; BOOLEAN padding[3]; struct { diff --git a/server/protocol.def b/server/protocol.def index 133d6ad0552..c6da8576f39 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1450,6 +1450,7 @@ struct poll_socket_output
/* Perform an async poll on a socket */ @REQ(poll_socket) + int exclusive; async_data_t async; /* async I/O parameters */ timeout_t timeout; /* timeout */ VARARG(sockets,poll_socket_input); /* list of sockets to poll */ diff --git a/server/sock.c b/server/sock.c index 3c5f2612b51..8fc21e39da1 100644 --- a/server/sock.c +++ b/server/sock.c @@ -128,12 +128,14 @@ struct poll_req struct async *async; struct iosb *iosb; struct timeout_user *timeout; + int exclusive; unsigned int count; struct poll_socket_output *output; struct { struct sock *sock; int flags; + int main; } sockets[1]; };
@@ -2839,7 +2841,50 @@ static int poll_single_socket( struct sock *sock, int mask ) return get_poll_flags( sock, pollfd.revents ) & mask; }
-static void poll_socket( struct sock *poll_sock, struct async *async, timeout_t timeout, +static void poll_handle_exclusive(struct poll_req *req) +{ + struct poll_req *areq; + unsigned int i, j; + + for (i = 0; i < req->count; ++i) + { + int has_main = FALSE; + + LIST_FOR_EACH_ENTRY(areq, &poll_list, struct poll_req, entry) + { + for (j = 0; j < areq->count; ++j) + { + if (areq->sockets[j].sock != req->sockets[i].sock) + continue; + + if (!areq->sockets[j].main) + continue; + + has_main = TRUE; + + if (areq->exclusive && req->exclusive) + { + /* Previous exclusive main poll replaced by new exclusive poll */ + areq->sockets[j].main = FALSE; + + areq->iosb->status = STATUS_SUCCESS; + areq->iosb->out_data = areq->output; + areq->iosb->out_size = areq->count * sizeof(*areq->output); + async_terminate(areq->async, STATUS_ALERTED); + + has_main = FALSE; + } + + goto next; + } + } + + next: + req->sockets[i].main = !has_main; + } +} + +static void poll_socket( struct sock *poll_sock, struct async *async, int exclusive, timeout_t timeout, unsigned int count, const struct poll_socket_input *input ) { struct poll_socket_output *output; @@ -2880,11 +2925,14 @@ static void poll_socket( struct sock *poll_sock, struct async *async, timeout_t req->sockets[i].flags = input[i].flags; }
+ req->exclusive = exclusive; req->count = count; req->async = (struct async *)grab_object( async ); req->iosb = async_get_iosb( async ); req->output = output;
+ poll_handle_exclusive(req); + list_add_tail( &poll_list, &req->entry ); async_set_completion_callback( async, free_poll_req, req ); queue_async( &poll_sock->poll_q, async ); @@ -3285,7 +3333,7 @@ DECL_HANDLER(poll_socket)
if ((async = create_request_async( sock->fd, get_fd_comp_flags( sock->fd ), &req->async ))) { - poll_socket( sock, async, req->timeout, count, input ); + poll_socket( sock, async, req->exclusive, req->timeout, count, input ); reply->wait = async_handoff( async, NULL, 0 ); reply->options = get_fd_options( sock->fd ); release_object( async );
Signed-off-by: Guillaume Charifi guillaume.charifi@sfr.fr --- dlls/ws2_32/tests/afd.c | 346 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+)
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index eb7c8ee50de..90aacc81580 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -212,6 +212,7 @@ static void test_poll(void)
in_params->timeout = 0; in_params->count = 1; + in_params->exclusive = FALSE; in_params->sockets[0].socket = listener; in_params->sockets[0].flags = ~0; in_params->sockets[0].status = 0xdeadbeef; @@ -746,6 +747,350 @@ static void test_poll(void) free(large_buffer); }
+struct poll_exclusive_thread_cb_ctx +{ + SOCKET ctl_sock; + HANDLE event; + IO_STATUS_BLOCK *io; + ULONG params_size; + struct afd_poll_params *in_params; + struct afd_poll_params *out_params; +}; + +static DWORD WINAPI poll_exclusive_thread_cb(void *param) +{ + struct poll_exclusive_thread_cb_ctx *ctx = param; + int ret; + + ret = NtDeviceIoControlFile((HANDLE)ctx->ctl_sock, ctx->event, NULL, NULL, ctx->io, + IOCTL_AFD_POLL, ctx->in_params, ctx->params_size, ctx->out_params, ctx->params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(ctx->event, 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + return 0; +} + +#define POLL_SOCK_CNT 2 +#define POLL_CNT 4 + +static void test_poll_exclusive(void) +{ + char in_buffer[offsetof(struct afd_poll_params, sockets[POLL_SOCK_CNT + 1])]; + char out_buffers[POLL_CNT][offsetof(struct afd_poll_params, sockets[POLL_SOCK_CNT + 1])]; + struct afd_poll_params *in_params = (struct afd_poll_params *)in_buffer; + struct afd_poll_params *out_params[POLL_CNT] = { + (struct afd_poll_params *)out_buffers[0], + (struct afd_poll_params *)out_buffers[1], + (struct afd_poll_params *)out_buffers[2], + (struct afd_poll_params *)out_buffers[3] + }; + SOCKET ctl_sock; + SOCKET socks[POLL_CNT]; + IO_STATUS_BLOCK io[POLL_CNT]; + HANDLE events[POLL_CNT]; + ULONG params_size; + struct poll_exclusive_thread_cb_ctx cb_ctx; + HANDLE thrd; + size_t i; + int ret; + + ctl_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + for (i = 0; i < POLL_CNT; i++) + { + socks[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + events[i] = CreateEventW(NULL, TRUE, FALSE, NULL); + } + + params_size = offsetof(struct afd_poll_params, sockets[1]); + + in_params->timeout = 0x7fffffffffffffff; /* TIMEOUT_INFINITE */ + in_params->count = 1; + in_params->exclusive = FALSE; + in_params->sockets[0].socket = socks[0]; + in_params->sockets[0].flags = ~0; + in_params->sockets[0].status = 0; + + /***** Exclusive explicitely terminated *****/ + + in_params->exclusive = TRUE; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + + /***** Same socket tests *****/ + + /* Basic non-exclusive behavior as reference */ + + in_params->exclusive = FALSE; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1], + IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + ret = WaitForSingleObject(events[1], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + /* If the main poll is exclusive it is terminated by the following exclusive */ + + in_params->exclusive = TRUE; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1], + IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + + ret = WaitForSingleObject(events[1], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + /* If the main poll is non-exclusive neither itself nor the following exclusives are terminated */ + + in_params->exclusive = FALSE; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + in_params->exclusive = TRUE; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1], + IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2], + IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + ret = WaitForSingleObject(events[1], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + ret = WaitForSingleObject(events[2], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + /* An exclusive poll can become main after the non-exclusive main have been terminated */ + + in_params->exclusive = FALSE; + + ret = NtDeviceIoControlFile((HANDLE)socks[0], events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + CancelIo((HANDLE)socks[0]); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + + in_params->exclusive = TRUE; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1], + IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2], + IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(events[1], 100); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + + ret = WaitForSingleObject(events[2], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + /* The exclusive check does not happen again after the call to NtDeviceIoControlFile() */ + + in_params->exclusive = FALSE; + + ret = NtDeviceIoControlFile((HANDLE)socks[0], events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + in_params->exclusive = TRUE; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1], + IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + CancelIo((HANDLE)socks[0]); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2], + IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(events[1], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + ret = WaitForSingleObject(events[2], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + /* After the main poll is terminated, any subsequent poll becomes the main + * and can be terminated if exclusive */ + + in_params->exclusive = FALSE; + + ret = NtDeviceIoControlFile((HANDLE)socks[0], events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + in_params->exclusive = TRUE; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1], + IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + CancelIo((HANDLE)socks[0]); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2], + IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[3], NULL, NULL, &io[3], + IOCTL_AFD_POLL, in_params, params_size, out_params[3], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(events[1], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + ret = WaitForSingleObject(events[2], 100); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + + ret = WaitForSingleObject(events[3], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + /***** Exclusive poll on different sockets *****/ + + in_params->exclusive = TRUE; + in_params->sockets[0].socket = socks[0]; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + in_params->sockets[0].socket = socks[1]; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1], + IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + ret = WaitForSingleObject(events[1], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + /***** Exclusive poll from other thread *****/ + + in_params->exclusive = TRUE; + in_params->sockets[0].socket = ctl_sock; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + cb_ctx.ctl_sock = ctl_sock; + cb_ctx.event = events[1]; + cb_ctx.io = &io[1]; + cb_ctx.params_size = params_size; + cb_ctx.in_params = in_params; + cb_ctx.out_params = out_params[1]; + + thrd = CreateThread(NULL, 0, poll_exclusive_thread_cb, &cb_ctx, 0, NULL); + WaitForSingleObject(thrd, INFINITE); + CloseHandle(thrd); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + /***** Exclusive poll on overlapping socket sets *****/ + + params_size = offsetof(struct afd_poll_params, sockets[2]); + + in_params->exclusive = TRUE; + in_params->count = 2; + in_params->sockets[0].socket = ctl_sock; + in_params->sockets[1].socket = socks[0]; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0], + IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + in_params->sockets[0].socket = ctl_sock; + in_params->sockets[1].socket = socks[1]; + + ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1], + IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size); + ok(ret == STATUS_PENDING, "got %#x\n", ret); + + ret = WaitForSingleObject(events[0], 100); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + + ret = WaitForSingleObject(events[1], 100); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + CancelIo((HANDLE)ctl_sock); + + /* Cleanup */ + + closesocket(ctl_sock); + + for (i = 0; i < POLL_CNT; i++) + { + closesocket(socks[i]); + CloseHandle(events[i]); + } +} + +#undef POLL_SOCK_CNT +#undef POLL_CNT + static void test_poll_completion_port(void) { struct afd_poll_params params = {0}; @@ -1751,6 +2096,7 @@ START_TEST(afd)
test_open_device(); test_poll(); + test_poll_exclusive(); test_poll_completion_port(); test_recv(); test_event_select();
On 9/6/21 12:47 PM, Guillaume Charifi wrote:
Signed-off-by: Guillaume Charifi guillaume.charifi@sfr.fr
dlls/ws2_32/tests/afd.c | 346 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+)
This looks mostly good, so I'm just going to add a few nitpicks inline...
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index eb7c8ee50de..90aacc81580 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -212,6 +212,7 @@ static void test_poll(void)
in_params->timeout = 0; in_params->count = 1;
- in_params->exclusive = FALSE; in_params->sockets[0].socket = listener; in_params->sockets[0].flags = ~0; in_params->sockets[0].status = 0xdeadbeef;
@@ -746,6 +747,350 @@ static void test_poll(void) free(large_buffer); }
+struct poll_exclusive_thread_cb_ctx +{
- SOCKET ctl_sock;
- HANDLE event;
- IO_STATUS_BLOCK *io;
- ULONG params_size;
- struct afd_poll_params *in_params;
- struct afd_poll_params *out_params;
+};
+static DWORD WINAPI poll_exclusive_thread_cb(void *param) +{
- struct poll_exclusive_thread_cb_ctx *ctx = param;
- int ret;
- ret = NtDeviceIoControlFile((HANDLE)ctx->ctl_sock, ctx->event, NULL, NULL, ctx->io,
IOCTL_AFD_POLL, ctx->in_params, ctx->params_size, ctx->out_params, ctx->params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(ctx->event, 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- return 0;
+}
+#define POLL_SOCK_CNT 2 +#define POLL_CNT 4
+static void test_poll_exclusive(void) +{
- char in_buffer[offsetof(struct afd_poll_params, sockets[POLL_SOCK_CNT + 1])];
- char out_buffers[POLL_CNT][offsetof(struct afd_poll_params, sockets[POLL_SOCK_CNT + 1])];
- struct afd_poll_params *in_params = (struct afd_poll_params *)in_buffer;
- struct afd_poll_params *out_params[POLL_CNT] = {
(struct afd_poll_params *)out_buffers[0],
(struct afd_poll_params *)out_buffers[1],
(struct afd_poll_params *)out_buffers[2],
(struct afd_poll_params *)out_buffers[3]
- };
- SOCKET ctl_sock;
- SOCKET socks[POLL_CNT];
- IO_STATUS_BLOCK io[POLL_CNT];
- HANDLE events[POLL_CNT];
- ULONG params_size;
- struct poll_exclusive_thread_cb_ctx cb_ctx;
- HANDLE thrd;
- size_t i;
- int ret;
- ctl_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- for (i = 0; i < POLL_CNT; i++)
- {
socks[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
events[i] = CreateEventW(NULL, TRUE, FALSE, NULL);
- }
- params_size = offsetof(struct afd_poll_params, sockets[1]);
- in_params->timeout = 0x7fffffffffffffff; /* TIMEOUT_INFINITE */
It'd probably be even better to actually define TIMEOUT_INFINITE somewhere above. You might also consider defining it to _I64_MAX or something.
- in_params->count = 1;
- in_params->exclusive = FALSE;
- in_params->sockets[0].socket = socks[0];
- in_params->sockets[0].flags = ~0;
- in_params->sockets[0].status = 0;
- /***** Exclusive explicitely terminated *****/
Typo, "explicitly".
- in_params->exclusive = TRUE;
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
- /***** Same socket tests *****/
- /* Basic non-exclusive behavior as reference */
- in_params->exclusive = FALSE;
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- ret = WaitForSingleObject(events[1], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- /* If the main poll is exclusive it is terminated by the following exclusive */
- in_params->exclusive = TRUE;
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
- ret = WaitForSingleObject(events[1], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- /* If the main poll is non-exclusive neither itself nor the following exclusives are terminated */
- in_params->exclusive = FALSE;
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- in_params->exclusive = TRUE;
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2],
IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- ret = WaitForSingleObject(events[1], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- ret = WaitForSingleObject(events[2], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- /* An exclusive poll can become main after the non-exclusive main have been terminated */
This is a bit misleading, because it makes it sound like the poll changes state while queued, which it doesn't. Maybe something like:
/* A poll is considered the main poll if no others are queued at the time. */
- in_params->exclusive = FALSE;
- ret = NtDeviceIoControlFile((HANDLE)socks[0], events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- CancelIo((HANDLE)socks[0]);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
- in_params->exclusive = TRUE;
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2],
IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(events[1], 100);
- ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
- ret = WaitForSingleObject(events[2], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- /* The exclusive check does not happen again after the call to NtDeviceIoControlFile() */
- in_params->exclusive = FALSE;
- ret = NtDeviceIoControlFile((HANDLE)socks[0], events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- in_params->exclusive = TRUE;
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- CancelIo((HANDLE)socks[0]);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2],
IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(events[1], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- ret = WaitForSingleObject(events[2], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- /* After the main poll is terminated, any subsequent poll becomes the main
* and can be terminated if exclusive */
- in_params->exclusive = FALSE;
- ret = NtDeviceIoControlFile((HANDLE)socks[0], events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- in_params->exclusive = TRUE;
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- CancelIo((HANDLE)socks[0]);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2],
IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[3], NULL, NULL, &io[3],
IOCTL_AFD_POLL, in_params, params_size, out_params[3], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(events[1], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- ret = WaitForSingleObject(events[2], 100);
- ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
- ret = WaitForSingleObject(events[3], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- /***** Exclusive poll on different sockets *****/
- in_params->exclusive = TRUE;
- in_params->sockets[0].socket = socks[0];
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- in_params->sockets[0].socket = socks[1];
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- ret = WaitForSingleObject(events[1], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- /***** Exclusive poll from other thread *****/
- in_params->exclusive = TRUE;
- in_params->sockets[0].socket = ctl_sock;
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- cb_ctx.ctl_sock = ctl_sock;
- cb_ctx.event = events[1];
- cb_ctx.io = &io[1];
- cb_ctx.params_size = params_size;
- cb_ctx.in_params = in_params;
- cb_ctx.out_params = out_params[1];
- thrd = CreateThread(NULL, 0, poll_exclusive_thread_cb, &cb_ctx, 0, NULL);
- WaitForSingleObject(thrd, INFINITE);
- CloseHandle(thrd);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- /***** Exclusive poll on overlapping socket sets *****/
- params_size = offsetof(struct afd_poll_params, sockets[2]);
- in_params->exclusive = TRUE;
- in_params->count = 2;
- in_params->sockets[0].socket = ctl_sock;
- in_params->sockets[1].socket = socks[0];
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- in_params->sockets[0].socket = ctl_sock;
- in_params->sockets[1].socket = socks[1];
- ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
- ok(ret == STATUS_PENDING, "got %#x\n", ret);
- ret = WaitForSingleObject(events[0], 100);
- ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
- ret = WaitForSingleObject(events[1], 100);
- ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
- CancelIo((HANDLE)ctl_sock);
- /* Cleanup */
- closesocket(ctl_sock);
- for (i = 0; i < POLL_CNT; i++)
- {
closesocket(socks[i]);
CloseHandle(events[i]);
- }
+}
+#undef POLL_SOCK_CNT +#undef POLL_CNT
- static void test_poll_completion_port(void) { struct afd_poll_params params = {0};
@@ -1751,6 +2096,7 @@ START_TEST(afd)
test_open_device(); test_poll();
- test_poll_exclusive(); test_poll_completion_port(); test_recv(); test_event_select();
On 9/6/21 12:47 PM, Guillaume Charifi wrote:
Signed-off-by: Guillaume Charifi guillaume.charifi@sfr.fr
dlls/ntdll/unix/socket.c | 6 ++--- include/wine/afd.h | 2 +- server/protocol.def | 1 + server/sock.c | 52 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 6 deletions(-)
Based on your description [1], it seems to me like it'd be easier just to save the "main" poll request as a poll_req field in the relevant socket. Then your poll_handle_exclusive() can pretty much do exactly what you describe in that mail:
if (sock->main_poll && sock->main_poll->exclusive && req->exclusive) // terminate it if (!sock->main_poll) sock->main_poll = req;
Of course the problem is, we can't do this yet, because cancel_async can terminate the async behind our back. I wrote [2] for a different purpose, but if accepted, it'd help here as well.
In lieu of [2], though, it'd at least be nice to see a helper function like "get_main_poll", to avoid that goto and boolean variable.
I don't like the name "main_poll", but I'm hard-pressed to come up with something better. "exclusive_poll" perhaps, but it's not guaranteed to actually be exclusive...
[1] https://www.winehq.org/pipermail/wine-devel/2021-September/194463.html
On 9/6/21 12:47 PM, Guillaume Charifi wrote:
Signed-off-by: Guillaume Charifi guillaume.charifi@sfr.fr
dlls/ntdll/unix/socket.c | 6 ++--- include/wine/afd.h | 2 +- server/protocol.def | 1 + server/sock.c | 52 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 6 deletions(-)
Based on your description [1], it seems to me like it'd be easier just to save the "main" poll request as a poll_req field in the relevant socket. Then your poll_handle_exclusive() can pretty much do exactly what you describe in that mail:
if (sock->main_poll && sock->main_poll->exclusive && req->exclusive) // terminate it if (!sock->main_poll) sock->main_poll = req;
Of course the problem is, we can't do this yet, because cancel_async can terminate the async behind our back. I wrote [2] for a different purpose, but if accepted, it'd help here as well.
Yeah, I didn't do it because I wasn't sure the referenced handles would still be valid at the time the function would get called... This would definitely help.
In lieu of [2], though, it'd at least be nice to see a helper function like "get_main_poll", to avoid that goto and boolean variable.
Agreed.
I don't like the name "main_poll", but I'm hard-pressed to come up with something better. "exclusive_poll" perhaps, but it's not guaranteed to actually be exclusive...
Me neither, what do you think of "pinned_poll"?
[1] https://www.winehq.org/pipermail/wine-devel/2021-September/194463.html
On 9/7/21 12:01 AM, Guillaume Charifi-Hoareau wrote:
On 9/6/21 12:47 PM, Guillaume Charifi wrote:
Signed-off-by: Guillaume Charifi guillaume.charifi@sfr.fr
dlls/ntdll/unix/socket.c | 6 ++--- include/wine/afd.h | 2 +- server/protocol.def | 1 + server/sock.c | 52 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 6 deletions(-)
Based on your description [1], it seems to me like it'd be easier just to save the "main" poll request as a poll_req field in the relevant socket. Then your poll_handle_exclusive() can pretty much do exactly what you describe in that mail:
if (sock->main_poll && sock->main_poll->exclusive && req->exclusive) // terminate it if (!sock->main_poll) sock->main_poll = req;
Of course the problem is, we can't do this yet, because cancel_async can terminate the async behind our back. I wrote [2] for a different purpose, but if accepted, it'd help here as well.
Yeah, I didn't do it because I wasn't sure the referenced handles would still be valid at the time the function would get called... This would definitely help.
In lieu of [2], though, it'd at least be nice to see a helper function like "get_main_poll", to avoid that goto and boolean variable.
Agreed.
I don't like the name "main_poll", but I'm hard-pressed to come up with something better. "exclusive_poll" perhaps, but it's not guaranteed to actually be exclusive...
Me neither, what do you think of "pinned_poll"?
I'm not sure it's an improvement, although it doesn't seem much if at all worse...
Ultimately it's hard to name something whose purpose is completely undocumented and makes no sense :-(
[1] https://www.winehq.org/pipermail/wine-devel/2021-September/194463.html