Skip to content

Commit a49f1b4

Browse files
committed
Using WSAWaitForMultipleEvents and WSAEnumNetworkEvents instead of WSAPoll
1 parent 328e2d4 commit a49f1b4

File tree

2 files changed

+54
-46
lines changed

2 files changed

+54
-46
lines changed

ext/socket/sagittarius-socket.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ SG_CLASS_DECL(Sg_SocketPortClass);
177177
WSAEventSelect(s, (hEvent), flags); \
178178
ioctlsocket(s, FIONBIO, &val); \
179179
} while (0)
180-
#define SG_ABORTABLE_SOCKET_OP(ret, socket, flags, operation) \
180+
# define SG_ABORTABLE_SOCKET_OP(ret, socket, flags, operation) \
181181
do { \
182182
if (SG_SOCKET(socket)->nonblocking) { \
183183
(ret) = operation; \
@@ -199,8 +199,8 @@ SG_CLASS_DECL(Sg_SocketPortClass);
199199
} \
200200
} while (0)
201201
#else
202-
#define SG_SET_SOCKET_EVENT(sock, hEvent, flags, revertp) /* dummy */
203-
#define SG_ABORTABLE_SOCKET_OP(ret, socket, flags, operation) \
202+
# define SG_SET_SOCKET_EVENT(sock, hEvent, flags, revertp) /* dummy */
203+
# define SG_ABORTABLE_SOCKET_OP(ret, socket, flags, operation) \
204204
(ret) = operation;
205205
#endif
206206

ext/socket/selector-win.c

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636

3737
typedef struct win_context_rec
3838
{
39-
HANDLE event;
40-
HANDLE thread; /* waiting thread */
39+
WSAEVENT event;
40+
HANDLE thread; /* waiting thread */
4141
} win_context_t;
4242

4343

@@ -60,7 +60,7 @@ SgObject Sg_MakeSocketSelector()
6060

6161
SG_SET_CLASS(selector, SG_CLASS_SOCKET_SELECTOR);
6262

63-
ctx->event = CreateEvent(NULL, TRUE, FALSE, NULL);
63+
ctx->event = WSACreateEvent();
6464
if (ctx->event == NULL) goto err;
6565

6666
ctx->thread = NULL;
@@ -78,7 +78,7 @@ SgObject Sg_MakeSocketSelector()
7878
void Sg_CloseSocketSelector(SgSocketSelector *selector)
7979
{
8080
win_context_t *ctx = (win_context_t *)selector->context;
81-
CloseHandle(ctx->event);
81+
WSACloseEvent(ctx->event);
8282
Sg_UnregisterFinalizer(selector);
8383
}
8484

@@ -107,67 +107,75 @@ static SgObject select_socket(SOCKET fd, SgObject sockets)
107107
SgObject Sg_SocketSelectorWait(SgSocketSelector *selector, SgObject timeout)
108108
{
109109
win_context_t *ctx = (win_context_t *)selector->context;
110-
int n = selector_sockets(selector), millis = INFINITE, r;
111-
HANDLE hEvents[2];
110+
int n = selector_sockets(selector), r, err = FALSE;
111+
const int waiting_flags = FD_READ | FD_OOB;
112112
struct timespec spec, *sp;
113+
DWORD millis = INFINITE;
113114
SgObject ret = SG_NIL;
115+
SOCKET sArray[WSA_MAXIMUM_WAIT_EVENTS];
116+
WSAEVENT eArray[WSA_MAXIMUM_WAIT_EVENTS] = { NULL, };
114117

115118
if (ctx->thread != NULL) {
116119
Sg_Error(UC("There's a thread already waiting for %A"), selector);
117120
}
118121
if (n == 0) return ret;
122+
if (n-1 > WSA_MAXIMUM_WAIT_EVENTS) {
123+
Sg_Error(UC("[Windows] More than max selectable sockets are set %d > %d"),
124+
n, WSA_MAXIMUM_WAIT_EVENTS);
125+
}
119126
ctx->thread = GetCurrentThread();
120-
121-
hEvents[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
122-
hEvents[1] = ctx->event;
123-
124-
#define SET_EVENT(sockets, event, flags) \
125-
do { \
126-
SgObject cp; \
127-
SG_FOR_EACH(cp, sockets) { \
128-
SG_SET_SOCKET_EVENT(SG_CAAR(cp), event, flags); \
129-
} \
127+
eArray[n] = ctx->event;
128+
#define SET_EVENT(sockets, flags) \
129+
do { \
130+
SgObject cp; \
131+
int i = 0; \
132+
SG_FOR_EACH(cp, sockets) { \
133+
SgObject s = SG_CAAR(cp); \
134+
sArray[i] = SG_SOCKET(s)->socket; \
135+
eArray[i] = WSACreateEvent(); \
136+
if (WSAEventSelect(sArray[i], eArray[i], flags) != 0) { \
137+
err = TRUE; \
138+
goto cleanup; \
139+
} \
140+
i++; \
141+
} \
130142
} while(0)
131-
132-
SET_EVENT(selector->sockets, hEvents[0], FD_READ | FD_OOB);
143+
SET_EVENT(selector->sockets, waiting_flags);
133144

134145
sp = selector_timespec(timeout, &spec);
135146
if (sp) {
136147
millis = sp->tv_sec * 1000;
137148
millis += sp->tv_nsec / 1000000;
138149
}
139150

140-
r = WaitForMultipleObjects(2, hEvents, FALSE, millis);
141-
if (r == WAIT_OBJECT_0 + 1) {
142-
ResetEvent(ctx->event);
143-
}
144-
145-
/* Using WSAPoll to detect which sockets are ready to read */
146-
WSAPOLLFD *fds = SG_NEW_ATOMIC2(WSAPOLLFD *, n * sizeof(WSAPOLLFD));
147-
int i = 0;
148-
SgObject cp;
149-
SG_FOR_EACH(cp, selector->sockets) {
150-
SgSocket *sock = SG_SOCKET(SG_CAAR(cp));
151-
fds[i].fd = sock->socket;
152-
fds[i].events = POLLRDNORM;
153-
i++;
154-
}
155-
r = WSAPoll(fds, n, 0); /* We may return SG_NIL in case of interrupt */
156-
if (r == SOCKET_ERROR) system_error(WSAGetLastError());
157-
for (i = 0; i < n; i++) {
158-
if (fds[i].revents & POLLRDNORM) {
159-
/* collect sockets, should we use hashtable? */
160-
SgObject o = select_socket(fds[i].fd, selector->sockets);
161-
if (!SG_FALSEP(o)) ret = Sg_Cons(o, ret);
151+
r = WSAWaitForMultipleEvents(n + 1, eArray, FALSE, millis, FALSE);
152+
for (int i = r - WSA_WAIT_EVENT_0; i < n; i++) {
153+
r = WSAWaitForMultipleEvents(1, &eArray[i], TRUE, 0, FALSE);
154+
if (r != WSA_WAIT_FAILED && r != WSA_WAIT_TIMEOUT) {
155+
WSANETWORKEVENTS networkEvents;
156+
if (WSAEnumNetworkEvents(sArray[i], eArray[i], &networkEvents) == 0) {
157+
if ((networkEvents.lNetworkEvents & waiting_flags) != 0) {
158+
SgObject o = select_socket(sArray[i], selector->sockets);
159+
if (!SG_FALSEP(o)) ret = Sg_Cons(o, ret);
160+
}
161+
}
162162
}
163163
}
164164

165-
SET_EVENT(selector->sockets, hEvents[0], 0);
166165
#undef SET_EVENT
167166

168167
strip_sockets(selector, ret);
169-
CloseHandle(hEvents[0]);
168+
169+
cleanup:
170+
for (int i = 0; i < n; i++) {
171+
if (eArray[i]) WSACloseEvent(eArray[i]);
172+
}
170173
ctx->thread = NULL;
174+
if (err) {
175+
int e = WSAGetLastError();
176+
Sg_Error(UC("Failed to wait selector: [%d] %S"), e,
177+
Sg_GetLastErrorMessageWithErrorCode(e));
178+
}
171179
return ret;
172180
}
173181

@@ -181,6 +189,6 @@ int Sg_SocketSelectorWaitingP(SgSocketSelector *selector)
181189
SgObject Sg_SocketSelectorInterrupt(SgSocketSelector *selector)
182190
{
183191
win_context_t *ctx = (win_context_t *)selector->context;
184-
SetEvent(ctx->event);
192+
WSASetEvent(ctx->event);
185193
return selector;
186194
}

0 commit comments

Comments
 (0)