Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmlibuv/src/win/poll.c
3153 views
1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
*
3
* Permission is hereby granted, free of charge, to any person obtaining a copy
4
* of this software and associated documentation files (the "Software"), to
5
* deal in the Software without restriction, including without limitation the
6
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
* sell copies of the Software, and to permit persons to whom the Software is
8
* furnished to do so, subject to the following conditions:
9
*
10
* The above copyright notice and this permission notice shall be included in
11
* all copies or substantial portions of the Software.
12
*
13
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
* IN THE SOFTWARE.
20
*/
21
22
#include <assert.h>
23
#include <io.h>
24
25
#include "uv.h"
26
#include "internal.h"
27
#include "handle-inl.h"
28
#include "req-inl.h"
29
30
31
static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
32
{0xe70f1aa0, 0xab8b, 0x11cf,
33
{0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
34
{0xf9eab0c0, 0x26d4, 0x11d0,
35
{0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
36
{0x9fc48064, 0x7298, 0x43e4,
37
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}},
38
{0xa00943d9, 0x9c2e, 0x4633,
39
{0x9b, 0x59, 0x00, 0x57, 0xa3, 0x16, 0x09, 0x94}}
40
};
41
42
typedef struct uv_single_fd_set_s {
43
unsigned int fd_count;
44
SOCKET fd_array[1];
45
} uv_single_fd_set_t;
46
47
48
static OVERLAPPED overlapped_dummy_;
49
static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
50
51
static AFD_POLL_INFO afd_poll_info_dummy_;
52
53
54
static void uv__init_overlapped_dummy(void) {
55
HANDLE event;
56
57
event = CreateEvent(NULL, TRUE, TRUE, NULL);
58
if (event == NULL)
59
uv_fatal_error(GetLastError(), "CreateEvent");
60
61
memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
62
overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
63
}
64
65
66
static OVERLAPPED* uv__get_overlapped_dummy(void) {
67
uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
68
return &overlapped_dummy_;
69
}
70
71
72
static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
73
return &afd_poll_info_dummy_;
74
}
75
76
77
static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
78
uv_req_t* req;
79
AFD_POLL_INFO* afd_poll_info;
80
int result;
81
82
/* Find a yet unsubmitted req to submit. */
83
if (handle->submitted_events_1 == 0) {
84
req = &handle->poll_req_1;
85
afd_poll_info = &handle->afd_poll_info_1;
86
handle->submitted_events_1 = handle->events;
87
handle->mask_events_1 = 0;
88
handle->mask_events_2 = handle->events;
89
} else if (handle->submitted_events_2 == 0) {
90
req = &handle->poll_req_2;
91
afd_poll_info = &handle->afd_poll_info_2;
92
handle->submitted_events_2 = handle->events;
93
handle->mask_events_1 = handle->events;
94
handle->mask_events_2 = 0;
95
} else {
96
/* Just wait until there's an unsubmitted req. This will happen almost
97
* immediately as one of the 2 outstanding requests is about to return.
98
* When this happens, uv__fast_poll_process_poll_req will be called, and
99
* the pending events, if needed, will be processed in a subsequent
100
* request. */
101
return;
102
}
103
104
/* Setting Exclusive to TRUE makes the other poll request return if there is
105
* any. */
106
afd_poll_info->Exclusive = TRUE;
107
afd_poll_info->NumberOfHandles = 1;
108
afd_poll_info->Timeout.QuadPart = INT64_MAX;
109
afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
110
afd_poll_info->Handles[0].Status = 0;
111
afd_poll_info->Handles[0].Events = 0;
112
113
if (handle->events & UV_READABLE) {
114
afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
115
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
116
} else {
117
if (handle->events & UV_DISCONNECT) {
118
afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT;
119
}
120
}
121
if (handle->events & UV_WRITABLE) {
122
afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
123
}
124
125
memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
126
127
result = uv__msafd_poll((SOCKET) handle->peer_socket,
128
afd_poll_info,
129
afd_poll_info,
130
&req->u.io.overlapped);
131
if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
132
/* Queue this req, reporting an error. */
133
SET_REQ_ERROR(req, WSAGetLastError());
134
uv__insert_pending_req(loop, req);
135
}
136
}
137
138
139
static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
140
uv_req_t* req) {
141
unsigned char mask_events;
142
AFD_POLL_INFO* afd_poll_info;
143
144
if (req == &handle->poll_req_1) {
145
afd_poll_info = &handle->afd_poll_info_1;
146
handle->submitted_events_1 = 0;
147
mask_events = handle->mask_events_1;
148
} else if (req == &handle->poll_req_2) {
149
afd_poll_info = &handle->afd_poll_info_2;
150
handle->submitted_events_2 = 0;
151
mask_events = handle->mask_events_2;
152
} else {
153
assert(0);
154
return;
155
}
156
157
/* Report an error unless the select was just interrupted. */
158
if (!REQ_SUCCESS(req)) {
159
DWORD error = GET_REQ_SOCK_ERROR(req);
160
if (error != WSAEINTR && handle->events != 0) {
161
handle->events = 0; /* Stop the watcher */
162
handle->poll_cb(handle, uv_translate_sys_error(error), 0);
163
}
164
165
} else if (afd_poll_info->NumberOfHandles >= 1) {
166
unsigned char events = 0;
167
168
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
169
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
170
events |= UV_READABLE;
171
if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) {
172
events |= UV_DISCONNECT;
173
}
174
}
175
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
176
AFD_POLL_CONNECT_FAIL)) != 0) {
177
events |= UV_WRITABLE;
178
}
179
180
events &= handle->events & ~mask_events;
181
182
if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
183
/* Stop polling. */
184
handle->events = 0;
185
if (uv__is_active(handle))
186
uv__handle_stop(handle);
187
}
188
189
if (events != 0) {
190
handle->poll_cb(handle, 0, events);
191
}
192
}
193
194
if ((handle->events & ~(handle->submitted_events_1 |
195
handle->submitted_events_2)) != 0) {
196
uv__fast_poll_submit_poll_req(loop, handle);
197
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
198
handle->submitted_events_1 == 0 &&
199
handle->submitted_events_2 == 0) {
200
uv__want_endgame(loop, (uv_handle_t*) handle);
201
}
202
}
203
204
205
static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
206
WSAPROTOCOL_INFOW* protocol_info) {
207
SOCKET sock = 0;
208
209
sock = WSASocketW(protocol_info->iAddressFamily,
210
protocol_info->iSocketType,
211
protocol_info->iProtocol,
212
protocol_info,
213
0,
214
WSA_FLAG_OVERLAPPED);
215
if (sock == INVALID_SOCKET) {
216
return INVALID_SOCKET;
217
}
218
219
if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
220
goto error;
221
};
222
223
if (CreateIoCompletionPort((HANDLE) sock,
224
iocp,
225
(ULONG_PTR) sock,
226
0) == NULL) {
227
goto error;
228
}
229
230
return sock;
231
232
error:
233
closesocket(sock);
234
return INVALID_SOCKET;
235
}
236
237
238
static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
239
WSAPROTOCOL_INFOW* protocol_info) {
240
int index, i;
241
SOCKET peer_socket;
242
243
index = -1;
244
for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
245
if (memcmp((void*) &protocol_info->ProviderId,
246
(void*) &uv_msafd_provider_ids[i],
247
sizeof protocol_info->ProviderId) == 0) {
248
index = i;
249
}
250
}
251
252
/* Check if the protocol uses an msafd socket. */
253
if (index < 0) {
254
return INVALID_SOCKET;
255
}
256
257
/* If we didn't (try) to create a peer socket yet, try to make one. Don't try
258
* again if the peer socket creation failed earlier for the same protocol. */
259
peer_socket = loop->poll_peer_sockets[index];
260
if (peer_socket == 0) {
261
peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
262
loop->poll_peer_sockets[index] = peer_socket;
263
}
264
265
return peer_socket;
266
}
267
268
269
static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
270
uv_req_t* req = (uv_req_t*) arg;
271
uv_poll_t* handle = (uv_poll_t*) req->data;
272
unsigned char reported_events;
273
int r;
274
uv_single_fd_set_t rfds, wfds, efds;
275
struct timeval timeout;
276
277
assert(handle->type == UV_POLL);
278
assert(req->type == UV_POLL_REQ);
279
280
if (handle->events & UV_READABLE) {
281
rfds.fd_count = 1;
282
rfds.fd_array[0] = handle->socket;
283
} else {
284
rfds.fd_count = 0;
285
}
286
287
if (handle->events & UV_WRITABLE) {
288
wfds.fd_count = 1;
289
wfds.fd_array[0] = handle->socket;
290
efds.fd_count = 1;
291
efds.fd_array[0] = handle->socket;
292
} else {
293
wfds.fd_count = 0;
294
efds.fd_count = 0;
295
}
296
297
/* Make the select() time out after 3 minutes. If select() hangs because the
298
* user closed the socket, we will at least not hang indefinitely. */
299
timeout.tv_sec = 3 * 60;
300
timeout.tv_usec = 0;
301
302
r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
303
if (r == SOCKET_ERROR) {
304
/* Queue this req, reporting an error. */
305
SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
306
POST_COMPLETION_FOR_REQ(handle->loop, req);
307
return 0;
308
}
309
310
reported_events = 0;
311
312
if (r > 0) {
313
if (rfds.fd_count > 0) {
314
assert(rfds.fd_count == 1);
315
assert(rfds.fd_array[0] == handle->socket);
316
reported_events |= UV_READABLE;
317
}
318
319
if (wfds.fd_count > 0) {
320
assert(wfds.fd_count == 1);
321
assert(wfds.fd_array[0] == handle->socket);
322
reported_events |= UV_WRITABLE;
323
} else if (efds.fd_count > 0) {
324
assert(efds.fd_count == 1);
325
assert(efds.fd_array[0] == handle->socket);
326
reported_events |= UV_WRITABLE;
327
}
328
}
329
330
SET_REQ_SUCCESS(req);
331
req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
332
POST_COMPLETION_FOR_REQ(handle->loop, req);
333
334
return 0;
335
}
336
337
338
static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
339
uv_req_t* req;
340
341
/* Find a yet unsubmitted req to submit. */
342
if (handle->submitted_events_1 == 0) {
343
req = &handle->poll_req_1;
344
handle->submitted_events_1 = handle->events;
345
handle->mask_events_1 = 0;
346
handle->mask_events_2 = handle->events;
347
} else if (handle->submitted_events_2 == 0) {
348
req = &handle->poll_req_2;
349
handle->submitted_events_2 = handle->events;
350
handle->mask_events_1 = handle->events;
351
handle->mask_events_2 = 0;
352
} else {
353
assert(0);
354
return;
355
}
356
357
if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
358
(void*) req,
359
WT_EXECUTELONGFUNCTION)) {
360
/* Make this req pending, reporting an error. */
361
SET_REQ_ERROR(req, GetLastError());
362
uv__insert_pending_req(loop, req);
363
}
364
}
365
366
367
368
static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
369
uv_req_t* req) {
370
unsigned char mask_events;
371
int err;
372
373
if (req == &handle->poll_req_1) {
374
handle->submitted_events_1 = 0;
375
mask_events = handle->mask_events_1;
376
} else if (req == &handle->poll_req_2) {
377
handle->submitted_events_2 = 0;
378
mask_events = handle->mask_events_2;
379
} else {
380
assert(0);
381
return;
382
}
383
384
if (!REQ_SUCCESS(req)) {
385
/* Error. */
386
if (handle->events != 0) {
387
err = GET_REQ_ERROR(req);
388
handle->events = 0; /* Stop the watcher */
389
handle->poll_cb(handle, uv_translate_sys_error(err), 0);
390
}
391
} else {
392
/* Got some events. */
393
int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
394
if (events != 0) {
395
handle->poll_cb(handle, 0, events);
396
}
397
}
398
399
if ((handle->events & ~(handle->submitted_events_1 |
400
handle->submitted_events_2)) != 0) {
401
uv__slow_poll_submit_poll_req(loop, handle);
402
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
403
handle->submitted_events_1 == 0 &&
404
handle->submitted_events_2 == 0) {
405
uv__want_endgame(loop, (uv_handle_t*) handle);
406
}
407
}
408
409
410
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
411
return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
412
}
413
414
415
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
416
uv_os_sock_t socket) {
417
WSAPROTOCOL_INFOW protocol_info;
418
int len;
419
SOCKET peer_socket, base_socket;
420
DWORD bytes;
421
DWORD yes = 1;
422
423
/* Set the socket to nonblocking mode */
424
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
425
return uv_translate_sys_error(WSAGetLastError());
426
427
/* Try to obtain a base handle for the socket. This increases this chances that
428
* we find an AFD handle and are able to use the fast poll mechanism. This will
429
* always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE
430
* ioctl. */
431
#ifndef NDEBUG
432
base_socket = INVALID_SOCKET;
433
#endif
434
435
if (WSAIoctl(socket,
436
SIO_BASE_HANDLE,
437
NULL,
438
0,
439
&base_socket,
440
sizeof base_socket,
441
&bytes,
442
NULL,
443
NULL) == 0) {
444
assert(base_socket != 0 && base_socket != INVALID_SOCKET);
445
socket = base_socket;
446
}
447
448
uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
449
handle->socket = socket;
450
handle->events = 0;
451
452
/* Obtain protocol information about the socket. */
453
len = sizeof protocol_info;
454
if (getsockopt(socket,
455
SOL_SOCKET,
456
SO_PROTOCOL_INFOW,
457
(char*) &protocol_info,
458
&len) != 0) {
459
return uv_translate_sys_error(WSAGetLastError());
460
}
461
462
/* Get the peer socket that is needed to enable fast poll. If the returned
463
* value is NULL, the protocol is not implemented by MSAFD and we'll have to
464
* use slow mode. */
465
peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
466
467
if (peer_socket != INVALID_SOCKET) {
468
/* Initialize fast poll specific fields. */
469
handle->peer_socket = peer_socket;
470
} else {
471
/* Initialize slow poll specific fields. */
472
handle->flags |= UV_HANDLE_POLL_SLOW;
473
}
474
475
/* Initialize 2 poll reqs. */
476
handle->submitted_events_1 = 0;
477
UV_REQ_INIT(&handle->poll_req_1, UV_POLL_REQ);
478
handle->poll_req_1.data = handle;
479
480
handle->submitted_events_2 = 0;
481
UV_REQ_INIT(&handle->poll_req_2, UV_POLL_REQ);
482
handle->poll_req_2.data = handle;
483
484
return 0;
485
}
486
487
488
static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) {
489
int submitted_events;
490
491
assert(handle->type == UV_POLL);
492
assert(!(handle->flags & UV_HANDLE_CLOSING));
493
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
494
UV_PRIORITIZED)) == 0);
495
496
handle->events = events;
497
handle->poll_cb = cb;
498
499
if (handle->events == 0) {
500
uv__handle_stop(handle);
501
return 0;
502
}
503
504
uv__handle_start(handle);
505
submitted_events = handle->submitted_events_1 | handle->submitted_events_2;
506
507
if (handle->events & ~submitted_events) {
508
if (handle->flags & UV_HANDLE_POLL_SLOW) {
509
uv__slow_poll_submit_poll_req(handle->loop, handle);
510
} else {
511
uv__fast_poll_submit_poll_req(handle->loop, handle);
512
}
513
}
514
515
return 0;
516
}
517
518
519
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
520
return uv__poll_set(handle, events, cb);
521
}
522
523
524
int uv_poll_stop(uv_poll_t* handle) {
525
return uv__poll_set(handle, 0, handle->poll_cb);
526
}
527
528
529
void uv__process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
530
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
531
uv__fast_poll_process_poll_req(loop, handle, req);
532
} else {
533
uv__slow_poll_process_poll_req(loop, handle, req);
534
}
535
}
536
537
538
int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle) {
539
AFD_POLL_INFO afd_poll_info;
540
DWORD error;
541
int result;
542
543
handle->events = 0;
544
uv__handle_closing(handle);
545
546
if (handle->submitted_events_1 == 0 &&
547
handle->submitted_events_2 == 0) {
548
uv__want_endgame(loop, (uv_handle_t*) handle);
549
return 0;
550
}
551
552
if (handle->flags & UV_HANDLE_POLL_SLOW)
553
return 0;
554
555
/* Cancel outstanding poll requests by executing another, unique poll
556
* request that forces the outstanding ones to return. */
557
afd_poll_info.Exclusive = TRUE;
558
afd_poll_info.NumberOfHandles = 1;
559
afd_poll_info.Timeout.QuadPart = INT64_MAX;
560
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
561
afd_poll_info.Handles[0].Status = 0;
562
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
563
564
result = uv__msafd_poll(handle->socket,
565
&afd_poll_info,
566
uv__get_afd_poll_info_dummy(),
567
uv__get_overlapped_dummy());
568
569
if (result == SOCKET_ERROR) {
570
error = WSAGetLastError();
571
if (error != WSA_IO_PENDING)
572
return uv_translate_sys_error(error);
573
}
574
575
return 0;
576
}
577
578
579
void uv__poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
580
assert(handle->flags & UV_HANDLE_CLOSING);
581
assert(!(handle->flags & UV_HANDLE_CLOSED));
582
583
assert(handle->submitted_events_1 == 0);
584
assert(handle->submitted_events_2 == 0);
585
586
uv__handle_close(handle);
587
}
588
589