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 };
39
40 typedef struct uv_single_fd_set_s {
41 unsigned int fd_count;
42 SOCKET fd_array[1];
43 } uv_single_fd_set_t;
44
45
46 static OVERLAPPED overlapped_dummy_;
47 static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
48
49 static AFD_POLL_INFO afd_poll_info_dummy_;
50
51
uv__init_overlapped_dummy(void)52 static void uv__init_overlapped_dummy(void) {
53 HANDLE event;
54
55 event = CreateEvent(NULL, TRUE, TRUE, NULL);
56 if (event == NULL)
57 uv_fatal_error(GetLastError(), "CreateEvent");
58
59 memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
60 overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
61 }
62
63
uv__get_overlapped_dummy(void)64 static OVERLAPPED* uv__get_overlapped_dummy(void) {
65 uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
66 return &overlapped_dummy_;
67 }
68
69
uv__get_afd_poll_info_dummy(void)70 static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
71 return &afd_poll_info_dummy_;
72 }
73
74
uv__fast_poll_submit_poll_req(uv_loop_t * loop,uv_poll_t * handle)75 static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
76 uv_req_t* req;
77 AFD_POLL_INFO* afd_poll_info;
78 int result;
79
80 /* Find a yet unsubmitted req to submit. */
81 if (handle->submitted_events_1 == 0) {
82 req = &handle->poll_req_1;
83 afd_poll_info = &handle->afd_poll_info_1;
84 handle->submitted_events_1 = handle->events;
85 handle->mask_events_1 = 0;
86 handle->mask_events_2 = handle->events;
87 } else if (handle->submitted_events_2 == 0) {
88 req = &handle->poll_req_2;
89 afd_poll_info = &handle->afd_poll_info_2;
90 handle->submitted_events_2 = handle->events;
91 handle->mask_events_1 = handle->events;
92 handle->mask_events_2 = 0;
93 } else {
94 /* Just wait until there's an unsubmitted req. This will happen almost
95 * immediately as one of the 2 outstanding requests is about to return.
96 * When this happens, uv__fast_poll_process_poll_req will be called, and
97 * the pending events, if needed, will be processed in a subsequent
98 * request. */
99 return;
100 }
101
102 /* Setting Exclusive to TRUE makes the other poll request return if there is
103 * any. */
104 afd_poll_info->Exclusive = TRUE;
105 afd_poll_info->NumberOfHandles = 1;
106 afd_poll_info->Timeout.QuadPart = INT64_MAX;
107 afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
108 afd_poll_info->Handles[0].Status = 0;
109 afd_poll_info->Handles[0].Events = 0;
110
111 if (handle->events & UV_READABLE) {
112 afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
113 AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
114 } else {
115 if (handle->events & UV_DISCONNECT) {
116 afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT;
117 }
118 }
119 if (handle->events & UV_WRITABLE) {
120 afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
121 }
122
123 memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
124
125 result = uv_msafd_poll((SOCKET) handle->peer_socket,
126 afd_poll_info,
127 afd_poll_info,
128 &req->u.io.overlapped);
129 if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
130 /* Queue this req, reporting an error. */
131 SET_REQ_ERROR(req, WSAGetLastError());
132 uv_insert_pending_req(loop, req);
133 }
134 }
135
136
uv__fast_poll_cancel_poll_req(uv_loop_t * loop,uv_poll_t * handle)137 static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
138 AFD_POLL_INFO afd_poll_info;
139 int result;
140
141 afd_poll_info.Exclusive = TRUE;
142 afd_poll_info.NumberOfHandles = 1;
143 afd_poll_info.Timeout.QuadPart = INT64_MAX;
144 afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
145 afd_poll_info.Handles[0].Status = 0;
146 afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
147
148 result = uv_msafd_poll(handle->socket,
149 &afd_poll_info,
150 uv__get_afd_poll_info_dummy(),
151 uv__get_overlapped_dummy());
152
153 if (result == SOCKET_ERROR) {
154 DWORD error = WSAGetLastError();
155 if (error != WSA_IO_PENDING)
156 return error;
157 }
158
159 return 0;
160 }
161
162
uv__fast_poll_process_poll_req(uv_loop_t * loop,uv_poll_t * handle,uv_req_t * req)163 static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
164 uv_req_t* req) {
165 unsigned char mask_events;
166 AFD_POLL_INFO* afd_poll_info;
167
168 if (req == &handle->poll_req_1) {
169 afd_poll_info = &handle->afd_poll_info_1;
170 handle->submitted_events_1 = 0;
171 mask_events = handle->mask_events_1;
172 } else if (req == &handle->poll_req_2) {
173 afd_poll_info = &handle->afd_poll_info_2;
174 handle->submitted_events_2 = 0;
175 mask_events = handle->mask_events_2;
176 } else {
177 assert(0);
178 return;
179 }
180
181 /* Report an error unless the select was just interrupted. */
182 if (!REQ_SUCCESS(req)) {
183 DWORD error = GET_REQ_SOCK_ERROR(req);
184 if (error != WSAEINTR && handle->events != 0) {
185 handle->events = 0; /* Stop the watcher */
186 handle->poll_cb(handle, uv_translate_sys_error(error), 0);
187 }
188
189 } else if (afd_poll_info->NumberOfHandles >= 1) {
190 unsigned char events = 0;
191
192 if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
193 AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
194 events |= UV_READABLE;
195 if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) {
196 events |= UV_DISCONNECT;
197 }
198 }
199 if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
200 AFD_POLL_CONNECT_FAIL)) != 0) {
201 events |= UV_WRITABLE;
202 }
203
204 events &= handle->events & ~mask_events;
205
206 if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
207 /* Stop polling. */
208 handle->events = 0;
209 if (uv__is_active(handle))
210 uv__handle_stop(handle);
211 }
212
213 if (events != 0) {
214 handle->poll_cb(handle, 0, events);
215 }
216 }
217
218 if ((handle->events & ~(handle->submitted_events_1 |
219 handle->submitted_events_2)) != 0) {
220 uv__fast_poll_submit_poll_req(loop, handle);
221 } else if ((handle->flags & UV_HANDLE_CLOSING) &&
222 handle->submitted_events_1 == 0 &&
223 handle->submitted_events_2 == 0) {
224 uv_want_endgame(loop, (uv_handle_t*) handle);
225 }
226 }
227
228
uv__fast_poll_set(uv_loop_t * loop,uv_poll_t * handle,int events)229 static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
230 assert(handle->type == UV_POLL);
231 assert(!(handle->flags & UV_HANDLE_CLOSING));
232 assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
233
234 handle->events = events;
235
236 if (handle->events != 0) {
237 uv__handle_start(handle);
238 } else {
239 uv__handle_stop(handle);
240 }
241
242 if ((handle->events & ~(handle->submitted_events_1 |
243 handle->submitted_events_2)) != 0) {
244 uv__fast_poll_submit_poll_req(handle->loop, handle);
245 }
246
247 return 0;
248 }
249
250
uv__fast_poll_close(uv_loop_t * loop,uv_poll_t * handle)251 static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
252 handle->events = 0;
253 uv__handle_closing(handle);
254
255 if (handle->submitted_events_1 == 0 &&
256 handle->submitted_events_2 == 0) {
257 uv_want_endgame(loop, (uv_handle_t*) handle);
258 return 0;
259 } else {
260 /* Cancel outstanding poll requests by executing another, unique poll
261 * request that forces the outstanding ones to return. */
262 return uv__fast_poll_cancel_poll_req(loop, handle);
263 }
264 }
265
266
uv__fast_poll_create_peer_socket(HANDLE iocp,WSAPROTOCOL_INFOW * protocol_info)267 static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
268 WSAPROTOCOL_INFOW* protocol_info) {
269 SOCKET sock = 0;
270
271 sock = WSASocketW(protocol_info->iAddressFamily,
272 protocol_info->iSocketType,
273 protocol_info->iProtocol,
274 protocol_info,
275 0,
276 WSA_FLAG_OVERLAPPED);
277 if (sock == INVALID_SOCKET) {
278 return INVALID_SOCKET;
279 }
280
281 if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
282 goto error;
283 };
284
285 if (CreateIoCompletionPort((HANDLE) sock,
286 iocp,
287 (ULONG_PTR) sock,
288 0) == NULL) {
289 goto error;
290 }
291
292 return sock;
293
294 error:
295 closesocket(sock);
296 return INVALID_SOCKET;
297 }
298
299
uv__fast_poll_get_peer_socket(uv_loop_t * loop,WSAPROTOCOL_INFOW * protocol_info)300 static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
301 WSAPROTOCOL_INFOW* protocol_info) {
302 int index, i;
303 SOCKET peer_socket;
304
305 index = -1;
306 for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
307 if (memcmp((void*) &protocol_info->ProviderId,
308 (void*) &uv_msafd_provider_ids[i],
309 sizeof protocol_info->ProviderId) == 0) {
310 index = i;
311 }
312 }
313
314 /* Check if the protocol uses an msafd socket. */
315 if (index < 0) {
316 return INVALID_SOCKET;
317 }
318
319 /* If we didn't (try) to create a peer socket yet, try to make one. Don't try
320 * again if the peer socket creation failed earlier for the same protocol. */
321 peer_socket = loop->poll_peer_sockets[index];
322 if (peer_socket == 0) {
323 peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
324 loop->poll_peer_sockets[index] = peer_socket;
325 }
326
327 return peer_socket;
328 }
329
330
uv__slow_poll_thread_proc(void * arg)331 static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
332 uv_req_t* req = (uv_req_t*) arg;
333 uv_poll_t* handle = (uv_poll_t*) req->data;
334 unsigned char reported_events;
335 int r;
336 uv_single_fd_set_t rfds, wfds, efds;
337 struct timeval timeout;
338
339 assert(handle->type == UV_POLL);
340 assert(req->type == UV_POLL_REQ);
341
342 if (handle->events & UV_READABLE) {
343 rfds.fd_count = 1;
344 rfds.fd_array[0] = handle->socket;
345 } else {
346 rfds.fd_count = 0;
347 }
348
349 if (handle->events & UV_WRITABLE) {
350 wfds.fd_count = 1;
351 wfds.fd_array[0] = handle->socket;
352 efds.fd_count = 1;
353 efds.fd_array[0] = handle->socket;
354 } else {
355 wfds.fd_count = 0;
356 efds.fd_count = 0;
357 }
358
359 /* Make the select() time out after 3 minutes. If select() hangs because the
360 * user closed the socket, we will at least not hang indefinitely. */
361 timeout.tv_sec = 3 * 60;
362 timeout.tv_usec = 0;
363
364 r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
365 if (r == SOCKET_ERROR) {
366 /* Queue this req, reporting an error. */
367 SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
368 POST_COMPLETION_FOR_REQ(handle->loop, req);
369 return 0;
370 }
371
372 reported_events = 0;
373
374 if (r > 0) {
375 if (rfds.fd_count > 0) {
376 assert(rfds.fd_count == 1);
377 assert(rfds.fd_array[0] == handle->socket);
378 reported_events |= UV_READABLE;
379 }
380
381 if (wfds.fd_count > 0) {
382 assert(wfds.fd_count == 1);
383 assert(wfds.fd_array[0] == handle->socket);
384 reported_events |= UV_WRITABLE;
385 } else if (efds.fd_count > 0) {
386 assert(efds.fd_count == 1);
387 assert(efds.fd_array[0] == handle->socket);
388 reported_events |= UV_WRITABLE;
389 }
390 }
391
392 SET_REQ_SUCCESS(req);
393 req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
394 POST_COMPLETION_FOR_REQ(handle->loop, req);
395
396 return 0;
397 }
398
399
uv__slow_poll_submit_poll_req(uv_loop_t * loop,uv_poll_t * handle)400 static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
401 uv_req_t* req;
402
403 /* Find a yet unsubmitted req to submit. */
404 if (handle->submitted_events_1 == 0) {
405 req = &handle->poll_req_1;
406 handle->submitted_events_1 = handle->events;
407 handle->mask_events_1 = 0;
408 handle->mask_events_2 = handle->events;
409 } else if (handle->submitted_events_2 == 0) {
410 req = &handle->poll_req_2;
411 handle->submitted_events_2 = handle->events;
412 handle->mask_events_1 = handle->events;
413 handle->mask_events_2 = 0;
414 } else {
415 assert(0);
416 return;
417 }
418
419 if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
420 (void*) req,
421 WT_EXECUTELONGFUNCTION)) {
422 /* Make this req pending, reporting an error. */
423 SET_REQ_ERROR(req, GetLastError());
424 uv_insert_pending_req(loop, req);
425 }
426 }
427
428
429
uv__slow_poll_process_poll_req(uv_loop_t * loop,uv_poll_t * handle,uv_req_t * req)430 static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
431 uv_req_t* req) {
432 unsigned char mask_events;
433 int err;
434
435 if (req == &handle->poll_req_1) {
436 handle->submitted_events_1 = 0;
437 mask_events = handle->mask_events_1;
438 } else if (req == &handle->poll_req_2) {
439 handle->submitted_events_2 = 0;
440 mask_events = handle->mask_events_2;
441 } else {
442 assert(0);
443 return;
444 }
445
446 if (!REQ_SUCCESS(req)) {
447 /* Error. */
448 if (handle->events != 0) {
449 err = GET_REQ_ERROR(req);
450 handle->events = 0; /* Stop the watcher */
451 handle->poll_cb(handle, uv_translate_sys_error(err), 0);
452 }
453 } else {
454 /* Got some events. */
455 int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
456 if (events != 0) {
457 handle->poll_cb(handle, 0, events);
458 }
459 }
460
461 if ((handle->events & ~(handle->submitted_events_1 |
462 handle->submitted_events_2)) != 0) {
463 uv__slow_poll_submit_poll_req(loop, handle);
464 } else if ((handle->flags & UV_HANDLE_CLOSING) &&
465 handle->submitted_events_1 == 0 &&
466 handle->submitted_events_2 == 0) {
467 uv_want_endgame(loop, (uv_handle_t*) handle);
468 }
469 }
470
471
uv__slow_poll_set(uv_loop_t * loop,uv_poll_t * handle,int events)472 static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
473 assert(handle->type == UV_POLL);
474 assert(!(handle->flags & UV_HANDLE_CLOSING));
475 assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
476
477 handle->events = events;
478
479 if (handle->events != 0) {
480 uv__handle_start(handle);
481 } else {
482 uv__handle_stop(handle);
483 }
484
485 if ((handle->events &
486 ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
487 uv__slow_poll_submit_poll_req(handle->loop, handle);
488 }
489
490 return 0;
491 }
492
493
uv__slow_poll_close(uv_loop_t * loop,uv_poll_t * handle)494 static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
495 handle->events = 0;
496 uv__handle_closing(handle);
497
498 if (handle->submitted_events_1 == 0 &&
499 handle->submitted_events_2 == 0) {
500 uv_want_endgame(loop, (uv_handle_t*) handle);
501 }
502
503 return 0;
504 }
505
506
uv_poll_init(uv_loop_t * loop,uv_poll_t * handle,int fd)507 int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
508 return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
509 }
510
511
uv_poll_init_socket(uv_loop_t * loop,uv_poll_t * handle,uv_os_sock_t socket)512 int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
513 uv_os_sock_t socket) {
514 WSAPROTOCOL_INFOW protocol_info;
515 int len;
516 SOCKET peer_socket, base_socket;
517 DWORD bytes;
518 DWORD yes = 1;
519
520 /* Set the socket to nonblocking mode */
521 if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
522 return uv_translate_sys_error(WSAGetLastError());
523
524 /* Try to obtain a base handle for the socket. This increases this chances that
525 * we find an AFD handle and are able to use the fast poll mechanism. This will
526 * always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE
527 * ioctl. */
528 #ifndef NDEBUG
529 base_socket = INVALID_SOCKET;
530 #endif
531
532 if (WSAIoctl(socket,
533 SIO_BASE_HANDLE,
534 NULL,
535 0,
536 &base_socket,
537 sizeof base_socket,
538 &bytes,
539 NULL,
540 NULL) == 0) {
541 assert(base_socket != 0 && base_socket != INVALID_SOCKET);
542 socket = base_socket;
543 }
544
545 uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
546 handle->socket = socket;
547 handle->events = 0;
548
549 /* Obtain protocol information about the socket. */
550 len = sizeof protocol_info;
551 if (getsockopt(socket,
552 SOL_SOCKET,
553 SO_PROTOCOL_INFOW,
554 (char*) &protocol_info,
555 &len) != 0) {
556 return uv_translate_sys_error(WSAGetLastError());
557 }
558
559 /* Get the peer socket that is needed to enable fast poll. If the returned
560 * value is NULL, the protocol is not implemented by MSAFD and we'll have to
561 * use slow mode. */
562 peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
563
564 if (peer_socket != INVALID_SOCKET) {
565 /* Initialize fast poll specific fields. */
566 handle->peer_socket = peer_socket;
567 } else {
568 /* Initialize slow poll specific fields. */
569 handle->flags |= UV_HANDLE_POLL_SLOW;
570 }
571
572 /* Initialize 2 poll reqs. */
573 handle->submitted_events_1 = 0;
574 UV_REQ_INIT(&handle->poll_req_1, UV_POLL_REQ);
575 handle->poll_req_1.data = handle;
576
577 handle->submitted_events_2 = 0;
578 UV_REQ_INIT(&handle->poll_req_2, UV_POLL_REQ);
579 handle->poll_req_2.data = handle;
580
581 return 0;
582 }
583
584
uv_poll_start(uv_poll_t * handle,int events,uv_poll_cb cb)585 int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
586 int err;
587
588 if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
589 err = uv__fast_poll_set(handle->loop, handle, events);
590 } else {
591 err = uv__slow_poll_set(handle->loop, handle, events);
592 }
593
594 if (err) {
595 return uv_translate_sys_error(err);
596 }
597
598 handle->poll_cb = cb;
599
600 return 0;
601 }
602
603
uv_poll_stop(uv_poll_t * handle)604 int uv_poll_stop(uv_poll_t* handle) {
605 int err;
606
607 if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
608 err = uv__fast_poll_set(handle->loop, handle, 0);
609 } else {
610 err = uv__slow_poll_set(handle->loop, handle, 0);
611 }
612
613 return uv_translate_sys_error(err);
614 }
615
616
uv_process_poll_req(uv_loop_t * loop,uv_poll_t * handle,uv_req_t * req)617 void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
618 if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
619 uv__fast_poll_process_poll_req(loop, handle, req);
620 } else {
621 uv__slow_poll_process_poll_req(loop, handle, req);
622 }
623 }
624
625
uv_poll_close(uv_loop_t * loop,uv_poll_t * handle)626 int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
627 if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
628 return uv__fast_poll_close(loop, handle);
629 } else {
630 return uv__slow_poll_close(loop, handle);
631 }
632 }
633
634
uv_poll_endgame(uv_loop_t * loop,uv_poll_t * handle)635 void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
636 assert(handle->flags & UV_HANDLE_CLOSING);
637 assert(!(handle->flags & UV_HANDLE_CLOSED));
638
639 assert(handle->submitted_events_1 == 0);
640 assert(handle->submitted_events_2 == 0);
641
642 uv__handle_close(handle);
643 }
644