Skip to content

Commit

Permalink
Improving Windows socket selector
Browse files Browse the repository at this point in the history
  • Loading branch information
ktakashi committed Jan 21, 2025
1 parent 7858653 commit 70276d8
Showing 1 changed file with 91 additions and 0 deletions.
91 changes: 91 additions & 0 deletions ext/socket/selector-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ void Sg_CloseSocketSelector(SgSocketSelector *selector)
}
}

#if 0
static SgObject select_socket(SOCKET fd, SgObject sockets)
{
SgObject cp;
Expand Down Expand Up @@ -266,6 +267,96 @@ static SgObject selector_wait(SgSocketSelector *selector, int n,

return win_selector_wait(ctx, n, selector, sockets, sp);
}
#endif

static SgObject win_selector_wait(win_context_t *ctx, int n,
SgSocketSelector *selector,
SgObject sockets,
struct timespec *sp)
{
const int waiting_flags = FD_READ | FD_OOB;
int r, err = FALSE;
DWORD millis = INFINITE;
SgObject ret = SG_NIL;
WSAEVENT eArray[2] = { NULL, };

eArray[1] = ctx->event;
eArray[0] = WSACreateEvent();
#define SET_EVENT(sockets, flags) \
do { \
SgObject cp; \
int i = 0; \
SG_FOR_EACH(cp, sockets) { \
SgObject s = SG_CAAR(cp); \
/* avoid unwanted sockets */ \
if (i == n) break; \
if (WSAEventSelect(SG_SOCKET(s)->socket, eArray[0], flags) != 0) { \
err = TRUE; \
goto cleanup; \
} \
i++; \
} \
} while(0)
SET_EVENT(sockets, waiting_flags);

if (sp) {
millis = sp->tv_sec * 1000;
millis += sp->tv_nsec / 1000000;
}

r = WSAWaitForMultipleEvents(2, eArray, FALSE, millis, FALSE);
/* most likely closed selector */
if (r == WSA_WAIT_FAILED) {
err = TRUE;
goto cleanup;
}
/* reset interrupting event as soon as possible */
WSAResetEvent(ctx->event);
if (r == WSA_WAIT_EVENT_0) {
SgObject cp;
WSANETWORKEVENTS networkEvents;
SG_FOR_EACH(cp, sockets) {
SgSocket *so = SG_SOCKET(SG_CAAR(cp));
if (WSAEnumNetworkEvents(so->socket, eArray[0], &networkEvents) == 0) {
if ((networkEvents.lNetworkEvents & waiting_flags) != 0) {
ret = Sg_Cons(so, ret);
}
}
}
}

#undef SET_EVENT

cleanup:
if (eArray[0]) {
int i = 0;
SgObject cp;
SG_FOR_EACH(cp, sockets) {
SgObject s = SG_CAAR(cp);
WSAEventSelect(SG_SOCKET(s)->socket, eArray[0], 0);
}
WSACloseEvent(eArray[1]);
}

if (err) {
int e = WSAGetLastError();
selector->waiting = FALSE;
if (e == WSA_INVALID_HANDLE) {
Sg_Error(UC("Socket selector is closed during waiting: %A"), selector);
}
Sg_Error(UC("Failed to wait selector: [%d] %S"), e,
Sg_GetLastErrorMessageWithErrorCode(e));
}
return ret;
}

static SgObject selector_wait(SgSocketSelector *selector, int n,
struct timespec *sp)
{
win_context_t *ctx = (win_context_t *)selector->context;
SgObject sockets = Sg_Reverse(selector->sockets);
return win_selector_wait(ctx, n, selector, sockets, sp);
}


SgObject Sg_SocketSelectorInterrupt(SgSocketSelector *selector)
Expand Down

0 comments on commit 70276d8

Please sign in to comment.