xref: /libuv/src/win/poll.c (revision a7b16bfb)
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 
uv__init_overlapped_dummy(void)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 
uv__get_overlapped_dummy(void)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 
uv__get_afd_poll_info_dummy(void)72 static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
73   return &afd_poll_info_dummy_;
74 }
75 
76 
uv__fast_poll_submit_poll_req(uv_loop_t * loop,uv_poll_t * handle)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 
uv__fast_poll_process_poll_req(uv_loop_t * loop,uv_poll_t * handle,uv_req_t * req)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 
uv__fast_poll_create_peer_socket(HANDLE iocp,WSAPROTOCOL_INFOW * protocol_info)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 
uv__fast_poll_get_peer_socket(uv_loop_t * loop,WSAPROTOCOL_INFOW * protocol_info)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 
uv__slow_poll_thread_proc(void * arg)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 
uv__slow_poll_submit_poll_req(uv_loop_t * loop,uv_poll_t * handle)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 
uv__slow_poll_process_poll_req(uv_loop_t * loop,uv_poll_t * handle,uv_req_t * req)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 
uv_poll_init(uv_loop_t * loop,uv_poll_t * handle,int fd)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 
uv_poll_init_socket(uv_loop_t * loop,uv_poll_t * handle,uv_os_sock_t socket)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.
429  */
430 #ifndef NDEBUG
431   base_socket = INVALID_SOCKET;
432 #endif
433 
434   if (WSAIoctl(socket,
435                SIO_BASE_HANDLE,
436                NULL,
437                0,
438                &base_socket,
439                sizeof base_socket,
440                &bytes,
441                NULL,
442                NULL) == 0) {
443     assert(base_socket != 0 && base_socket != INVALID_SOCKET);
444     socket = base_socket;
445   }
446 
447   uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
448   handle->socket = socket;
449   handle->events = 0;
450 
451   /* Obtain protocol information about the socket. */
452   len = sizeof protocol_info;
453   if (getsockopt(socket,
454                  SOL_SOCKET,
455                  SO_PROTOCOL_INFOW,
456                  (char*) &protocol_info,
457                  &len) != 0) {
458     return uv_translate_sys_error(WSAGetLastError());
459   }
460 
461   /* Get the peer socket that is needed to enable fast poll. If the returned
462    * value is NULL, the protocol is not implemented by MSAFD and we'll have to
463    * use slow mode. */
464   peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
465 
466   if (peer_socket != INVALID_SOCKET) {
467     /* Initialize fast poll specific fields. */
468     handle->peer_socket = peer_socket;
469   } else {
470     /* Initialize slow poll specific fields. */
471     handle->flags |= UV_HANDLE_POLL_SLOW;
472   }
473 
474   /* Initialize 2 poll reqs. */
475   handle->submitted_events_1 = 0;
476   UV_REQ_INIT(&handle->poll_req_1, UV_POLL_REQ);
477   handle->poll_req_1.data = handle;
478 
479   handle->submitted_events_2 = 0;
480   UV_REQ_INIT(&handle->poll_req_2, UV_POLL_REQ);
481   handle->poll_req_2.data = handle;
482 
483   return 0;
484 }
485 
486 
uv__poll_set(uv_poll_t * handle,int events,uv_poll_cb cb)487 static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) {
488   int submitted_events;
489 
490   assert(handle->type == UV_POLL);
491   assert(!(handle->flags & UV_HANDLE_CLOSING));
492   assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
493                      UV_PRIORITIZED)) == 0);
494 
495   handle->events = events;
496   handle->poll_cb = cb;
497 
498   if (handle->events == 0) {
499     uv__handle_stop(handle);
500     return 0;
501   }
502 
503   uv__handle_start(handle);
504   submitted_events = handle->submitted_events_1 | handle->submitted_events_2;
505 
506   if (handle->events & ~submitted_events) {
507     if (handle->flags & UV_HANDLE_POLL_SLOW) {
508       uv__slow_poll_submit_poll_req(handle->loop, handle);
509     } else {
510       uv__fast_poll_submit_poll_req(handle->loop, handle);
511     }
512   }
513 
514   return 0;
515 }
516 
517 
uv_poll_start(uv_poll_t * handle,int events,uv_poll_cb cb)518 int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
519   return uv__poll_set(handle, events, cb);
520 }
521 
522 
uv_poll_stop(uv_poll_t * handle)523 int uv_poll_stop(uv_poll_t* handle) {
524   return uv__poll_set(handle, 0, handle->poll_cb);
525 }
526 
527 
uv__process_poll_req(uv_loop_t * loop,uv_poll_t * handle,uv_req_t * req)528 void uv__process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
529   if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
530     uv__fast_poll_process_poll_req(loop, handle, req);
531   } else {
532     uv__slow_poll_process_poll_req(loop, handle, req);
533   }
534 }
535 
536 
uv__poll_close(uv_loop_t * loop,uv_poll_t * handle)537 int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle) {
538   AFD_POLL_INFO afd_poll_info;
539   DWORD error;
540   int result;
541 
542   handle->events = 0;
543   uv__handle_closing(handle);
544 
545   if (handle->submitted_events_1 == 0 &&
546       handle->submitted_events_2 == 0) {
547     uv__want_endgame(loop, (uv_handle_t*) handle);
548     return 0;
549   }
550 
551   if (handle->flags & UV_HANDLE_POLL_SLOW)
552     return 0;
553 
554   /* Cancel outstanding poll requests by executing another, unique poll
555    * request that forces the outstanding ones to return. */
556   afd_poll_info.Exclusive = TRUE;
557   afd_poll_info.NumberOfHandles = 1;
558   afd_poll_info.Timeout.QuadPart = INT64_MAX;
559   afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
560   afd_poll_info.Handles[0].Status = 0;
561   afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
562 
563   result = uv__msafd_poll(handle->socket,
564                           &afd_poll_info,
565                           uv__get_afd_poll_info_dummy(),
566                           uv__get_overlapped_dummy());
567 
568   if (result == SOCKET_ERROR) {
569     error = WSAGetLastError();
570     if (error != WSA_IO_PENDING)
571       return uv_translate_sys_error(error);
572   }
573 
574   return 0;
575 }
576 
577 
uv__poll_endgame(uv_loop_t * loop,uv_poll_t * handle)578 void uv__poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
579   assert(handle->flags & UV_HANDLE_CLOSING);
580   assert(!(handle->flags & UV_HANDLE_CLOSED));
581 
582   assert(handle->submitted_events_1 == 0);
583   assert(handle->submitted_events_2 == 0);
584 
585   uv__handle_close(handle);
586 }
587