4
4
#include <stdbool.h>
5
5
#include <string.h>
6
6
7
+ #if _WIN32
8
+ #define WIN32_LEAN_AND_MEAN
9
+ #include <windows.h>
10
+ #else
7
11
#include <poll.h>
8
12
#include <unistd.h>
9
13
#include <sys/mman.h>
14
+ #endif
10
15
11
16
#include "coroutine.h"
12
17
18
+
19
+ #if _WIN32
20
+ int getpagesize () {
21
+ SYSTEM_INFO si ;
22
+ GetSystemInfo (& si );
23
+ return si .dwPageSize ;
24
+ }
25
+ #endif
26
+
13
27
// TODO: make the STACK_CAPACITY customizable by the user
14
28
//#define STACK_CAPACITY (4*1024)
15
29
#define STACK_CAPACITY (1024*getpagesize())
@@ -60,7 +74,11 @@ typedef struct {
60
74
} Indices ;
61
75
62
76
typedef struct {
77
+ #if _WIN32
78
+ char * items ; // not supported yet
79
+ #else
63
80
struct pollfd * items ;
81
+ #endif
64
82
size_t count ;
65
83
size_t capacity ;
66
84
} Polls ;
@@ -82,12 +100,33 @@ typedef enum {
82
100
SM_WRITE ,
83
101
} Sleep_Mode ;
84
102
85
- // Linux x86_64 call convention
103
+ // Linux x86_64 calling convention
86
104
// %rdi, %rsi, %rdx, %rcx, %r8, and %r9
87
105
106
+ // https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions?view=msvc-170#x64-register-usage
107
+ // Windows x64 calling convention: RCX, RDX, R8, R9
108
+ // Windows x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, and XMM6-XMM15 nonvolatile.
109
+ // They must be saved and restored by a function that uses them.
110
+
88
111
void __attribute__((naked )) coroutine_yield (void )
89
112
{
90
113
// @arch
114
+ #if _WIN32
115
+ asm(
116
+ " pushq %rcx\n"
117
+ " pushq %rbx\n"
118
+ " pushq %rbp\n"
119
+ " pushq %rdi\n"
120
+ " pushq %rsi\n"
121
+ " pushq %r12\n"
122
+ " pushq %r13\n"
123
+ " pushq %r14\n"
124
+ " pushq %r15\n"
125
+ // TODO: push XMM6-XMM15
126
+ " movq %rsp, %rcx\n" // rsp
127
+ " movq $0, %rdx\n" // sm = SM_READ
128
+ " jmp coroutine_switch_context\n" );
129
+ #else
91
130
asm(
92
131
" pushq %rdi\n"
93
132
" pushq %rbp\n"
@@ -99,12 +138,32 @@ void __attribute__((naked)) coroutine_yield(void)
99
138
" movq %rsp, %rdi\n" // rsp
100
139
" movq $0, %rsi\n" // sm = SM_NONE
101
140
" jmp coroutine_switch_context\n" );
141
+ #endif
102
142
}
103
143
104
144
void __attribute__((naked )) coroutine_sleep_read (int fd )
105
145
{
146
+ #if !defined(__clang__ )
106
147
(void ) fd ;
148
+ #endif
107
149
// @arch
150
+ #if _WIN32
151
+ asm(
152
+ " pushq %rcx\n"
153
+ " pushq %rbx\n"
154
+ " pushq %rbp\n"
155
+ " pushq %rdi\n"
156
+ " pushq %rsi\n"
157
+ " pushq %r12\n"
158
+ " pushq %r13\n"
159
+ " pushq %r14\n"
160
+ " pushq %r15\n"
161
+ // TODO: push XMM6-XMM15
162
+ " movq %rcx, %r8\n" // fd
163
+ " movq %rsp, %rcx\n" // rsp
164
+ " movq $1, %rdx\n" // sm = SM_READ
165
+ " jmp coroutine_switch_context\n" );
166
+ #else
108
167
asm(
109
168
" pushq %rdi\n"
110
169
" pushq %rbp\n"
@@ -117,12 +176,32 @@ void __attribute__((naked)) coroutine_sleep_read(int fd)
117
176
" movq %rsp, %rdi\n" // rsp
118
177
" movq $1, %rsi\n" // sm = SM_READ
119
178
" jmp coroutine_switch_context\n" );
179
+ #endif
120
180
}
121
181
122
182
void __attribute__((naked )) coroutine_sleep_write (int fd )
123
183
{
184
+ #if !defined(__clang__ )
124
185
(void ) fd ;
186
+ #endif
125
187
// @arch
188
+ #if _WIN32
189
+ asm(
190
+ " pushq %rcx\n"
191
+ " pushq %rbx\n"
192
+ " pushq %rbp\n"
193
+ " pushq %rdi\n"
194
+ " pushq %rsi\n"
195
+ " pushq %r12\n"
196
+ " pushq %r13\n"
197
+ " pushq %r14\n"
198
+ " pushq %r15\n"
199
+ // TODO: push XMM6-XMM15
200
+ " movq %rcx, %r8\n" // fd
201
+ " movq %rsp, %rcx\n" // rsp
202
+ " movq $2, %rdx\n" // sm = SM_READ
203
+ " jmp coroutine_switch_context\n" );
204
+ #else
126
205
asm(
127
206
" pushq %rdi\n"
128
207
" pushq %rbp\n"
@@ -135,12 +214,30 @@ void __attribute__((naked)) coroutine_sleep_write(int fd)
135
214
" movq %rsp, %rdi\n" // rsp
136
215
" movq $2, %rsi\n" // sm = SM_WRITE
137
216
" jmp coroutine_switch_context\n" );
217
+ #endif
138
218
}
139
219
140
220
void __attribute__((naked )) coroutine_restore_context (void * rsp )
141
221
{
142
222
// @arch
223
+ #if !defined(__clang__ )
143
224
(void )rsp ;
225
+ #endif
226
+ #if _WIN32
227
+ asm(
228
+ " movq %rcx, %rsp\n"
229
+ // TODO: pop XMM15-XMM6
230
+ " popq %r15\n"
231
+ " popq %r14\n"
232
+ " popq %r13\n"
233
+ " popq %r12\n"
234
+ " popq %rsi\n"
235
+ " popq %rdi\n"
236
+ " popq %rbp\n"
237
+ " popq %rbx\n"
238
+ " popq %rcx\n"
239
+ " ret\n" );
240
+ #else
144
241
asm(
145
242
" movq %rdi, %rsp\n"
146
243
" popq %r15\n"
@@ -151,6 +248,7 @@ void __attribute__((naked)) coroutine_restore_context(void *rsp)
151
248
" popq %rbp\n"
152
249
" popq %rdi\n"
153
250
" ret\n" );
251
+ #endif
154
252
}
155
253
156
254
void coroutine_switch_context (void * rsp , Sleep_Mode sm , int fd )
@@ -160,23 +258,36 @@ void coroutine_switch_context(void *rsp, Sleep_Mode sm, int fd)
160
258
switch (sm ) {
161
259
case SM_NONE : current += 1 ; break ;
162
260
case SM_READ : {
261
+ #if _WIN32
262
+ (void )fd ;
263
+ TODO ("polling is not implemented for windows" );
264
+ #else
163
265
da_append (& asleep , active .items [current ]);
164
266
struct pollfd pfd = {.fd = fd , .events = POLLRDNORM ,};
165
267
da_append (& polls , pfd );
166
268
da_remove_unordered (& active , current );
269
+ #endif
167
270
} break ;
168
271
169
272
case SM_WRITE : {
273
+ #if _WIN32
274
+ (void )fd ;
275
+ TODO ("polling is not implemented for windows" );
276
+ #else
170
277
da_append (& asleep , active .items [current ]);
171
278
struct pollfd pfd = {.fd = fd , .events = POLLWRNORM ,};
172
279
da_append (& polls , pfd );
173
280
da_remove_unordered (& active , current );
281
+ #endif
174
282
} break ;
175
283
176
284
default : UNREACHABLE ("coroutine_switch_context" );
177
285
}
178
286
179
287
if (polls .count > 0 ) {
288
+ #if _WIN32
289
+ TODO ("polling is not implemented for windows" );
290
+ #else
180
291
int timeout = active .count == 0 ? -1 : 0 ;
181
292
int result = poll (polls .items , polls .count , timeout );
182
293
if (result < 0 ) TODO ("poll" );
@@ -191,6 +302,7 @@ void coroutine_switch_context(void *rsp, Sleep_Mode sm, int fd)
191
302
++ i ;
192
303
}
193
304
}
305
+ #endif
194
306
}
195
307
196
308
assert (active .count > 0 );
@@ -216,6 +328,9 @@ void coroutine__finish_current(void)
216
328
da_remove_unordered (& active , current );
217
329
218
330
if (polls .count > 0 ) {
331
+ #if _WIN32
332
+ TODO ("polling is not implemented for windows" );
333
+ #else
219
334
int timeout = active .count == 0 ? -1 : 0 ;
220
335
int result = poll (polls .items , polls .count , timeout );
221
336
if (result < 0 ) TODO ("poll" );
@@ -230,6 +345,7 @@ void coroutine__finish_current(void)
230
345
++ i ;
231
346
}
232
347
}
348
+ #endif
233
349
}
234
350
235
351
assert (active .count > 0 );
@@ -245,21 +361,40 @@ void coroutine_go(void (*f)(void*), void *arg)
245
361
} else {
246
362
da_append (& contexts , ((Context ){0 }));
247
363
id = contexts .count - 1 ;
364
+ #if _WIN32
365
+ void * base = contexts .items [id ].stack_base = VirtualAlloc (NULL , STACK_CAPACITY , MEM_COMMIT | MEM_RESERVE , PAGE_READWRITE );
366
+ assert (base != NULL );
367
+ // TODO: add VirtualProtect with PAGE_NOACCESS for overflow and underflow
368
+ #else
248
369
contexts .items [id ].stack_base = mmap (NULL , STACK_CAPACITY , PROT_WRITE |PROT_READ , MAP_PRIVATE |MAP_STACK |MAP_ANONYMOUS |MAP_GROWSDOWN , -1 , 0 );
249
370
assert (contexts .items [id ].stack_base != MAP_FAILED );
371
+ #endif
250
372
}
251
373
252
374
void * * rsp = (void * * )((char * )contexts .items [id ].stack_base + STACK_CAPACITY );
253
375
// @arch
254
376
* (-- rsp ) = coroutine__finish_current ;
255
377
* (-- rsp ) = f ;
378
+ #if _WIN32
379
+ * (-- rsp ) = arg ; // push rcx
380
+ * (-- rsp ) = 0 ; // push rbx
381
+ * (-- rsp ) = 0 ; // push rbp
382
+ * (-- rsp ) = 0 ; // push rdi
383
+ * (-- rsp ) = 0 ; // push rsi
384
+ * (-- rsp ) = 0 ; // push r12
385
+ * (-- rsp ) = 0 ; // push r13
386
+ * (-- rsp ) = 0 ; // push r14
387
+ * (-- rsp ) = 0 ; // push r15
388
+ // TODO: push XMM6-XMM15
389
+ #else
256
390
* (-- rsp ) = arg ; // push rdi
257
391
* (-- rsp ) = 0 ; // push rbx
258
392
* (-- rsp ) = 0 ; // push rbp
259
393
* (-- rsp ) = 0 ; // push r12
260
394
* (-- rsp ) = 0 ; // push r13
261
395
* (-- rsp ) = 0 ; // push r14
262
396
* (-- rsp ) = 0 ; // push r15
397
+ #endif
263
398
contexts .items [id ].rsp = rsp ;
264
399
265
400
da_append (& active , id );
0 commit comments