Fixes: 1eb56b20baefcdccaafbb622cadc71670c149e18 Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/server.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 771ababf904..043d381e1af 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -391,6 +391,7 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOO /* the server will pass us NULL if a call failed synchronously */ set_async_iosb( call->async_io.sb, result->async_io.status, info ); } + else result->async_io.status = STATUS_PENDING; /* restart it */ break; } case APC_VIRTUAL_ALLOC:
async_transmit_proc() expects the former.
Fixes: 1eb56b20baefcdccaafbb622cadc71670c149e18 Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 73d61c0d4e6..ec6aa02d14a 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1017,7 +1017,7 @@ static NTSTATUS try_transmit( int sock_fd, int file_fd, struct async_transmit_io
if (ret < read_size || (async->file_len && async->file_cursor == async->file_len)) async->file = NULL; - return STATUS_PENDING; /* still more data to send */ + return STATUS_DEVICE_NOT_READY; /* still more data to send */ }
while (async->tail_cursor < async->buffers.TailLength)
From: Guillaume Charifi guillaume.charifi@sfr.fr
Signed-off-by: Guillaume Charifi guillaume.charifi@sfr.fr Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Resent with the patches reordered.
dlls/ntdll/unix/socket.c | 6 +- dlls/ws2_32/tests/afd.c | 349 +++++++++++++++++++++++++++++++++++++++ include/wine/afd.h | 2 +- 3 files changed, 353 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index ec6aa02d14a..c1a29f5d5e0 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -736,12 +736,12 @@ 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 %#x, 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->exclusive) FIXME( "ignoring exclusive flag\n" ); 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] ); diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index eb7c8ee50de..647b7e41f63 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -31,6 +31,8 @@ #include "wine/afd.h" #include "wine/test.h"
+#define TIMEOUT_INFINITE _I64_MAX + static void tcp_socketpair(SOCKET *src, SOCKET *dst) { SOCKET server = INVALID_SOCKET; @@ -212,6 +214,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 +749,351 @@ 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 = 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 explicitly 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); + todo_wine 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); + + /* A new 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); + todo_wine 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); + todo_wine 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); + todo_wine 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); + todo_wine 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 +2099,7 @@ START_TEST(afd)
test_open_device(); test_poll(); + test_poll_exclusive(); test_poll_completion_port(); test_recv(); test_event_select(); 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 {
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/sock.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 1628be91794..a44c127825c 100644 --- a/server/sock.c +++ b/server/sock.c @@ -833,6 +833,12 @@ static int get_poll_flags( struct sock *sock, int event ) return flags; }
+static void complete_async_poll( struct poll_req *req, unsigned int status ) +{ + /* pass 0 as result; client will set actual result size */ + async_request_complete( req->async, status, 0, req->count * sizeof(*req->output), req->output ); +} + static void complete_async_polls( struct sock *sock, int event, int error ) { int flags = get_poll_flags( sock, event ); @@ -856,8 +862,7 @@ static void complete_async_polls( struct sock *sock, int event, int error ) req->output[i].flags = req->sockets[i].flags & flags; req->output[i].status = sock_get_ntstatus( error );
- async_request_complete( req->async, STATUS_SUCCESS, 0, - req->count * sizeof(*req->output), req->output ); + complete_async_poll( req, STATUS_SUCCESS ); break; } } @@ -871,7 +876,7 @@ static void async_poll_timeout( void *private )
if (req->iosb->status != STATUS_PENDING) return;
- async_request_complete( req->async, STATUS_TIMEOUT, 0, req->count * sizeof(*req->output), req->output ); + complete_async_poll( req, STATUS_TIMEOUT ); }
static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) @@ -1321,12 +1326,7 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h } }
- if (signaled) - { - /* pass 0 as result; client will set actual result size */ - async_request_complete( poll_req->async, STATUS_SUCCESS, 0, - poll_req->count * sizeof(*poll_req->output), poll_req->output ); - } + if (signaled) complete_async_poll( poll_req, STATUS_SUCCESS ); } }
@@ -2914,7 +2914,7 @@ static void poll_socket( struct sock *poll_sock, struct async *async, timeout_t }
if (!timeout || signaled) - async_request_complete( req->async, STATUS_SUCCESS, 0, count * sizeof(*output), output ); + complete_async_poll( req, STATUS_SUCCESS );
for (i = 0; i < req->count; ++i) sock_reselect( req->sockets[i].sock );
From: Guillaume Charifi guillaume.charifi@sfr.fr
Signed-off-by: Guillaume Charifi guillaume.charifi@sfr.fr Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Resent with a bit of restructuring; namely, use the introduced complete_async_poll() helper.
dlls/ntdll/unix/socket.c | 2 +- dlls/ws2_32/tests/afd.c | 10 +++--- server/protocol.def | 1 + server/sock.c | 66 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 70 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index c1a29f5d5e0..75c54295c20 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -741,7 +741,6 @@ static NTSTATUS sock_poll( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi params->padding[0], params->padding[1], params->padding[2], params->sockets[0].socket, params->sockets[0].flags );
- if (params->exclusive) FIXME( "ignoring exclusive flag\n" ); 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] ); @@ -782,6 +781,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/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 647b7e41f63..9e888f1fcb9 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -867,7 +867,7 @@ static void test_poll_exclusive(void) ok(ret == STATUS_PENDING, "got %#x\n", ret);
ret = WaitForSingleObject(events[0], 100); - todo_wine ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
ret = WaitForSingleObject(events[1], 100); ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); @@ -927,7 +927,7 @@ static void test_poll_exclusive(void) ok(ret == STATUS_PENDING, "got %#x\n", ret);
ret = WaitForSingleObject(events[1], 100); - todo_wine ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
ret = WaitForSingleObject(events[2], 100); ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); @@ -997,7 +997,7 @@ static void test_poll_exclusive(void) ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
ret = WaitForSingleObject(events[2], 100); - todo_wine ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
ret = WaitForSingleObject(events[3], 100); ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); @@ -1048,7 +1048,7 @@ static void test_poll_exclusive(void) CloseHandle(thrd);
ret = WaitForSingleObject(events[0], 100); - todo_wine ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
CancelIo((HANDLE)ctl_sock);
@@ -1073,7 +1073,7 @@ static void test_poll_exclusive(void) ok(ret == STATUS_PENDING, "got %#x\n", ret);
ret = WaitForSingleObject(events[0], 100); - todo_wine ok(ret == STATUS_SUCCESS, "got %#x\n", ret); + ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
ret = WaitForSingleObject(events[1], 100); ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); diff --git a/server/protocol.def b/server/protocol.def index ad0a6e2cdcf..1ae64d496f4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1451,6 +1451,7 @@ struct poll_socket_output
/* Perform an async poll on a socket */ @REQ(poll_socket) + int exclusive; /* is the poll 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 a44c127825c..396447a0aa4 100644 --- a/server/sock.c +++ b/server/sock.c @@ -128,6 +128,7 @@ struct poll_req struct async *async; struct iosb *iosb; struct timeout_user *timeout; + int exclusive; unsigned int count; struct poll_socket_output *output; struct @@ -205,6 +206,7 @@ struct sock struct list accept_list; /* list of pending accept requests */ struct accept_req *accept_recv_req; /* pending accept-into request which will recv on this socket */ struct connect_req *connect_req; /* pending connection request */ + struct poll_req *main_poll; /* main poll */ union win_sockaddr addr; /* socket name */ int addr_len; /* socket name length */ unsigned int rcvbuf; /* advisory recv buffer size */ @@ -231,6 +233,7 @@ static int sock_get_poll_events( struct fd *fd ); static void sock_poll_event( struct fd *fd, int event ); static enum server_fd_type sock_get_fd_type( struct fd *fd ); static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ); +static void sock_cancel_async( struct fd *fd, struct async *async ); static void sock_queue_async( struct fd *fd, struct async *async, int type, int count ); static void sock_reselect_async( struct fd *fd, struct async_queue *queue );
@@ -275,7 +278,7 @@ static const struct fd_ops sock_fd_ops = default_fd_get_file_info, /* get_file_info */ no_fd_get_volume_info, /* get_volume_info */ sock_ioctl, /* ioctl */ - default_fd_cancel_async, /* cancel_async */ + sock_cancel_async, /* cancel_async */ sock_queue_async, /* queue_async */ sock_reselect_async /* reselect_async */ }; @@ -835,6 +838,16 @@ static int get_poll_flags( struct sock *sock, int event )
static void complete_async_poll( struct poll_req *req, unsigned int status ) { + unsigned int i; + + for (i = 0; i < req->count; ++i) + { + struct sock *sock = req->sockets[i].sock; + + if (sock->main_poll == req) + sock->main_poll = NULL; + } + /* pass 0 as result; client will set actual result size */ async_request_complete( req->async, status, 0, req->count * sizeof(*req->output), req->output ); } @@ -1223,6 +1236,29 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd ) return FD_TYPE_SOCKET; }
+static void sock_cancel_async( struct fd *fd, struct async *async ) +{ + struct poll_req *req; + + LIST_FOR_EACH_ENTRY( req, &poll_list, struct poll_req, entry ) + { + unsigned int i; + + if (req->async != async) + continue; + + for (i = 0; i < req->count; i++) + { + struct sock *sock = req->sockets[i].sock; + + if (sock->main_poll == req) + sock->main_poll = NULL; + } + } + + async_terminate( async, STATUS_CANCELLED ); +} + static void sock_queue_async( struct fd *fd, struct async *async, int type, int count ) { struct sock *sock = get_fd_user( fd ); @@ -1384,6 +1420,7 @@ static struct sock *create_socket(void) sock->ifchange_obj = NULL; sock->accept_recv_req = NULL; sock->connect_req = NULL; + sock->main_poll = NULL; memset( &sock->addr, 0, sizeof(sock->addr) ); sock->addr_len = 0; sock->rd_shutdown = 0; @@ -2841,7 +2878,27 @@ 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 handle_exclusive_poll(struct poll_req *req) +{ + unsigned int i; + + for (i = 0; i < req->count; ++i) + { + struct sock *sock = req->sockets[i].sock; + struct poll_req *main_poll = sock->main_poll; + + if (main_poll && main_poll->exclusive && req->exclusive) + { + complete_async_poll( main_poll, STATUS_SUCCESS ); + main_poll = NULL; + } + + if (!main_poll) + sock->main_poll = req; + } +} + +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; @@ -2882,11 +2939,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;
+ handle_exclusive_poll(req); + list_add_tail( &poll_list, &req->entry ); async_set_completion_callback( async, free_poll_req, req ); queue_async( &poll_sock->poll_q, async ); @@ -3290,7 +3350,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 );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=98558
Your paranoid android.
=== debiant2 (32 bit report) ===
ws2_32: afd.c:339: Test failed: got flags 0x43 afd.c:345: Test failed: got flags 0x41