From b895c1866efe391c5e7d7a724c06d19341b7e455 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 14:28:01 +0200 Subject: [PATCH 01/16] test: write newline before check() failure message --- test/shared/test-util.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/shared/test-util.h b/test/shared/test-util.h index 314d54b..6cd6808 100644 --- a/test/shared/test-util.h +++ b/test/shared/test-util.h @@ -20,7 +20,8 @@ void no_inline no_return check_fail(const char* message); #define check(expression) \ (void) ((!!(expression)) || \ - (check_fail("Check failed:\n" \ + (check_fail("\n" \ + "Check failed:\n" \ " test: " #expression "\n" \ " file: " __FILE__ "\n" \ " line: " __check_to_string(__LINE__) "\n"), \ From 5323fa751b25cfce027e0b3d3a0a42651b2e9cb2 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 14:32:13 +0200 Subject: [PATCH 02/16] misc: remove javascript formatting rules from .clang-format --- .clang-format | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.clang-format b/.clang-format index c83cd2b..21fe245 100644 --- a/.clang-format +++ b/.clang-format @@ -20,18 +20,3 @@ SpacesInContainerLiterals: false # Alas, not supported: # ForceEmptyLineAtEOF: true - ---- -Language: JavaScript -BasedOnStyle: Google - -AllowShortFunctionsOnASingleLine: Empty -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -BinPackArguments: false -BinPackParameters: false -BreakBeforeBraces: Attach -ColumnLimit: 79 -IndentWrappedFunctionNames: true -MaxEmptyLinesToKeep: 1 -SpacesInContainerLiterals: false From 3315e2fb1b47ddb6eb50d486a172915a40f175d8 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 14:24:33 +0200 Subject: [PATCH 03/16] sock: remove unnecessary forward declaration of poll_req_t --- src/sock.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sock.h b/src/sock.h index 2ff9c24..86d983e 100644 --- a/src/sock.h +++ b/src/sock.h @@ -11,7 +11,6 @@ #include "win.h" typedef struct ep_port ep_port_t; -typedef struct poll_req poll_req_t; typedef struct ep_sock { tree_node_t tree_node; From c3506ab046cc563316a552156a81abeff032ac5b Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 14:23:43 +0200 Subject: [PATCH 04/16] error: remove unnecessary include from error.h --- src/error.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/error.h b/src/error.h index 1e4591b..ea17c1b 100644 --- a/src/error.h +++ b/src/error.h @@ -1,8 +1,6 @@ #ifndef WEPOLL_ERROR_H_ #define WEPOLL_ERROR_H_ -#include - #include "internal.h" #include "win.h" From 279315afcd9b84484d52b40f99505ccdc8f30d26 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 14:11:44 +0200 Subject: [PATCH 05/16] src: add missing includes --- src/poll-group.c | 1 + src/port.c | 1 + src/sock.c | 1 + test/test-multi-poll.c | 1 + test/test-oneshot-and-hangup.c | 1 + 5 files changed, 5 insertions(+) diff --git a/src/poll-group.c b/src/poll-group.c index 11e3ec2..0511e01 100644 --- a/src/poll-group.c +++ b/src/poll-group.c @@ -1,5 +1,6 @@ #include #include +#include #include "error.h" #include "poll-group.h" diff --git a/src/port.c b/src/port.c index 0459b9c..afc1dee 100644 --- a/src/port.c +++ b/src/port.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "error.h" #include "poll-group.h" diff --git a/src/sock.c b/src/sock.c index 0dca3eb..9f9dbb0 100644 --- a/src/sock.c +++ b/src/sock.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "afd.h" #include "error.h" diff --git a/test/test-multi-poll.c b/test/test-multi-poll.c index 73f5287..d2e5a0b 100644 --- a/test/test-multi-poll.c +++ b/test/test-multi-poll.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "init.h" #include "test-util.h" diff --git a/test/test-oneshot-and-hangup.c b/test/test-oneshot-and-hangup.c index ff1d731..9cd5e3a 100644 --- a/test/test-oneshot-and-hangup.c +++ b/test/test-oneshot-and-hangup.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "test-util.h" #include "wepoll.h" From 7c52fee8be360cbd8342d49b72477bda618056d8 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 14:25:27 +0200 Subject: [PATCH 06/16] util: fix comments about polyfills --- src/util.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util.h b/src/util.h index 2715803..7cb45d6 100644 --- a/src/util.h +++ b/src/util.h @@ -26,13 +26,13 @@ typedef intptr_t ssize_t; #define unused_fn /* nothing */ #endif +/* Polyfill `inline` for older versions of msvc (up to Visual Studio 2013) */ #if defined(_MSC_VER) && _MSC_VER < 1900 -/* Polyfill `inline` for msvc 12 (Visual Studio 2013) */ #define inline __inline #endif -#if (defined(__clang__) || defined(__GNUC__)) && !defined(static_assert) /* Polyfill `static_assert` for some versions of clang and gcc. */ +#if (defined(__clang__) || defined(__GNUC__)) && !defined(static_assert) #define static_assert(condition, message) typedef __attribute__( \ (__unused__)) int __static_assert_##__LINE__[(condition) ? 1 : -1]; #endif From 0fbf0e2b0ecdd86d4d54cec55a30ce43cc17a857 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 14:21:11 +0200 Subject: [PATCH 07/16] src: use more condensed style for short comments --- src/afd.c | 11 ++++------- src/port.c | 6 ++---- src/tree.h | 7 +++---- src/ws.c | 3 +-- test/test-oneshot-and-hangup.c | 7 +++---- test/test-udp-pings.c | 3 +-- 6 files changed, 14 insertions(+), 23 deletions(-) diff --git a/src/afd.c b/src/afd.c index ed74ffb..1b6e8fe 100644 --- a/src/afd.c +++ b/src/afd.c @@ -37,8 +37,7 @@ static const GUID _AFD_PROVIDER_GUID_LIST[] = { /* This protocol info record is used by afd_create_driver_socket() to create * sockets that can be used as the first argument to afd_poll(). It is - * populated on startup by afd_global_init(). - */ + * populated on startup by afd_global_init(). */ static WSAPROTOCOL_INFOW _afd_driver_socket_template; static const WSAPROTOCOL_INFOW* _afd_find_protocol_info( @@ -76,8 +75,7 @@ int afd_global_init(void) { /* Find a WSAPROTOCOL_INFOW structure that we can use to create an MSAFD * socket. Preferentially we pick a UDP socket, otherwise try TCP or any - * other type. - */ + * other type. */ for (;;) { afd_info = _afd_find_protocol_info(infos, infos_count, IPPROTO_UDP); if (afd_info != NULL) @@ -174,9 +172,8 @@ int afd_poll(SOCKET driver_socket, sizeof *poll_info); if (overlapped == NULL) { - /* If this is a blocking operation, wait for the event to become - * signaled, and then grab the real status from the io status block. - */ + /* If this is a blocking operation, wait for the event to become signaled, + * and then grab the real status from the io status block. */ if (status == STATUS_PENDING) { DWORD r = WaitForSingleObject(event, INFINITE); diff --git a/src/port.c b/src/port.c index afc1dee..4d92f0f 100644 --- a/src/port.c +++ b/src/port.c @@ -214,8 +214,7 @@ int ep_port_wait(ep_port_t* port_info, } /* Compute the timeout for GetQueuedCompletionStatus, and the wait end - * time, if the user specified a timeout other than zero or infinite. - */ + * time, if the user specified a timeout other than zero or infinite. */ if (timeout > 0) { due = GetTickCount64() + timeout; gqcs_timeout = (DWORD) timeout; @@ -228,8 +227,7 @@ int ep_port_wait(ep_port_t* port_info, EnterCriticalSection(&port_info->lock); /* Dequeue completion packets until either at least one interesting event - * has been discovered, or the timeout is reached. - */ + * has been discovered, or the timeout is reached. */ for (;;) { ULONGLONG now; diff --git a/src/tree.h b/src/tree.h index d1c58ea..139e13f 100644 --- a/src/tree.h +++ b/src/tree.h @@ -7,10 +7,9 @@ #include "internal.h" #include "util.h" -/* NB: the tree functions do not set errno or LastError when they fail. Each of - * the API functions has at most one failure mode. It is up to the caller to - * set an appropriate error code when necessary. - */ +/* N.b.: the tree functions do not set errno or LastError when they fail. Each + * of the API functions has at most one failure mode. It is up to the caller to + * set an appropriate error code when necessary. */ typedef struct tree tree_t; typedef struct tree_node tree_node_t; diff --git a/src/ws.c b/src/ws.c index e100de5..857b7f0 100644 --- a/src/ws.c +++ b/src/ws.c @@ -42,8 +42,7 @@ SOCKET ws_get_base_socket(SOCKET socket) { } /* Retrieves a copy of the winsock catalog. - * The infos pointer must be released by the caller with free(). - */ + * The infos pointer must be released by the caller with free(). */ ssize_t ws_get_protocol_catalog(WSAPROTOCOL_INFOW** infos_out) { DWORD buffer_size = _WS_INITIAL_CATALOG_BUFFER_SIZE; int count; diff --git a/test/test-oneshot-and-hangup.c b/test/test-oneshot-and-hangup.c index 9cd5e3a..cd9d719 100644 --- a/test/test-oneshot-and-hangup.c +++ b/test/test-oneshot-and-hangup.c @@ -200,10 +200,9 @@ int main(void) { } { - /* Add the *write* socket to the epoll set. The event mask is empty, - * but since EPOLLHUP and EPOLLERR are always reportable, the next call to - * epoll_wait() should be able to detect that the connection is now closed. - */ + /* Add the *write* socket to the epoll set. The event mask is empty, but + * since EPOLLHUP and EPOLLERR are always reportable, the next call to + * epoll_wait() should detect that the connection has been closed. */ struct epoll_event ev; int r; diff --git a/test/test-udp-pings.c b/test/test-udp-pings.c index 90b2b7d..020bd67 100644 --- a/test/test-udp-pings.c +++ b/test/test-udp-pings.c @@ -53,8 +53,7 @@ int main(void) { r = connect(sock, (struct sockaddr*) &address, sizeof address); /* Unlike unix, windows sets the error to EWOULDBLOCK when the connection - * is being established in the background. - */ + * is being established in the background. */ check(r == 0 || WSAGetLastError() == WSAEWOULDBLOCK); ev.events = EPOLLOUT | EPOLLERR | EPOLLONESHOT; From 5b7b5b0ed45e280957d258fd00e62d8b43aebe5e Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 14:39:54 +0200 Subject: [PATCH 08/16] afd: remove unused event type and flag definitions --- src/afd.h | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/src/afd.h b/src/afd.h index 21e6f73..a1180e7 100644 --- a/src/afd.h +++ b/src/afd.h @@ -7,36 +7,15 @@ #include "win.h" /* clang-format off */ - -#define AFD_NO_FAST_IO 0x00000001 -#define AFD_OVERLAPPED 0x00000002 -#define AFD_IMMEDIATE 0x00000004 - -#define AFD_POLL_RECEIVE_BIT 0 -#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT) -#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1 -#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT) -#define AFD_POLL_SEND_BIT 2 -#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT) -#define AFD_POLL_DISCONNECT_BIT 3 -#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT) -#define AFD_POLL_ABORT_BIT 4 -#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT) -#define AFD_POLL_LOCAL_CLOSE_BIT 5 -#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT) -#define AFD_POLL_CONNECT_BIT 6 -#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT) -#define AFD_POLL_ACCEPT_BIT 7 -#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT) -#define AFD_POLL_CONNECT_FAIL_BIT 8 -#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT) -#define AFD_POLL_QOS_BIT 9 -#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT) -#define AFD_POLL_GROUP_QOS_BIT 10 -#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT) -#define AFD_NUM_POLL_EVENTS 11 -#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1) - +#define AFD_POLL_RECEIVE 0x0001 +#define AFD_POLL_RECEIVE_EXPEDITED 0x0002 +#define AFD_POLL_SEND 0x0004 +#define AFD_POLL_DISCONNECT 0x0008 +#define AFD_POLL_ABORT 0x0010 +#define AFD_POLL_LOCAL_CLOSE 0x0020 +#define AFD_POLL_CONNECT 0x0040 +#define AFD_POLL_ACCEPT 0x0080 +#define AFD_POLL_CONNECT_FAIL 0x0100 /* clang-format on */ typedef struct _AFD_POLL_HANDLE_INFO { From 55d08bee97d9bbeaff5a14ba74445ea9a39bab67 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 22:55:03 +0200 Subject: [PATCH 09/16] port: assert that the update queue is empty before freeing --- src/port.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/port.c b/src/port.c index 4d92f0f..11b8086 100644 --- a/src/port.c +++ b/src/port.c @@ -110,6 +110,8 @@ int ep_port_delete(ep_port_t* port_info) { poll_group_delete(poll_group); } + assert(queue_empty(&port_info->sock_update_queue)); + DeleteCriticalSection(&port_info->lock); _ep_port_free(port_info); From fb9820b06c7dbe33d7d22b8fea9bde5382035c07 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 23:21:26 +0200 Subject: [PATCH 10/16] src: improve phrasing of some comments, fix spelling error --- src/api.c | 4 ++-- src/port.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/api.c b/src/api.c index a35d180..76f95a5 100644 --- a/src/api.c +++ b/src/api.c @@ -106,8 +106,8 @@ int epoll_ctl(HANDLE ephnd, int op, SOCKET sock, struct epoll_event* ev) { return 0; err: - /* On Linux, in the case of epoll_ctl_mod(), EBADF takes precendence over - * other errors. Wepoll copies this behavior. */ + /* On Linux, in the case of epoll_ctl_mod(), EBADF takes priority over other + * errors. Wepoll mimics this behavior. */ err_check_handle(ephnd); err_check_handle((HANDLE) sock); return -1; diff --git a/src/port.c b/src/port.c index 11b8086..3701d7f 100644 --- a/src/port.c +++ b/src/port.c @@ -131,8 +131,7 @@ static int _ep_port_update_events(ep_port_t* port_info) { if (ep_sock_update(port_info, sock_info) < 0) return -1; - /* ep_sock_update() removes the socket from the update list if - * successfull. */ + /* ep_sock_update() removes the socket from the update queue. */ } return 0; From 74d7624afd9f446cfc9071cd180e950c79b1f9a3 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 22:57:13 +0200 Subject: [PATCH 11/16] port: access ep_sock_t.tree_node and ep_sock_t.queue_node through getters --- src/port.c | 36 +++++++++++++++++++----------------- src/sock.c | 16 ++++++++++++++++ src/sock.h | 5 +++++ 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/port.c b/src/port.c index 3701d7f..7d42a87 100644 --- a/src/port.c +++ b/src/port.c @@ -96,12 +96,12 @@ int ep_port_delete(ep_port_t* port_info) { assert(port_info->iocp == NULL); while ((tree_node = tree_root(&port_info->sock_tree)) != NULL) { - ep_sock_t* sock_info = container_of(tree_node, ep_sock_t, tree_node); + ep_sock_t* sock_info = ep_sock_from_tree_node(tree_node); ep_sock_force_delete(port_info, sock_info); } while ((queue_node = queue_first(&port_info->sock_deleted_queue)) != NULL) { - ep_sock_t* sock_info = container_of(queue_node, ep_sock_t, queue_node); + ep_sock_t* sock_info = ep_sock_from_queue_node(queue_node); ep_sock_force_delete(port_info, sock_info); } @@ -126,7 +126,7 @@ static int _ep_port_update_events(ep_port_t* port_info) { * it. */ while (!queue_empty(sock_update_queue)) { queue_node_t* queue_node = queue_first(sock_update_queue); - ep_sock_t* sock_info = container_of(queue_node, ep_sock_t, queue_node); + ep_sock_t* sock_info = ep_sock_from_queue_node(queue_node); if (ep_sock_update(port_info, sock_info) < 0) return -1; @@ -342,48 +342,50 @@ int ep_port_ctl(ep_port_t* port_info, int ep_port_register_socket_handle(ep_port_t* port_info, ep_sock_t* sock_info, SOCKET socket) { - if (tree_add(&port_info->sock_tree, &sock_info->tree_node, socket) < 0) + if (tree_add( + &port_info->sock_tree, ep_sock_to_tree_node(sock_info), socket) < 0) return_error(-1, ERROR_ALREADY_EXISTS); return 0; } void ep_port_unregister_socket_handle(ep_port_t* port_info, ep_sock_t* sock_info) { - tree_del(&port_info->sock_tree, &sock_info->tree_node); + tree_del(&port_info->sock_tree, ep_sock_to_tree_node(sock_info)); } ep_sock_t* ep_port_find_socket(ep_port_t* port_info, SOCKET socket) { - ep_sock_t* sock_info = safe_container_of( - tree_find(&port_info->sock_tree, socket), ep_sock_t, tree_node); - if (sock_info == NULL) + tree_node_t* tree_node = tree_find(&port_info->sock_tree, socket); + if (tree_node == NULL) return_error(NULL, ERROR_NOT_FOUND); - return sock_info; + return ep_sock_from_tree_node(tree_node); } void ep_port_request_socket_update(ep_port_t* port_info, ep_sock_t* sock_info) { - if (queue_enqueued(&sock_info->queue_node)) + if (queue_enqueued(ep_sock_to_queue_node(sock_info))) return; - queue_append(&port_info->sock_update_queue, &sock_info->queue_node); + queue_append(&port_info->sock_update_queue, + ep_sock_to_queue_node(sock_info)); } void ep_port_cancel_socket_update(ep_port_t* port_info, ep_sock_t* sock_info) { unused_var(port_info); - if (!queue_enqueued(&sock_info->queue_node)) + if (!queue_enqueued(ep_sock_to_queue_node(sock_info))) return; - queue_remove(&sock_info->queue_node); + queue_remove(ep_sock_to_queue_node(sock_info)); } void ep_port_add_deleted_socket(ep_port_t* port_info, ep_sock_t* sock_info) { - if (queue_enqueued(&sock_info->queue_node)) + if (queue_enqueued(ep_sock_to_queue_node(sock_info))) return; - queue_append(&port_info->sock_deleted_queue, &sock_info->queue_node); + queue_append(&port_info->sock_deleted_queue, + ep_sock_to_queue_node(sock_info)); } void ep_port_remove_deleted_socket(ep_port_t* port_info, ep_sock_t* sock_info) { unused_var(port_info); - if (!queue_enqueued(&sock_info->queue_node)) + if (!queue_enqueued(ep_sock_to_queue_node(sock_info))) return; - queue_remove(&sock_info->queue_node); + queue_remove(ep_sock_to_queue_node(sock_info)); } diff --git a/src/sock.c b/src/sock.c index 9f9dbb0..b550d82 100644 --- a/src/sock.c +++ b/src/sock.c @@ -375,3 +375,19 @@ int ep_sock_feed_event(ep_port_t* port_info, return ev_count; } + +queue_node_t* ep_sock_to_queue_node(ep_sock_t* sock_info) { + return &sock_info->queue_node; +} + +ep_sock_t* ep_sock_from_tree_node(tree_node_t* tree_node) { + return container_of(tree_node, ep_sock_t, tree_node); +} + +tree_node_t* ep_sock_to_tree_node(ep_sock_t* sock_info) { + return &sock_info->tree_node; +} + +ep_sock_t* ep_sock_from_queue_node(queue_node_t* queue_node) { + return container_of(queue_node, ep_sock_t, queue_node); +} diff --git a/src/sock.h b/src/sock.h index 86d983e..27383df 100644 --- a/src/sock.h +++ b/src/sock.h @@ -32,4 +32,9 @@ WEPOLL_INTERNAL int ep_sock_feed_event(ep_port_t* port_info, OVERLAPPED* overlapped, struct epoll_event* ev); +WEPOLL_INTERNAL ep_sock_t* ep_sock_from_queue_node(queue_node_t* queue_node); +WEPOLL_INTERNAL queue_node_t* ep_sock_to_queue_node(ep_sock_t* sock_info); +WEPOLL_INTERNAL ep_sock_t* ep_sock_from_tree_node(tree_node_t* tree_node); +WEPOLL_INTERNAL tree_node_t* ep_sock_to_tree_node(ep_sock_t* sock_info); + #endif /* WEPOLL_SOCK_H_ */ From 7c57e192981967eb6d7b5e20e792fb79d87639a7 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 3 May 2018 23:24:39 +0200 Subject: [PATCH 12/16] sock: make all ep_sock_t fields private, remove _ep_sock_private_t --- src/sock.c | 132 +++++++++++++++++++++++++---------------------------- src/sock.h | 6 +-- 2 files changed, 62 insertions(+), 76 deletions(-) diff --git a/src/sock.c b/src/sock.c index b550d82..bb4c1a9 100644 --- a/src/sock.c +++ b/src/sock.c @@ -26,9 +26,10 @@ typedef enum _poll_status { _POLL_CANCELLED } _poll_status_t; -typedef struct _ep_sock_private { - ep_sock_t pub; +typedef struct ep_sock { _poll_req_t poll_req; + queue_node_t queue_node; + tree_node_t tree_node; poll_group_t* poll_group; SOCKET base_socket; epoll_data_t user_data; @@ -36,7 +37,7 @@ typedef struct _ep_sock_private { uint32_t pending_events; _poll_status_t poll_status; bool delete_pending; -} _ep_sock_private_t; +} ep_sock_t; static DWORD _epoll_events_to_afd_events(uint32_t epoll_events) { /* Always monitor for AFD_POLL_LOCAL_CLOSE, which is triggered when the @@ -144,30 +145,26 @@ static void _poll_req_complete(const _poll_req_t* poll_req, *socket_closed_out = socket_closed; } -static inline _ep_sock_private_t* _ep_sock_private(ep_sock_t* sock_info) { - return container_of(sock_info, _ep_sock_private_t, pub); -} - -static inline _ep_sock_private_t* _ep_sock_alloc(void) { - _ep_sock_private_t* sock_private = malloc(sizeof *sock_private); - if (sock_private == NULL) +static inline ep_sock_t* _ep_sock_alloc(void) { + ep_sock_t* sock_info = malloc(sizeof *sock_info); + if (sock_info == NULL) return_error(NULL, ERROR_NOT_ENOUGH_MEMORY); - return sock_private; + return sock_info; } -static inline void _ep_sock_free(_ep_sock_private_t* sock_private) { - free(sock_private); +static inline void _ep_sock_free(ep_sock_t* sock_info) { + free(sock_info); } -static int _ep_sock_cancel_poll(_ep_sock_private_t* sock_private) { - assert(sock_private->poll_status == _POLL_PENDING); +static int _ep_sock_cancel_poll(ep_sock_t* sock_info) { + assert(sock_info->poll_status == _POLL_PENDING); - if (_poll_req_cancel(&sock_private->poll_req, - poll_group_get_socket(sock_private->poll_group)) < 0) + if (_poll_req_cancel(&sock_info->poll_req, + poll_group_get_socket(sock_info->poll_group)) < 0) return -1; - sock_private->poll_status = _POLL_CANCELLED; - sock_private->pending_events = 0; + sock_info->poll_status = _POLL_CANCELLED; + sock_info->pending_events = 0; return 0; } @@ -175,7 +172,7 @@ static int _ep_sock_cancel_poll(_ep_sock_private_t* sock_private) { ep_sock_t* ep_sock_new(ep_port_t* port_info, SOCKET socket) { SOCKET base_socket; poll_group_t* poll_group; - _ep_sock_private_t* sock_private; + ep_sock_t* sock_info; if (socket == 0 || socket == INVALID_SOCKET) return_error(NULL, ERROR_INVALID_HANDLE); @@ -188,26 +185,25 @@ ep_sock_t* ep_sock_new(ep_port_t* port_info, SOCKET socket) { if (poll_group == NULL) return NULL; - sock_private = _ep_sock_alloc(); - if (sock_private == NULL) + sock_info = _ep_sock_alloc(); + if (sock_info == NULL) goto err1; - memset(sock_private, 0, sizeof *sock_private); + memset(sock_info, 0, sizeof *sock_info); - sock_private->base_socket = base_socket; - sock_private->poll_group = poll_group; + sock_info->base_socket = base_socket; + sock_info->poll_group = poll_group; - tree_node_init(&sock_private->pub.tree_node); - queue_node_init(&sock_private->pub.queue_node); + tree_node_init(&sock_info->tree_node); + queue_node_init(&sock_info->queue_node); - if (ep_port_register_socket_handle(port_info, &sock_private->pub, socket) < - 0) + if (ep_port_register_socket_handle(port_info, sock_info, socket) < 0) goto err2; - return &sock_private->pub; + return sock_info; err2: - _ep_sock_free(sock_private); + _ep_sock_free(sock_info); err1: poll_group_release(poll_group); @@ -217,26 +213,24 @@ err1: static void _ep_sock_delete(ep_port_t* port_info, ep_sock_t* sock_info, bool force) { - _ep_sock_private_t* sock_private = _ep_sock_private(sock_info); - - if (!sock_private->delete_pending) { - if (sock_private->poll_status == _POLL_PENDING) - _ep_sock_cancel_poll(sock_private); + if (!sock_info->delete_pending) { + if (sock_info->poll_status == _POLL_PENDING) + _ep_sock_cancel_poll(sock_info); ep_port_cancel_socket_update(port_info, sock_info); ep_port_unregister_socket_handle(port_info, sock_info); - sock_private->delete_pending = true; + sock_info->delete_pending = true; } /* If the poll request still needs to complete, the ep_sock object can't * be free()d yet. `ep_sock_feed_event()` or `ep_port_close()` will take care * of this later. */ - if (force || sock_private->poll_status == _POLL_IDLE) { + if (force || sock_info->poll_status == _POLL_IDLE) { /* Free the sock_info now. */ ep_port_remove_deleted_socket(port_info, sock_info); - poll_group_release(sock_private->poll_group); - _ep_sock_free(sock_private); + poll_group_release(sock_info->poll_group); + _ep_sock_free(sock_info); } else { /* Free the socket later. */ ep_port_add_deleted_socket(port_info, sock_info); @@ -254,53 +248,50 @@ void ep_sock_force_delete(ep_port_t* port_info, ep_sock_t* sock_info) { int ep_sock_set_event(ep_port_t* port_info, ep_sock_t* sock_info, const struct epoll_event* ev) { - _ep_sock_private_t* sock_private = _ep_sock_private(sock_info); - /* EPOLLERR and EPOLLHUP are always reported, even when not requested by the * caller. However they are disabled after a event has been reported for a * socket for which the EPOLLONESHOT flag as set. */ uint32_t events = ev->events | EPOLLERR | EPOLLHUP; - sock_private->user_events = events; - sock_private->user_data = ev->data; + sock_info->user_events = events; + sock_info->user_data = ev->data; - if ((events & _KNOWN_EPOLL_EVENTS & ~sock_private->pending_events) != 0) + if ((events & _KNOWN_EPOLL_EVENTS & ~sock_info->pending_events) != 0) ep_port_request_socket_update(port_info, sock_info); return 0; } int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) { - _ep_sock_private_t* sock_private = _ep_sock_private(sock_info); bool socket_closed = false; - assert(!sock_private->delete_pending); - if ((sock_private->poll_status == _POLL_PENDING) && - (sock_private->user_events & _KNOWN_EPOLL_EVENTS & - ~sock_private->pending_events) == 0) { + assert(!sock_info->delete_pending); + if ((sock_info->poll_status == _POLL_PENDING) && + (sock_info->user_events & _KNOWN_EPOLL_EVENTS & + ~sock_info->pending_events) == 0) { /* All the events the user is interested in are already being monitored * by the pending poll request. It might spuriously complete because of an * event that we're no longer interested in; if that happens we just * submit another poll request with the right event mask. */ - } else if (sock_private->poll_status == _POLL_PENDING) { + } else if (sock_info->poll_status == _POLL_PENDING) { /* A poll request is already pending, but it's not monitoring for all the * events that the user is interested in. Cancel the pending poll request; * when it completes it will be submitted again with the correct event * mask. */ - if (_ep_sock_cancel_poll(sock_private) < 0) + if (_ep_sock_cancel_poll(sock_info) < 0) return -1; - } else if (sock_private->poll_status == _POLL_CANCELLED) { + } else if (sock_info->poll_status == _POLL_CANCELLED) { /* The poll request has already been cancelled, we're still waiting for it * to return. For now, there's nothing that needs to be done. */ - } else if (sock_private->poll_status == _POLL_IDLE) { - SOCKET driver_socket = poll_group_get_socket(sock_private->poll_group); + } else if (sock_info->poll_status == _POLL_IDLE) { + SOCKET driver_socket = poll_group_get_socket(sock_info->poll_group); - if (_poll_req_submit(&sock_private->poll_req, - sock_private->user_events, - sock_private->base_socket, + if (_poll_req_submit(&sock_info->poll_req, + sock_info->user_events, + sock_info->base_socket, driver_socket) < 0) { if (GetLastError() == ERROR_INVALID_HANDLE) /* The socket is broken. It will be dropped from the epoll set. */ @@ -311,8 +302,8 @@ int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) { } else { /* The poll request was successfully submitted. */ - sock_private->poll_status = _POLL_PENDING; - sock_private->pending_events = sock_private->user_events; + sock_info->poll_status = _POLL_PENDING; + sock_info->pending_events = sock_info->user_events; } } else { /* Unreachable. */ @@ -331,36 +322,35 @@ int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) { int ep_sock_feed_event(ep_port_t* port_info, OVERLAPPED* overlapped, struct epoll_event* ev) { - _ep_sock_private_t* sock_private = - container_of(overlapped, _ep_sock_private_t, poll_req.overlapped); - ep_sock_t* sock_info = &sock_private->pub; + ep_sock_t* sock_info = + container_of(overlapped, ep_sock_t, poll_req.overlapped); uint32_t epoll_events; bool socket_closed; int ev_count = 0; - sock_private->poll_status = _POLL_IDLE; - sock_private->pending_events = 0; + sock_info->poll_status = _POLL_IDLE; + sock_info->pending_events = 0; - if (sock_private->delete_pending) { + if (sock_info->delete_pending) { /* Ignore completion for overlapped poll operation if the socket is pending * deletion; instead, delete the socket. */ ep_sock_delete(port_info, sock_info); return 0; } - _poll_req_complete(&sock_private->poll_req, &epoll_events, &socket_closed); + _poll_req_complete(&sock_info->poll_req, &epoll_events, &socket_closed); /* Filter events that the user didn't ask for. */ - epoll_events &= sock_private->user_events; + epoll_events &= sock_info->user_events; /* Clear the event mask if EPOLLONESHOT is set and there are any events * to report. */ - if (epoll_events != 0 && (sock_private->user_events & EPOLLONESHOT)) - sock_private->user_events = 0; + if (epoll_events != 0 && (sock_info->user_events & EPOLLONESHOT)) + sock_info->user_events = 0; /* Fill the ev structure if there are any events to report. */ if (epoll_events != 0) { - ev->data = sock_private->user_data; + ev->data = sock_info->user_data; ev->events = epoll_events; ev_count = 1; } diff --git a/src/sock.h b/src/sock.h index 27383df..9d3639e 100644 --- a/src/sock.h +++ b/src/sock.h @@ -11,11 +11,7 @@ #include "win.h" typedef struct ep_port ep_port_t; - -typedef struct ep_sock { - tree_node_t tree_node; - queue_node_t queue_node; -} ep_sock_t; +typedef struct ep_sock ep_sock_t; WEPOLL_INTERNAL ep_sock_t* ep_sock_new(ep_port_t* port_info, SOCKET socket); WEPOLL_INTERNAL void ep_sock_delete(ep_port_t* port_info, From b9b4cc7686e707abbff77d15aede49cb6d9eb028 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 4 May 2018 02:13:52 +0200 Subject: [PATCH 13/16] sock: integrate _poll_req_t fields into ep_sock_t, and merge functions --- src/sock.c | 309 ++++++++++++++++++++++------------------------------- 1 file changed, 128 insertions(+), 181 deletions(-) diff --git a/src/sock.c b/src/sock.c index bb4c1a9..0f1ab8b 100644 --- a/src/sock.c +++ b/src/sock.c @@ -15,11 +15,6 @@ (EPOLLIN | EPOLLPRI | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLRDNORM | \ EPOLLRDBAND | EPOLLWRNORM | EPOLLWRBAND | EPOLLRDHUP) -typedef struct _poll_req { - OVERLAPPED overlapped; - AFD_POLL_INFO poll_info; -} _poll_req_t; - typedef enum _poll_status { _POLL_IDLE = 0, _POLL_PENDING, @@ -27,7 +22,8 @@ typedef enum _poll_status { } _poll_status_t; typedef struct ep_sock { - _poll_req_t poll_req; + OVERLAPPED overlapped; + AFD_POLL_INFO poll_info; queue_node_t queue_node; tree_node_t tree_node; poll_group_t* poll_group; @@ -39,112 +35,6 @@ typedef struct ep_sock { bool delete_pending; } ep_sock_t; -static DWORD _epoll_events_to_afd_events(uint32_t epoll_events) { - /* Always monitor for AFD_POLL_LOCAL_CLOSE, which is triggered when the - * socket is closed with closesocket() or CloseHandle(). */ - DWORD afd_events = AFD_POLL_LOCAL_CLOSE; - - if (epoll_events & (EPOLLIN | EPOLLRDNORM)) - afd_events |= AFD_POLL_RECEIVE | AFD_POLL_ACCEPT; - if (epoll_events & (EPOLLPRI | EPOLLRDBAND)) - afd_events |= AFD_POLL_RECEIVE_EXPEDITED; - if (epoll_events & (EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND)) - afd_events |= AFD_POLL_SEND | AFD_POLL_CONNECT; - if (epoll_events & (EPOLLIN | EPOLLRDNORM | EPOLLRDHUP)) - afd_events |= AFD_POLL_DISCONNECT; - if (epoll_events & EPOLLHUP) - afd_events |= AFD_POLL_ABORT; - if (epoll_events & EPOLLERR) - afd_events |= AFD_POLL_CONNECT_FAIL; - - return afd_events; -} - -static uint32_t _afd_events_to_epoll_events(DWORD afd_events) { - uint32_t epoll_events = 0; - - if (afd_events & (AFD_POLL_RECEIVE | AFD_POLL_ACCEPT)) - epoll_events |= EPOLLIN | EPOLLRDNORM; - if (afd_events & AFD_POLL_RECEIVE_EXPEDITED) - epoll_events |= EPOLLPRI | EPOLLRDBAND; - if (afd_events & (AFD_POLL_SEND | AFD_POLL_CONNECT)) - epoll_events |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; - if (afd_events & AFD_POLL_DISCONNECT) - epoll_events |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP; - if (afd_events & AFD_POLL_ABORT) - epoll_events |= EPOLLHUP; - if (afd_events & AFD_POLL_CONNECT_FAIL) - epoll_events |= EPOLLERR; - - return epoll_events; -} - -static int _poll_req_submit(_poll_req_t* poll_req, - uint32_t epoll_events, - SOCKET socket, - SOCKET driver_socket) { - int r; - - memset(&poll_req->overlapped, 0, sizeof poll_req->overlapped); - - poll_req->poll_info.Exclusive = FALSE; - poll_req->poll_info.NumberOfHandles = 1; - poll_req->poll_info.Timeout.QuadPart = INT64_MAX; - poll_req->poll_info.Handles[0].Handle = (HANDLE) socket; - poll_req->poll_info.Handles[0].Status = 0; - poll_req->poll_info.Handles[0].Events = - _epoll_events_to_afd_events(epoll_events); - - r = afd_poll(driver_socket, &poll_req->poll_info, &poll_req->overlapped); - if (r != 0 && GetLastError() != ERROR_IO_PENDING) - return_error(-1); - - return 0; -} - -static int _poll_req_cancel(_poll_req_t* poll_req, SOCKET driver_socket) { - OVERLAPPED* overlapped = &poll_req->overlapped; - - if (!CancelIoEx((HANDLE) driver_socket, overlapped)) { - DWORD error = GetLastError(); - if (error == ERROR_NOT_FOUND) - return 0; /* Already completed or canceled. */ - else - return_error(-1); - } - - return 0; -} - -static void _poll_req_complete(const _poll_req_t* poll_req, - uint32_t* epoll_events_out, - bool* socket_closed_out) { - const OVERLAPPED* overlapped = &poll_req->overlapped; - - uint32_t epoll_events = 0; - bool socket_closed = false; - - if ((NTSTATUS) overlapped->Internal == STATUS_CANCELLED) { - /* The poll request was cancelled by CancelIoEx. */ - } else if (!NT_SUCCESS(overlapped->Internal)) { - /* The overlapped request itself failed in an unexpected way. */ - epoll_events = EPOLLERR; - } else if (poll_req->poll_info.NumberOfHandles < 1) { - /* This overlapped request succeeded but didn't report any events. */ - } else { - /* Events related to our socket were reported. */ - DWORD afd_events = poll_req->poll_info.Handles[0].Events; - - if (afd_events & AFD_POLL_LOCAL_CLOSE) - socket_closed = true; /* Socket closed locally be silently dropped. */ - else - epoll_events = _afd_events_to_epoll_events(afd_events); - } - - *epoll_events_out = epoll_events; - *socket_closed_out = socket_closed; -} - static inline ep_sock_t* _ep_sock_alloc(void) { ep_sock_t* sock_info = malloc(sizeof *sock_info); if (sock_info == NULL) @@ -157,15 +47,17 @@ static inline void _ep_sock_free(ep_sock_t* sock_info) { } static int _ep_sock_cancel_poll(ep_sock_t* sock_info) { + HANDLE driver_handle = (HANDLE) poll_group_get_socket(sock_info->poll_group); assert(sock_info->poll_status == _POLL_PENDING); - if (_poll_req_cancel(&sock_info->poll_req, - poll_group_get_socket(sock_info->poll_group)) < 0) - return -1; + /* CancelIoEx() may fail with ERROR_NOT_FOUND if the overlapped operation has + * already completed. This is not a problem and we proceed normally. */ + if (!CancelIoEx(driver_handle, &sock_info->overlapped) && + GetLastError() != ERROR_NOT_FOUND) + return_error(-1); sock_info->poll_status = _POLL_CANCELLED; sock_info->pending_events = 0; - return 0; } @@ -210,9 +102,9 @@ err1: return NULL; } -static void _ep_sock_delete(ep_port_t* port_info, - ep_sock_t* sock_info, - bool force) { +static int _ep_sock_delete(ep_port_t* port_info, + ep_sock_t* sock_info, + bool force) { if (!sock_info->delete_pending) { if (sock_info->poll_status == _POLL_PENDING) _ep_sock_cancel_poll(sock_info); @@ -235,6 +127,8 @@ static void _ep_sock_delete(ep_port_t* port_info, /* Free the socket later. */ ep_port_add_deleted_socket(port_info, sock_info); } + + return 0; } void ep_sock_delete(ep_port_t* port_info, ep_sock_t* sock_info) { @@ -262,108 +156,161 @@ int ep_sock_set_event(ep_port_t* port_info, return 0; } -int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) { - bool socket_closed = false; +static inline ULONG _epoll_events_to_afd_events(uint32_t epoll_events) { + /* Always monitor for AFD_POLL_LOCAL_CLOSE, which is triggered when the + * socket is closed with closesocket() or CloseHandle(). */ + DWORD afd_events = AFD_POLL_LOCAL_CLOSE; + if (epoll_events & (EPOLLIN | EPOLLRDNORM)) + afd_events |= AFD_POLL_RECEIVE | AFD_POLL_ACCEPT; + if (epoll_events & (EPOLLPRI | EPOLLRDBAND)) + afd_events |= AFD_POLL_RECEIVE_EXPEDITED; + if (epoll_events & (EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND)) + afd_events |= AFD_POLL_SEND | AFD_POLL_CONNECT; + if (epoll_events & (EPOLLIN | EPOLLRDNORM | EPOLLRDHUP)) + afd_events |= AFD_POLL_DISCONNECT; + if (epoll_events & EPOLLHUP) + afd_events |= AFD_POLL_ABORT; + if (epoll_events & EPOLLERR) + afd_events |= AFD_POLL_CONNECT_FAIL; + + return afd_events; +} + +static inline uint32_t _afd_events_to_epoll_events(ULONG afd_events) { + uint32_t epoll_events = 0; + + if (afd_events & (AFD_POLL_RECEIVE | AFD_POLL_ACCEPT)) + epoll_events |= EPOLLIN | EPOLLRDNORM; + if (afd_events & AFD_POLL_RECEIVE_EXPEDITED) + epoll_events |= EPOLLPRI | EPOLLRDBAND; + if (afd_events & (AFD_POLL_SEND | AFD_POLL_CONNECT)) + epoll_events |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; + if (afd_events & AFD_POLL_DISCONNECT) + epoll_events |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP; + if (afd_events & AFD_POLL_ABORT) + epoll_events |= EPOLLHUP; + if (afd_events & AFD_POLL_CONNECT_FAIL) + epoll_events |= EPOLLERR; + + return epoll_events; +} + +int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) { assert(!sock_info->delete_pending); + if ((sock_info->poll_status == _POLL_PENDING) && (sock_info->user_events & _KNOWN_EPOLL_EVENTS & ~sock_info->pending_events) == 0) { - /* All the events the user is interested in are already being monitored - * by the pending poll request. It might spuriously complete because of an - * event that we're no longer interested in; if that happens we just - * submit another poll request with the right event mask. */ + /* All the events the user is interested in are already being monitored by + * the pending poll operation. It might spuriously complete because of an + * event that we're no longer interested in; when that happens we'll submit + * a new poll operation with the updated event mask. */ } else if (sock_info->poll_status == _POLL_PENDING) { - /* A poll request is already pending, but it's not monitoring for all the - * events that the user is interested in. Cancel the pending poll request; - * when it completes it will be submitted again with the correct event - * mask. */ + /* A poll operation is already pending, but it's not monitoring for all the + * events that the user is interested in. Therefore, cancel the pending + * poll operation; when we receive it's completion package, a new poll + * operation will be submitted with the correct event mask. */ if (_ep_sock_cancel_poll(sock_info) < 0) return -1; } else if (sock_info->poll_status == _POLL_CANCELLED) { - /* The poll request has already been cancelled, we're still waiting for it - * to return. For now, there's nothing that needs to be done. */ + /* The poll operation has already been cancelled, we're still waiting for + * it to return. For now, there's nothing that needs to be done. */ } else if (sock_info->poll_status == _POLL_IDLE) { - SOCKET driver_socket = poll_group_get_socket(sock_info->poll_group); + /* No poll operation is pending; start one. */ + sock_info->poll_info.Exclusive = FALSE; + sock_info->poll_info.NumberOfHandles = 1; + sock_info->poll_info.Timeout.QuadPart = INT64_MAX; + sock_info->poll_info.Handles[0].Handle = (HANDLE) sock_info->base_socket; + sock_info->poll_info.Handles[0].Status = 0; + sock_info->poll_info.Handles[0].Events = + _epoll_events_to_afd_events(sock_info->user_events); - if (_poll_req_submit(&sock_info->poll_req, - sock_info->user_events, - sock_info->base_socket, - driver_socket) < 0) { - if (GetLastError() == ERROR_INVALID_HANDLE) - /* The socket is broken. It will be dropped from the epoll set. */ - socket_closed = true; - else - /* Another error occurred, which is propagated to the caller. */ - return -1; + memset(&sock_info->overlapped, 0, sizeof sock_info->overlapped); - } else { - /* The poll request was successfully submitted. */ - sock_info->poll_status = _POLL_PENDING; - sock_info->pending_events = sock_info->user_events; + if (afd_poll(poll_group_get_socket(sock_info->poll_group), + &sock_info->poll_info, + &sock_info->overlapped) < 0) { + switch (GetLastError()) { + case ERROR_IO_PENDING: + /* Overlapped poll operation in progress; this is expected. */ + break; + case ERROR_INVALID_HANDLE: + /* Socket closed; it'll be dropped from the epoll set. */ + return _ep_sock_delete(port_info, sock_info, false); + default: + /* Other errors are propagated to the caller. */ + return_error(-1); + } } + + /* The poll request was successfully submitted. */ + sock_info->poll_status = _POLL_PENDING; + sock_info->pending_events = sock_info->user_events; + } else { /* Unreachable. */ assert(false); } ep_port_cancel_socket_update(port_info, sock_info); - - /* If we saw an ERROR_INVALID_HANDLE error, drop the socket. */ - if (socket_closed) - ep_sock_delete(port_info, sock_info); - return 0; } int ep_sock_feed_event(ep_port_t* port_info, OVERLAPPED* overlapped, struct epoll_event* ev) { - ep_sock_t* sock_info = - container_of(overlapped, ep_sock_t, poll_req.overlapped); - uint32_t epoll_events; - bool socket_closed; - int ev_count = 0; + ep_sock_t* sock_info = container_of(overlapped, ep_sock_t, overlapped); + AFD_POLL_INFO* poll_info = &sock_info->poll_info; + uint32_t epoll_events = 0; sock_info->poll_status = _POLL_IDLE; sock_info->pending_events = 0; if (sock_info->delete_pending) { - /* Ignore completion for overlapped poll operation if the socket is pending - * deletion; instead, delete the socket. */ - ep_sock_delete(port_info, sock_info); - return 0; + /* Socket has been deleted earlier and can now be freed. */ + return _ep_sock_delete(port_info, sock_info, false); + + } else if ((NTSTATUS) overlapped->Internal == STATUS_CANCELLED) { + /* The poll request was cancelled by CancelIoEx. */ + + } else if (!NT_SUCCESS(overlapped->Internal)) { + /* The overlapped request itself failed in an unexpected way. */ + epoll_events = EPOLLERR; + + } else if (poll_info->NumberOfHandles < 1) { + /* This poll operation succeeded but didn't report any socket events. */ + + } else if (poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) { + /* The poll operation reported that the socket was closed. */ + return _ep_sock_delete(port_info, sock_info, false); + + } else { + /* Events related to our socket were reported. */ + epoll_events = _afd_events_to_epoll_events(poll_info->Handles[0].Events); } - _poll_req_complete(&sock_info->poll_req, &epoll_events, &socket_closed); + /* Requeue the socket so a new poll request will be submitted. */ + ep_port_request_socket_update(port_info, sock_info); - /* Filter events that the user didn't ask for. */ + /* Filter out events that the user didn't ask for. */ epoll_events &= sock_info->user_events; - /* Clear the event mask if EPOLLONESHOT is set and there are any events - * to report. */ - if (epoll_events != 0 && (sock_info->user_events & EPOLLONESHOT)) + /* Return if there are no epoll events to report. */ + if (epoll_events == 0) + return 0; + + /* If the the socket has the EPOLLONESHOT flag set, unmonitor all events, + * even EPOLLERR and EPOLLHUP. But always keep looking for closed sockets. */ + if (sock_info->user_events & EPOLLONESHOT) sock_info->user_events = 0; - /* Fill the ev structure if there are any events to report. */ - if (epoll_events != 0) { - ev->data = sock_info->user_data; - ev->events = epoll_events; - ev_count = 1; - } - - if (socket_closed) - /* Drop the socket from the epoll set. */ - ep_sock_delete(port_info, sock_info); - else - /* Put the socket back onto the attention list so a new poll request will - * be submitted. */ - ep_port_request_socket_update(port_info, sock_info); - - return ev_count; + ev->data = sock_info->user_data; + ev->events = epoll_events; + return 1; } queue_node_t* ep_sock_to_queue_node(ep_sock_t* sock_info) { From 6f6c32628ac58b8df607882d332ad18ad8e10605 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 4 May 2018 02:42:02 +0200 Subject: [PATCH 14/16] thread-safe-tree: don't use safe_container_of() --- src/thread-safe-tree.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/thread-safe-tree.c b/src/thread-safe-tree.c index ce01e01..12ad13e 100644 --- a/src/thread-safe-tree.c +++ b/src/thread-safe-tree.c @@ -26,17 +26,23 @@ int ts_tree_add(ts_tree_t* ts_tree, ts_tree_node_t* node, uintptr_t key) { return r; } +static inline ts_tree_node_t* _ts_tree_find_node(ts_tree_t* ts_tree, + uintptr_t key) { + tree_node_t* tree_node = tree_find(&ts_tree->tree, key); + if (tree_node == NULL) + return NULL; + + return container_of(tree_node, ts_tree_node_t, tree_node); +} + ts_tree_node_t* ts_tree_del_and_ref(ts_tree_t* ts_tree, uintptr_t key) { - tree_node_t* tree_node; ts_tree_node_t* ts_tree_node; AcquireSRWLockExclusive(&ts_tree->lock); - tree_node = tree_find(&ts_tree->tree, key); - ts_tree_node = safe_container_of(tree_node, ts_tree_node_t, tree_node); - + ts_tree_node = _ts_tree_find_node(ts_tree, key); if (ts_tree_node != NULL) { - tree_del(&ts_tree->tree, tree_node); + tree_del(&ts_tree->tree, &ts_tree_node->tree_node); reflock_ref(&ts_tree_node->reflock); } @@ -46,13 +52,11 @@ ts_tree_node_t* ts_tree_del_and_ref(ts_tree_t* ts_tree, uintptr_t key) { } ts_tree_node_t* ts_tree_find_and_ref(ts_tree_t* ts_tree, uintptr_t key) { - tree_node_t* tree_node; ts_tree_node_t* ts_tree_node; AcquireSRWLockShared(&ts_tree->lock); - tree_node = tree_find(&ts_tree->tree, key); - ts_tree_node = safe_container_of(tree_node, ts_tree_node_t, tree_node); + ts_tree_node = _ts_tree_find_node(ts_tree, key); if (ts_tree_node != NULL) reflock_ref(&ts_tree_node->reflock); From 2e4627ba4aa3e635069dc651ce1e9e2296bbfe5b Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 4 May 2018 02:45:19 +0200 Subject: [PATCH 15/16] util: remove safe_container_of() macro --- src/util.c | 11 ----------- src/util.h | 5 ----- 2 files changed, 16 deletions(-) delete mode 100644 src/util.c diff --git a/src/util.c b/src/util.c deleted file mode 100644 index b68130d..0000000 --- a/src/util.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include - -#include "util.h" - -void* util_safe_container_of_helper(void* ptr, size_t offset) { - if (ptr == NULL) - return NULL; - else - return (char*) ptr - offset; -} diff --git a/src/util.h b/src/util.h index 7cb45d6..8c59691 100644 --- a/src/util.h +++ b/src/util.h @@ -15,9 +15,6 @@ typedef intptr_t ssize_t; #define container_of(ptr, type, member) \ ((type*) ((char*) (ptr) -offsetof(type, member))) -#define safe_container_of(ptr, type, member) \ - ((type*) util_safe_container_of_helper((ptr), offsetof(type, member))) - #define unused_var(v) ((void) (v)) #if defined(__clang__) || defined(__GNUC__) @@ -37,6 +34,4 @@ typedef intptr_t ssize_t; (__unused__)) int __static_assert_##__LINE__[(condition) ? 1 : -1]; #endif -WEPOLL_INTERNAL void* util_safe_container_of_helper(void* ptr, size_t offset); - #endif /* WEPOLL_UTIL_H_ */ From 33a6ee6889599b44fc64694b3b3a573ed9a2f0df Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 4 May 2018 02:44:25 +0200 Subject: [PATCH 16/16] util: fix missing include --- src/util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util.h b/src/util.h index 8c59691..98746ba 100644 --- a/src/util.h +++ b/src/util.h @@ -1,6 +1,7 @@ #ifndef WEPOLL_UTIL_H_ #define WEPOLL_UTIL_H_ +#include #include #include "internal.h"