[PATCH v13 1/2] ntdll/socket: Implement exclusive flag for IOCTL_AFD_POLL.
Guillaume Charifi
guillaume.charifi at sfr.fr
Tue Sep 21 02:43:32 CDT 2021
Signed-off-by: Guillaume Charifi <guillaume.charifi at sfr.fr>
---
dlls/ntdll/unix/socket.c | 6 +--
include/wine/afd.h | 2 +-
server/protocol.def | 1 +
server/sock.c | 101 ++++++++++++++++++++++++++++++++++-----
4 files changed, 95 insertions(+), 15 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c
index 73d61c0d4e6..c40d0b526d7 100644
--- a/dlls/ntdll/unix/socket.c
+++ b/dlls/ntdll/unix/socket.c
@@ -736,12 +736,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] );
@@ -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/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 a5030fcf813..6a3faf3e625 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;
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 fc234e89865..f2799eb120a 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 );
@@ -274,7 +277,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 */
};
@@ -840,6 +843,8 @@ static void complete_async_polls( struct sock *sock, int event, int error )
LIST_FOR_EACH_ENTRY_SAFE( req, next, &poll_list, struct poll_req, entry )
{
unsigned int i;
+ unsigned int j;
+ int complete = 0;
if (req->iosb->status != STATUS_PENDING) continue;
@@ -848,28 +853,50 @@ static void complete_async_polls( struct sock *sock, int event, int error )
if (req->sockets[i].sock != sock) continue;
if (!(req->sockets[i].flags & flags)) continue;
- if (debug_level)
- fprintf( stderr, "completing poll for socket %p, wanted %#x got %#x\n",
- sock, req->sockets[i].flags, flags );
+ complete = 1;
+ break;
+ }
- req->output[i].flags = req->sockets[i].flags & flags;
- req->output[i].status = sock_get_ntstatus( error );
+ if (!complete)
+ continue;
- async_request_complete( req->async, STATUS_SUCCESS, 0,
- req->count * sizeof(*req->output), req->output );
- break;
+ if (debug_level)
+ fprintf( stderr, "completing poll for socket %p, wanted %#x got %#x\n",
+ sock, req->sockets[i].flags, flags );
+
+ for (j = 0; j < req->count; ++j)
+ {
+ struct sock *sock = req->sockets[j].sock;
+
+ if (sock->main_poll == req)
+ sock->main_poll = NULL;
}
+
+ 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 );
}
}
static void async_poll_timeout( void *private )
{
struct poll_req *req = private;
+ unsigned int i;
req->timeout = NULL;
if (req->iosb->status != STATUS_PENDING) return;
+ for (i = 0; i < req->count; ++i)
+ {
+ struct sock *sock = req->sockets[i].sock;
+
+ if (sock->main_poll == req)
+ sock->main_poll = NULL;
+ }
+
async_request_complete( req->async, STATUS_TIMEOUT, 0, req->count * sizeof(*req->output), req->output );
}
@@ -1217,6 +1244,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 );
@@ -1383,6 +1433,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;
@@ -2840,7 +2891,32 @@ 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)
+{
+ 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)
+ {
+ /* Previous exclusive main poll replaced by new exclusive poll. */
+ main_poll->iosb->status = STATUS_SUCCESS;
+ main_poll->iosb->out_data = main_poll->output;
+ main_poll->iosb->out_size = main_poll->count * sizeof(*main_poll->output);
+ async_terminate(main_poll->async, STATUS_ALERTED);
+
+ 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;
@@ -2881,11 +2957,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 );
@@ -3287,7 +3366,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 );
--
2.33.0
More information about the wine-devel
mailing list