Skip to content

Commit abc2100

Browse files
committed
Using WSAPoll for Windows socket selector.
IOCP is not really compatible with kqueue or epoll, it's much richer than I expected. So, on Windows, we do the same as select.
1 parent 3170cef commit abc2100

File tree

5 files changed

+108
-62
lines changed

5 files changed

+108
-62
lines changed

dist.bat

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,30 @@ goto:eof
1616

1717
rem insn
1818
:insn
19-
echo "Generating instructions files"
19+
echo Generating instructions files
2020
cd src
2121
%SASH% geninsn %1
2222
cd ..
2323
goto:eof
2424

2525
rem precomp
2626
:precomp
27-
echo "Generating compiled library files"
27+
echo Generating compiled library files
2828
cd src
2929
%SASH% genlib %1
3030
cd ..
3131
call :insn dummy %1
3232
cd tools\scripts
33-
echo "Generating builtin keywords"
33+
echo Generating builtin keywords
3434
%SASH% builtin-keywords.scm
35-
echo "Generating builtin symbols"
35+
echo Generating builtin symbols
3636
%SASH% builtin-symbols.scm
3737
cd ..\..
3838
goto:eof
3939

4040
rem stub
4141
:stub
42-
echo "Generating library from stub"
42+
echo Generating library from stub
4343
cd src
4444
%SASH% genstub %1
4545
cd ..
@@ -48,18 +48,23 @@ goto:eof
4848
rem srfi
4949
:srfi
5050
echo Generating R7RS style SRFI libraries
51-
%SASH% -L./sitelib ./tools/scripts/r7rs-srfi-gen.scm -p ./ext -p ./sitelib/srfi %1
51+
%SASH% -L./sitelib ./tools/scripts/r7rs-srfi-gen.scm^
52+
-p ./ext -p ./sitelib/srfi %1
5253
goto:eof
5354

5455
rem tzdata
5556
:tz
56-
echo "Generating TZ database"
57-
%SASH% ./tools/scripts/compile-tzdatabase.scm -o ext/time/sagittarius/tzdata.scm -w ext/time/sagittarius/win-mappings.scm -l ext/time/sagittarius/leap-table.scm -r %1
57+
echo Generating TZ database
58+
%SASH% ./tools/scripts/compile-tzdatabase.scm^
59+
-o ext/time/sagittarius/tzdata.scm^
60+
-w ext/time/sagittarius/win-mappings.scm^
61+
-l ext/time/sagittarius/leap-table.scm^
62+
-r %1
5863
goto:eof
5964

6065
rem unicode
6166
:unicode
62-
echo "Generating Unicode codepoints"
67+
echo Generating Unicode codepoints
6368
%SASH% ./tools/scripts/compile-unicode.scm %1
6469

6570
if "%1" == "-c" goto:unicode_end
@@ -95,7 +100,7 @@ goto:eof
95100

96101
rem html
97102
:html
98-
echo "Generating HTML entities"
103+
echo Generating HTML entities
99104
%SASH% ./tools/scripts/html-entities.scm -o sitelib/text/xml/entities-list.scm %1
100105
goto:eof
101106

@@ -127,20 +132,20 @@ for %%x in (%*) do call :%%x
127132
goto end
128133

129134
:usage
130-
echo "usage: %0 precomp|stub|srfi|tz|clean"
131-
echo " gen: generates all files"
132-
echo " precomp: generates precompiled files"
133-
echo " stub: generates stub files"
134-
echo " srfi: generates R7RS style SRFI libraries"
135-
echo " tz: generates TZ database"
136-
echo " unicode: generates Unicode codepoints"
137-
echo " html: generates HTML entries"
138-
echo " clean: cleasn generated files"
135+
echo usage: %0 precomp|stub|srfi|tz|clean
136+
echo gen: generates all files
137+
echo precomp: generates precompiled files
138+
echo stub: generates stub files
139+
echo srfi: generates R7RS style SRFI libraries
140+
echo tz: generates TZ database
141+
echo unicode: generates Unicode codepoints
142+
echo html: generates HTML entries
143+
echo clean: cleasn generated files
139144

140145
goto :end
141146

142147
:err
143-
echo "Sagittarius is not installed. Default %SASH%"
148+
echo Sagittarius is not installed. Default %SASH%
144149

145150
:end
146151

ext/socket/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ ENDIF()
1212
# Simple assumption
1313
# Linux - epoll
1414
# *BSD or macOS - kqueue
15-
# Windows - iocp
15+
# Windows - WSAPoll
1616
IF (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
1717
SET(SELECTOR_SOURCE selector-epoll.c)
1818
ELSEIF(WIN32)
19-
SET(SELECTOR_SOURCE selector-iocp.c)
19+
SET(SELECTOR_SOURCE selector-win.c)
2020
ELSE()
2121
# Assume *BSD or macOS,
2222
CHECK_INCLUDE_FILES("stdint.h;sys/types.h;sys/event.h" HAVE_SYS_EVENT_H)

ext/socket/sagittarius-socket.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1640,7 +1640,7 @@ SG_EXTENSION_ENTRY void CDECL Sg_Init_sagittarius__socket()
16401640
SgLibrary *lib;
16411641
#if defined(_WIN32)
16421642
WSADATA wsaData;
1643-
WSAStartup(2, &wsaData);
1643+
WSAStartup(MAKEWORD(2, 2), &wsaData);
16441644
Sg_AddCleanupHandler(finish_winsock, NULL);
16451645
#endif
16461646
SG_INIT_EXTENSION(sagittarius__socket);
Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* selector-iocp.c -*- mode:c; coding:utf-8; -*-
1+
/* selector-iocp.c -*- mode:c; coding:utf-8; -*-
22
*
33
* Copyright (c) 2023 Takashi Kato <ktakashi@ymail.com>
44
*
@@ -34,30 +34,33 @@
3434

3535
#include "socket-selector.incl"
3636

37-
typedef struct iocp_context_rec
37+
typedef struct win_context_rec
3838
{
39-
HANDLE iocp;
39+
HANDLE event;
4040
HANDLE thread; /* waiting thread */
41-
} iocp_context_t;
41+
} win_context_t;
4242

4343

4444
static void system_error(int code)
4545
{
46-
Sg_SystemError(GetLastError(),
46+
Sg_SystemError(code,
4747
UC("Setting up IOCP failed: %A"),
4848
Sg_GetLastErrorMessageWithErrorCode(code));
4949
}
5050

5151
SgObject Sg_MakeSocketSelector()
5252
{
5353
SgSocketSelector *selector = SG_NEW(SgSocketSelector);
54-
iocp_context_t *ctx = SG_NEW(iocp_context_t);
54+
win_context_t *ctx = SG_NEW(win_context_t);
5555

5656
SG_SET_CLASS(selector, SG_CLASS_SOCKET_SELECTOR);
57-
ctx->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
58-
if (ctx->iocp == NULL) goto err;
57+
58+
ctx->event = CreateEvent(NULL, FALSE, FALSE, NULL);
59+
if (ctx->event == NULL) goto err;
60+
5961
ctx->thread = NULL;
6062
selector->sockets = SG_NIL;
63+
selector->context = ctx;
6164

6265
Sg_RegisterFinalizer(selector, selector_finalizer, NULL);
6366
return SG_OBJ(selector);
@@ -69,32 +72,34 @@ SgObject Sg_MakeSocketSelector()
6972

7073
void Sg_CloseSocketSelector(SgSocketSelector *selector)
7174
{
72-
iocp_context_t *ctx = (iocp_context_t *)selector->context;
73-
CloseHandle(ctx->iocp);
75+
win_context_t *ctx = (win_context_t *)selector->context;
76+
CloseHandle(ctx->event);
7477
Sg_UnregisterFinalizer(selector);
7578
}
7679

7780
SgObject Sg_SocketSelectorAdd(SgSocketSelector *selector, SgSocket *socket)
7881
{
79-
iocp_context_t *ctx = (iocp_context_t *)selector->context;
80-
HANDLE r;
81-
r = CreateIoCompletionPort(ctx->iocp, (HANDLE)socket->socket,
82-
(ULONG_PTR)socket, 0);
83-
if (r == NULL) {
84-
system_error(Sg_GetLastError());
85-
}
82+
win_context_t *ctx = (win_context_t *)selector->context;
8683
selector->sockets = Sg_Cons(socket, selector->sockets);
8784
selector_sockets(selector);
8885
return SG_OBJ(selector);
8986
}
9087

88+
static SgObject select_socket(SOCKET fd, SgObject sockets)
89+
{
90+
SgObject cp;
91+
SG_FOR_EACH(cp, sockets) {
92+
SgSocket *sock = SG_SOCKET(SG_CAR(cp));
93+
if (sock->socket == fd) return sock;
94+
}
95+
return SG_FALSE;
96+
}
97+
9198
SgObject Sg_SocketSelectorWait(SgSocketSelector *selector, SgObject timeout)
9299
{
93-
iocp_context_t *ctx = (iocp_context_t *)selector->context;
94-
int n = selector_sockets(selector), i, millis = INFINITE;
95-
ULONG removed;
96-
LPOVERLAPPED_ENTRY entries;
97-
BOOL r;
100+
win_context_t *ctx = (win_context_t *)selector->context;
101+
int n = selector_sockets(selector), millis = INFINITE, r;
102+
HANDLE hEvents[2];
98103
struct timespec spec, *sp;
99104
SgObject ret = SG_NIL;
100105

@@ -103,35 +108,71 @@ SgObject Sg_SocketSelectorWait(SgSocketSelector *selector, SgObject timeout)
103108
}
104109
ctx->thread = GetCurrentThread();
105110

111+
hEvents[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
112+
hEvents[1] = ctx->event;
113+
114+
#define SET_EVENT(sockets, event, flags) \
115+
do { \
116+
SgObject cp; \
117+
SG_FOR_EACH(cp, sockets) { \
118+
SG_SET_SOCKET_EVENT(SG_CAR(cp), event, flags); \
119+
} \
120+
} while(0)
121+
122+
SET_EVENT(selector->sockets, hEvents[0], FD_READ | FD_OOB);
123+
106124
sp = selector_timespec(timeout, &spec);
107125
if (sp) {
108126
millis = sp->tv_sec * 1000;
109127
millis += sp->tv_nsec / 1000000;
110128
}
111129

112-
entries = SG_NEW_ATOMIC2(OVERLAPPED_ENTRY *, n * sizeof(OVERLAPPED_ENTRY));
113-
r = GetQueuedCompletionStatusEx(ctx->iocp, entries, n, &removed, millis, TRUE);
114-
if (r) {
115-
for (i = 0; i < removed; i++) {
116-
ret = Sg_Cons((SgObject) entries[i].lpCompletionKey, ret);
130+
r = WaitForMultipleObjects(2, hEvents, FALSE, millis);
131+
if (r == WAIT_OBJECT_0) {
132+
/* Using WSAPoll to detect which sockets are ready to read */
133+
WSAPOLLFD *fds = SG_NEW_ATOMIC2(WSAPOLLFD *, n * sizeof(WSAPOLLFD));
134+
int i = 0;
135+
SgObject cp;
136+
SG_FOR_EACH(cp, selector->sockets) {
137+
SgSocket *sock = SG_SOCKET(SG_CAR(cp));
138+
fds[i].fd = sock->socket;
139+
fds[i].events = POLLRDNORM;
140+
i++;
117141
}
118-
} else {
119-
system_error(Sg_GetLastError());
142+
r = WSAPoll(fds, n, 0); /* Some sockets must be ready at this stage */
143+
if (r == SOCKET_ERROR) system_error(WSAGetLastError());
144+
for (i = 0; i < n; i++) {
145+
if (fds[i].revents & POLLRDNORM) {
146+
/* collect sockets, should we use hashtable? */
147+
SgObject o = select_socket(fds[i].fd, selector->sockets);
148+
if (!SG_FALSEP(o)) ret = Sg_Cons(o, ret);
149+
}
150+
}
151+
}
152+
153+
SET_EVENT(selector->sockets, hEvents[0], 0);
154+
#undef SET_EVENT
155+
156+
if (!SG_NULLP(ret)) {
157+
/* remove the returned sockets from the targets */
158+
SgObject h = SG_NIL, t = SG_NIL, cp;
159+
SG_FOR_EACH(cp, selector->sockets) {
160+
if (SG_FALSEP(Sg_Memq(SG_CAR(cp), ret))) {
161+
SG_APPEND1(h, t, SG_CAR(cp));
162+
}
163+
}
164+
selector->sockets = h;
120165
}
166+
CloseHandle(hEvents[0]);
121167
ctx->thread = NULL;
122168
return ret;
123169
}
124170

125-
static void CALLBACK dummy(ULONG_PTR param)
126-
{
127-
/* Do nothing */
128-
}
129-
130171
SgObject Sg_SocketSelectorInterrupt(SgSocketSelector *selector)
131172
{
132-
iocp_context_t *ctx = (iocp_context_t *)selector->context;
173+
win_context_t *ctx = (win_context_t *)selector->context;
133174
if (ctx->thread) {
134-
QueueUserAPC(dummy, ctx->thread, 0);
175+
SetEvent(ctx->event);
135176
}
136177
return selector;
137178
}

ext/socket/socket-selector.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535
Socket selector.
3636
The underlying implementations are platform specific. At this moment,
3737
we support:
38-
- kqueue (*BSD and macOS)
39-
- IOCP (Windows)
40-
- epoll (Linux)
38+
- kqueue (*BSD and macOS)
39+
- WSAPoll (Windows)
40+
- epoll (Linux)
4141
*/
4242
typedef struct SgSocketSelectorRec
4343
{

0 commit comments

Comments
 (0)