afd: use IO_STATUS_BLOCK instead of OVERLAPPED to track async poll ops
This reduces per-socket memory usage, as the OVERLAPPED structure contains some fields that are never used.
This commit is contained in:
parent
a627f365fd
commit
d5f8f5f1b1
48
src/afd.c
48
src/afd.c
@ -55,33 +55,18 @@ error:
|
|||||||
|
|
||||||
int afd_poll(HANDLE afd_helper_handle,
|
int afd_poll(HANDLE afd_helper_handle,
|
||||||
AFD_POLL_INFO* poll_info,
|
AFD_POLL_INFO* poll_info,
|
||||||
OVERLAPPED* overlapped) {
|
IO_STATUS_BLOCK* io_status_block) {
|
||||||
IO_STATUS_BLOCK* iosb;
|
|
||||||
HANDLE event;
|
|
||||||
void* apc_context;
|
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
/* Blocking operation is not supported. */
|
/* Blocking operation is not supported. */
|
||||||
assert(overlapped != NULL);
|
assert(io_status_block != NULL);
|
||||||
|
|
||||||
iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
|
io_status_block->Status = STATUS_PENDING;
|
||||||
event = overlapped->hEvent;
|
|
||||||
|
|
||||||
/* Do what other windows APIs would do: if hEvent has it's lowest bit set,
|
|
||||||
* don't post a completion to the completion port. */
|
|
||||||
if ((uintptr_t) event & 1) {
|
|
||||||
event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
|
|
||||||
apc_context = NULL;
|
|
||||||
} else {
|
|
||||||
apc_context = overlapped;
|
|
||||||
}
|
|
||||||
|
|
||||||
iosb->Status = STATUS_PENDING;
|
|
||||||
status = NtDeviceIoControlFile(afd_helper_handle,
|
status = NtDeviceIoControlFile(afd_helper_handle,
|
||||||
event,
|
|
||||||
NULL,
|
NULL,
|
||||||
apc_context,
|
NULL,
|
||||||
iosb,
|
io_status_block,
|
||||||
|
io_status_block,
|
||||||
IOCTL_AFD_POLL,
|
IOCTL_AFD_POLL,
|
||||||
poll_info,
|
poll_info,
|
||||||
sizeof *poll_info,
|
sizeof *poll_info,
|
||||||
@ -95,3 +80,24 @@ int afd_poll(HANDLE afd_helper_handle,
|
|||||||
else
|
else
|
||||||
return_set_error(-1, RtlNtStatusToDosError(status));
|
return_set_error(-1, RtlNtStatusToDosError(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int afd_cancel_poll(HANDLE afd_helper_handle,
|
||||||
|
IO_STATUS_BLOCK* io_status_block) {
|
||||||
|
NTSTATUS cancel_status;
|
||||||
|
IO_STATUS_BLOCK cancel_iosb;
|
||||||
|
|
||||||
|
/* If the poll operation has already completed or has been cancelled earlier,
|
||||||
|
* there's nothing left for us to do. */
|
||||||
|
if (io_status_block->Status != STATUS_PENDING)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cancel_status =
|
||||||
|
NtCancelIoFileEx(afd_helper_handle, io_status_block, &cancel_iosb);
|
||||||
|
|
||||||
|
/* NtCancelIoFileEx() may return STATUS_NOT_FOUND if the operation completed
|
||||||
|
* just before calling NtCancelIoFileEx(). This is not an error. */
|
||||||
|
if (cancel_status == STATUS_SUCCESS || cancel_status == STATUS_NOT_FOUND)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return_set_error(-1, RtlNtStatusToDosError(cancel_status));
|
||||||
|
}
|
||||||
|
|||||||
@ -34,6 +34,8 @@ WEPOLL_INTERNAL int afd_create_helper_handle(HANDLE iocp_handle,
|
|||||||
|
|
||||||
WEPOLL_INTERNAL int afd_poll(HANDLE afd_helper_handle,
|
WEPOLL_INTERNAL int afd_poll(HANDLE afd_helper_handle,
|
||||||
AFD_POLL_INFO* poll_info,
|
AFD_POLL_INFO* poll_info,
|
||||||
OVERLAPPED* overlapped);
|
IO_STATUS_BLOCK* io_status_block);
|
||||||
|
WEPOLL_INTERNAL int afd_cancel_poll(HANDLE afd_helper_handle,
|
||||||
|
IO_STATUS_BLOCK* io_status_block);
|
||||||
|
|
||||||
#endif /* WEPOLL_AFD_H_ */
|
#endif /* WEPOLL_AFD_H_ */
|
||||||
|
|||||||
11
src/nt.h
11
src/nt.h
@ -25,6 +25,10 @@ typedef NTSTATUS* PNTSTATUS;
|
|||||||
#define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L)
|
#define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef STATUS_NOT_FOUND
|
||||||
|
#define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct _IO_STATUS_BLOCK {
|
typedef struct _IO_STATUS_BLOCK {
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
ULONG_PTR Information;
|
ULONG_PTR Information;
|
||||||
@ -65,6 +69,13 @@ typedef struct _OBJECT_ATTRIBUTES {
|
|||||||
(STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)
|
(STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)
|
||||||
|
|
||||||
#define NT_NTDLL_IMPORT_LIST(X) \
|
#define NT_NTDLL_IMPORT_LIST(X) \
|
||||||
|
X(NTSTATUS, \
|
||||||
|
NTAPI, \
|
||||||
|
NtCancelIoFileEx, \
|
||||||
|
(HANDLE FileHandle, \
|
||||||
|
PIO_STATUS_BLOCK IoRequestToCancel, \
|
||||||
|
PIO_STATUS_BLOCK IoStatusBlock)) \
|
||||||
|
\
|
||||||
X(NTSTATUS, \
|
X(NTSTATUS, \
|
||||||
NTAPI, \
|
NTAPI, \
|
||||||
NtCreateFile, \
|
NtCreateFile, \
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "nt.h"
|
||||||
#include "poll-group.h"
|
#include "poll-group.h"
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
@ -162,10 +163,11 @@ static int port__feed_events(port_state_t* port_state,
|
|||||||
DWORD i;
|
DWORD i;
|
||||||
|
|
||||||
for (i = 0; i < iocp_event_count; i++) {
|
for (i = 0; i < iocp_event_count; i++) {
|
||||||
OVERLAPPED* overlapped = iocp_events[i].lpOverlapped;
|
IO_STATUS_BLOCK* io_status_block =
|
||||||
|
(IO_STATUS_BLOCK*) iocp_events[i].lpOverlapped;
|
||||||
struct epoll_event* ev = &epoll_events[epoll_event_count];
|
struct epoll_event* ev = &epoll_events[epoll_event_count];
|
||||||
|
|
||||||
epoll_event_count += sock_feed_event(port_state, overlapped, ev);
|
epoll_event_count += sock_feed_event(port_state, io_status_block, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return epoll_event_count;
|
return epoll_event_count;
|
||||||
|
|||||||
25
src/sock.c
25
src/sock.c
@ -26,7 +26,7 @@ typedef enum sock__poll_status {
|
|||||||
} sock__poll_status_t;
|
} sock__poll_status_t;
|
||||||
|
|
||||||
typedef struct sock_state {
|
typedef struct sock_state {
|
||||||
OVERLAPPED overlapped;
|
IO_STATUS_BLOCK io_status_block;
|
||||||
AFD_POLL_INFO poll_info;
|
AFD_POLL_INFO poll_info;
|
||||||
queue_node_t queue_node;
|
queue_node_t queue_node;
|
||||||
tree_node_t tree_node;
|
tree_node_t tree_node;
|
||||||
@ -51,16 +51,11 @@ static inline void sock__free(sock_state_t* sock_state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int sock__cancel_poll(sock_state_t* sock_state) {
|
static int sock__cancel_poll(sock_state_t* sock_state) {
|
||||||
HANDLE afd_helper_handle =
|
|
||||||
poll_group_get_afd_helper_handle(sock_state->poll_group);
|
|
||||||
assert(sock_state->poll_status == SOCK__POLL_PENDING);
|
assert(sock_state->poll_status == SOCK__POLL_PENDING);
|
||||||
|
|
||||||
/* CancelIoEx() may fail with ERROR_NOT_FOUND if the overlapped operation has
|
if (afd_cancel_poll(poll_group_get_afd_helper_handle(sock_state->poll_group),
|
||||||
* already completed. This is not a problem and we proceed normally. */
|
&sock_state->io_status_block) < 0)
|
||||||
if (!HasOverlappedIoCompleted(&sock_state->overlapped) &&
|
return -1;
|
||||||
!CancelIoEx(afd_helper_handle, &sock_state->overlapped) &&
|
|
||||||
GetLastError() != ERROR_NOT_FOUND)
|
|
||||||
return_map_error(-1);
|
|
||||||
|
|
||||||
sock_state->poll_status = SOCK__POLL_CANCELLED;
|
sock_state->poll_status = SOCK__POLL_CANCELLED;
|
||||||
sock_state->pending_events = 0;
|
sock_state->pending_events = 0;
|
||||||
@ -237,11 +232,9 @@ int sock_update(port_state_t* port_state, sock_state_t* sock_state) {
|
|||||||
sock_state->poll_info.Handles[0].Events =
|
sock_state->poll_info.Handles[0].Events =
|
||||||
sock__epoll_events_to_afd_events(sock_state->user_events);
|
sock__epoll_events_to_afd_events(sock_state->user_events);
|
||||||
|
|
||||||
memset(&sock_state->overlapped, 0, sizeof sock_state->overlapped);
|
|
||||||
|
|
||||||
if (afd_poll(poll_group_get_afd_helper_handle(sock_state->poll_group),
|
if (afd_poll(poll_group_get_afd_helper_handle(sock_state->poll_group),
|
||||||
&sock_state->poll_info,
|
&sock_state->poll_info,
|
||||||
&sock_state->overlapped) < 0) {
|
&sock_state->io_status_block) < 0) {
|
||||||
switch (GetLastError()) {
|
switch (GetLastError()) {
|
||||||
case ERROR_IO_PENDING:
|
case ERROR_IO_PENDING:
|
||||||
/* Overlapped poll operation in progress; this is expected. */
|
/* Overlapped poll operation in progress; this is expected. */
|
||||||
@ -269,10 +262,10 @@ int sock_update(port_state_t* port_state, sock_state_t* sock_state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int sock_feed_event(port_state_t* port_state,
|
int sock_feed_event(port_state_t* port_state,
|
||||||
OVERLAPPED* overlapped,
|
IO_STATUS_BLOCK* io_status_block,
|
||||||
struct epoll_event* ev) {
|
struct epoll_event* ev) {
|
||||||
sock_state_t* sock_state =
|
sock_state_t* sock_state =
|
||||||
container_of(overlapped, sock_state_t, overlapped);
|
container_of(io_status_block, sock_state_t, io_status_block);
|
||||||
AFD_POLL_INFO* poll_info = &sock_state->poll_info;
|
AFD_POLL_INFO* poll_info = &sock_state->poll_info;
|
||||||
uint32_t epoll_events = 0;
|
uint32_t epoll_events = 0;
|
||||||
|
|
||||||
@ -283,10 +276,10 @@ int sock_feed_event(port_state_t* port_state,
|
|||||||
/* Socket has been deleted earlier and can now be freed. */
|
/* Socket has been deleted earlier and can now be freed. */
|
||||||
return sock__delete(port_state, sock_state, false);
|
return sock__delete(port_state, sock_state, false);
|
||||||
|
|
||||||
} else if ((NTSTATUS) overlapped->Internal == STATUS_CANCELLED) {
|
} else if (io_status_block->Status == STATUS_CANCELLED) {
|
||||||
/* The poll request was cancelled by CancelIoEx. */
|
/* The poll request was cancelled by CancelIoEx. */
|
||||||
|
|
||||||
} else if (!NT_SUCCESS(overlapped->Internal)) {
|
} else if (!NT_SUCCESS(io_status_block->Status)) {
|
||||||
/* The overlapped request itself failed in an unexpected way. */
|
/* The overlapped request itself failed in an unexpected way. */
|
||||||
epoll_events = EPOLLERR;
|
epoll_events = EPOLLERR;
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#define WEPOLL_SOCK_H_
|
#define WEPOLL_SOCK_H_
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "nt.h"
|
||||||
#include "wepoll.h"
|
#include "wepoll.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ WEPOLL_INTERNAL int sock_set_event(port_state_t* port_state,
|
|||||||
WEPOLL_INTERNAL int sock_update(port_state_t* port_state,
|
WEPOLL_INTERNAL int sock_update(port_state_t* port_state,
|
||||||
sock_state_t* sock_state);
|
sock_state_t* sock_state);
|
||||||
WEPOLL_INTERNAL int sock_feed_event(port_state_t* port_state,
|
WEPOLL_INTERNAL int sock_feed_event(port_state_t* port_state,
|
||||||
OVERLAPPED* overlapped,
|
IO_STATUS_BLOCK* io_status_block,
|
||||||
struct epoll_event* ev);
|
struct epoll_event* ev);
|
||||||
|
|
||||||
WEPOLL_INTERNAL sock_state_t* sock_state_from_queue_node(
|
WEPOLL_INTERNAL sock_state_t* sock_state_from_queue_node(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user