diff --git a/src/epoll-socket.c b/src/epoll-socket.c index 5a8359a..9a18746 100644 --- a/src/epoll-socket.c +++ b/src/epoll-socket.c @@ -8,7 +8,6 @@ #include "epoll.h" #include "error.h" #include "poll-group.h" -#include "poll-request.h" #include "port.h" #ifndef SIO_BASE_HANDLE @@ -17,13 +16,18 @@ #define _EP_EVENT_MASK 0xffff +typedef struct _poll_req { + OVERLAPPED overlapped; + AFD_POLL_INFO poll_info; +} _poll_req_t; + enum _poll_status { _POLL_IDLE = 0, _POLL_PENDING, _POLL_CANCELLED }; typedef struct _ep_sock_private { ep_sock_t pub; - SOCKET afd_socket; + _poll_req_t poll_req; poll_group_t* poll_group; - poll_req_t* poll_req; + SOCKET afd_socket; epoll_data_t user_data; uint32_t user_events; uint32_t pending_events; @@ -31,6 +35,111 @@ typedef struct _ep_sock_private { unsigned deleted : 1; } _ep_sock_private_t; +static DWORD _epoll_events_to_afd_events(uint32_t epoll_events) { + DWORD afd_events; + + /* These events should always be monitored. */ + assert(epoll_events & EPOLLERR); + assert(epoll_events & EPOLLHUP); + afd_events = AFD_POLL_ABORT | AFD_POLL_CONNECT_FAIL | 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; + + 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) + epoll_events |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; + if ((afd_events & AFD_POLL_DISCONNECT) && !(afd_events & AFD_POLL_ABORT)) + epoll_events |= EPOLLIN | EPOLLRDHUP; + if (afd_events & AFD_POLL_ABORT) + epoll_events |= EPOLLHUP; + if (afd_events & AFD_POLL_CONNECT) + epoll_events |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; + 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_private_t* _ep_sock_private(ep_sock_t* sock_info) { return container_of(sock_info, _ep_sock_private_t, pub); } @@ -44,7 +153,6 @@ static inline _ep_sock_private_t* _ep_sock_alloc(void) { static inline void _ep_sock_free(_ep_sock_private_t* sock_private) { assert(sock_private->poll_status == _POLL_IDLE); - poll_req_delete(sock_private->poll_req); free(sock_private); } @@ -117,10 +225,6 @@ ep_sock_t* ep_sock_new(ep_port_t* port_info, SOCKET socket) { return NULL; } - poll_req_t* poll_req = poll_req_new(&sock_private->pub); - assert(poll_req != NULL); - sock_private->poll_req = poll_req; - return &sock_private->pub; } @@ -162,6 +266,12 @@ ep_sock_t* ep_sock_find(tree_t* tree, SOCKET socket) { return container_of(tree_node, ep_sock_t, tree_node); } +ep_sock_t* ep_sock_from_overlapped(OVERLAPPED* overlapped) { + _ep_sock_private_t* sock_private = + container_of(overlapped, _ep_sock_private_t, poll_req.overlapped); + return &sock_private->pub; +} + int ep_sock_set_event(ep_port_t* port_info, ep_sock_t* sock_info, const struct epoll_event* ev) { @@ -199,7 +309,7 @@ int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) { * 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 (poll_req_cancel(sock_private->poll_req, driver_socket) < 0) + if (_poll_req_cancel(&sock_private->poll_req, driver_socket) < 0) return -1; sock_private->poll_status = _POLL_CANCELLED; sock_private->pending_events = 0; @@ -209,10 +319,10 @@ int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) { * to return. For now, there's nothing that needs to be done. */ } else if (sock_private->poll_status == _POLL_IDLE) { - if (poll_req_submit(sock_private->poll_req, - sock_private->user_events, - sock_private->afd_socket, - driver_socket) < 0) { + if (_poll_req_submit(&sock_private->poll_req, + sock_private->user_events, + sock_private->afd_socket, + driver_socket) < 0) { if (GetLastError() == ERROR_INVALID_HANDLE) /* The socket is broken. It will be dropped from the epoll set. */ broken = true; @@ -240,9 +350,8 @@ int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) { } int ep_sock_feed_event(ep_port_t* port_info, - poll_req_t* poll_req, + ep_sock_t* sock_info, struct epoll_event* ev) { - ep_sock_t* sock_info = poll_req_get_sock_data(poll_req); _ep_sock_private_t* sock_private = _ep_sock_private(sock_info); uint32_t epoll_events; @@ -259,7 +368,7 @@ int ep_sock_feed_event(ep_port_t* port_info, return 0; } - poll_req_complete(poll_req, &epoll_events, &drop_socket); + _poll_req_complete(&sock_private->poll_req, &epoll_events, &drop_socket); /* Filter events that the user didn't ask for. */ epoll_events &= sock_private->user_events; diff --git a/src/epoll-socket.h b/src/epoll-socket.h index 864fed1..4731615 100644 --- a/src/epoll-socket.h +++ b/src/epoll-socket.h @@ -25,6 +25,7 @@ EPOLL_INTERNAL void ep_sock_force_delete(ep_port_t* port_info, ep_sock_t* sock_info); EPOLL_INTERNAL ep_sock_t* ep_sock_find(tree_t* tree, SOCKET socket); +EPOLL_INTERNAL ep_sock_t* ep_sock_from_overlapped(OVERLAPPED* overlapped); EPOLL_INTERNAL int ep_sock_set_event(ep_port_t* port_info, ep_sock_t* sock_info, @@ -32,7 +33,7 @@ EPOLL_INTERNAL int ep_sock_set_event(ep_port_t* port_info, EPOLL_INTERNAL int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info); EPOLL_INTERNAL int ep_sock_feed_event(ep_port_t* port_info, - poll_req_t* poll_req, + ep_sock_t* sock_info, struct epoll_event* ev); #endif /* EPOLL_SOCK_DATA_H_ */ diff --git a/src/epoll.c b/src/epoll.c index 29c324b..9ba027b 100644 --- a/src/epoll.c +++ b/src/epoll.c @@ -11,7 +11,6 @@ #include "init.h" #include "nt.h" #include "poll-group.h" -#include "poll-request.h" #include "port.h" #include "queue.h" #include "rb.h" @@ -114,10 +113,10 @@ static size_t _ep_port_feed_events(ep_port_t* port_info, for (size_t i = 0; i < completion_count; i++) { OVERLAPPED* overlapped = completion_list[i].lpOverlapped; - poll_req_t* poll_req = overlapped_to_poll_req(overlapped); + ep_sock_t* sock_info = ep_sock_from_overlapped(overlapped); struct epoll_event* ev = &event_list[event_count]; - event_count += ep_sock_feed_event(port_info, poll_req, ev); + event_count += ep_sock_feed_event(port_info, sock_info, ev); } return event_count; diff --git a/src/poll-request.c b/src/poll-request.c deleted file mode 100644 index 4359048..0000000 --- a/src/poll-request.c +++ /dev/null @@ -1,160 +0,0 @@ -#include -#include -#include -#include - -#include "afd.h" -#include "epoll-socket.h" -#include "epoll.h" -#include "error.h" -#include "ntstatus.h" -#include "poll-request.h" -#include "util.h" -#include "win.h" - -typedef struct poll_req { - OVERLAPPED overlapped; - AFD_POLL_INFO poll_info; - ep_sock_t* sock_info; -} poll_req_t; - -static inline poll_req_t* _poll_req_alloc(void) { - poll_req_t* poll_req = malloc(sizeof *poll_req); - if (poll_req == NULL) - return_error(NULL, ERROR_NOT_ENOUGH_MEMORY); - return poll_req; -} - -static inline poll_req_t* _poll_req_free(poll_req_t* poll_req) { - free(poll_req); - return NULL; -} - -poll_req_t* poll_req_new(ep_sock_t* sock_info) { - poll_req_t* poll_req = _poll_req_alloc(); - if (poll_req == NULL) - return NULL; - - memset(poll_req, 0, sizeof *poll_req); - poll_req->sock_info = sock_info; - - return poll_req; -} - -void poll_req_delete(poll_req_t* poll_req) { - assert(poll_req != NULL); - _poll_req_free(poll_req); -} - -poll_req_t* overlapped_to_poll_req(OVERLAPPED* overlapped) { - return container_of(overlapped, poll_req_t, overlapped); -} - -ep_sock_t* poll_req_get_sock_data(const poll_req_t* poll_req) { - return poll_req->sock_info; -} - -static DWORD _epoll_events_to_afd_events(uint32_t epoll_events) { - DWORD afd_events; - - /* These events should always be monitored. */ - assert(epoll_events & EPOLLERR); - assert(epoll_events & EPOLLHUP); - afd_events = AFD_POLL_ABORT | AFD_POLL_CONNECT_FAIL | 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; - - 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) - epoll_events |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; - if ((afd_events & AFD_POLL_DISCONNECT) && !(afd_events & AFD_POLL_ABORT)) - epoll_events |= EPOLLIN | EPOLLRDHUP; - if (afd_events & AFD_POLL_ABORT) - epoll_events |= EPOLLHUP; - if (afd_events & AFD_POLL_CONNECT) - epoll_events |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; - if (afd_events & AFD_POLL_CONNECT_FAIL) - epoll_events |= EPOLLERR; - - return epoll_events; -} - -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; -} - -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; -} - -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; -} diff --git a/src/poll-request.h b/src/poll-request.h deleted file mode 100644 index 4387438..0000000 --- a/src/poll-request.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EPOLL_POLL_REQUEST_H_ -#define EPOLL_POLL_REQUEST_H_ - -#include -#include - -#include "afd.h" -#include "internal.h" -#include "win.h" - -typedef struct ep_port ep_port_t; -typedef struct ep_sock ep_sock_t; -typedef struct poll_req poll_req_t; - -EPOLL_INTERNAL poll_req_t* poll_req_new(ep_sock_t* sock_info); - -EPOLL_INTERNAL void poll_req_delete(poll_req_t* poll_req); - -EPOLL_INTERNAL poll_req_t* overlapped_to_poll_req(OVERLAPPED* overlapped); - -EPOLL_INTERNAL ep_sock_t* poll_req_get_sock_data(const poll_req_t* poll_req); - -EPOLL_INTERNAL int poll_req_submit(poll_req_t* poll_req, - uint32_t epoll_events, - SOCKET socket, - SOCKET driver_socket); - -EPOLL_INTERNAL int poll_req_cancel(poll_req_t* poll_req, SOCKET group_socket); -EPOLL_INTERNAL void poll_req_complete(const poll_req_t* poll_req, - uint32_t* epoll_events_out, - bool* socket_closed_out); - -#endif /* EPOLL_POLL_REQUEST_H_ */