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 <errno.h>
24 #include <limits.h>
25 #include <malloc.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <crtdbg.h>
30 
31 #include "uv.h"
32 #include "internal.h"
33 #include "handle-inl.h"
34 #include "req-inl.h"
35 
36 
37 /* The only event loop we support right now */
38 static uv_loop_t uv_default_loop_;
39 
40 /* uv_once intialization guards */
41 static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
42 static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;
43 
44 
45 #ifdef _DEBUG
46 /* Our crt debug report handler allows us to temporarily disable asserts */
47 /* just for the current thread. */
48 
49 __declspec( thread ) int uv__crt_assert_enabled = TRUE;
50 
uv__crt_dbg_report_handler(int report_type,char * message,int * ret_val)51 static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
52   if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
53     return FALSE;
54 
55   if (ret_val) {
56     /* Set ret_val to 0 to continue with normal execution. */
57     /* Set ret_val to 1 to trigger a breakpoint. */
58 
59     if(IsDebuggerPresent())
60       *ret_val = 1;
61     else
62       *ret_val = 0;
63   }
64 
65   /* Don't call _CrtDbgReport. */
66   return TRUE;
67 }
68 #endif
69 
70 
uv__crt_invalid_parameter_handler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t reserved)71 static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
72     const wchar_t* function, const wchar_t * file, unsigned int line,
73     uintptr_t reserved) {
74   /* No-op. */
75 }
76 
77 
uv_init(void)78 static void uv_init(void) {
79   /* Tell Windows that we will handle critical errors. */
80   SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
81                SEM_NOOPENFILEERRORBOX);
82 
83   /* Tell the CRT to not exit the application when an invalid parameter is */
84   /* passed. The main issue is that invalid FDs will trigger this behavior. */
85 #if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
86   _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
87 #endif
88 
89   /* We also need to setup our debug report handler because some CRT */
90   /* functions (eg _get_osfhandle) raise an assert when called with invalid */
91   /* FDs even though they return the proper error code in the release build. */
92 #ifdef _DEBUG
93   _CrtSetReportHook(uv__crt_dbg_report_handler);
94 #endif
95 
96   /* Fetch winapi function pointers. This must be done first because other */
97   /* intialization code might need these function pointers to be loaded. */
98   uv_winapi_init();
99 
100   /* Initialize winsock */
101   uv_winsock_init();
102 
103   /* Initialize FS */
104   uv_fs_init();
105 
106   /* Initialize signal stuff */
107   uv_signals_init();
108 
109   /* Initialize console */
110   uv_console_init();
111 
112   /* Initialize utilities */
113   uv__util_init();
114 }
115 
116 
uv_loop_init(uv_loop_t * loop)117 static void uv_loop_init(uv_loop_t* loop) {
118   /* Create an I/O completion port */
119   loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
120   if (loop->iocp == NULL) {
121     uv_fatal_error(GetLastError(), "CreateIoCompletionPort");
122   }
123 
124   /* To prevent uninitialized memory access, loop->time must be intialized */
125   /* to zero before calling uv_update_time for the first time. */
126   loop->time = 0;
127   loop->last_tick_count = 0;
128   uv_update_time(loop);
129 
130   QUEUE_INIT(&loop->handle_queue);
131   QUEUE_INIT(&loop->active_reqs);
132   loop->active_handles = 0;
133 
134   loop->pending_reqs_tail = NULL;
135 
136   loop->endgame_handles = NULL;
137 
138   RB_INIT(&loop->timers);
139 
140   loop->check_handles = NULL;
141   loop->prepare_handles = NULL;
142   loop->idle_handles = NULL;
143 
144   loop->next_prepare_handle = NULL;
145   loop->next_check_handle = NULL;
146   loop->next_idle_handle = NULL;
147 
148   memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
149 
150   loop->active_tcp_streams = 0;
151   loop->active_udp_streams = 0;
152 
153   loop->timer_counter = 0;
154   loop->stop_flag = 0;
155 }
156 
157 
uv_default_loop_init(void)158 static void uv_default_loop_init(void) {
159   /* Initialize libuv itself first */
160   uv__once_init();
161 
162   /* Initialize the main loop */
163   uv_loop_init(&uv_default_loop_);
164 }
165 
166 
uv__once_init(void)167 void uv__once_init(void) {
168   uv_once(&uv_init_guard_, uv_init);
169 }
170 
171 
uv_default_loop(void)172 uv_loop_t* uv_default_loop(void) {
173   uv_once(&uv_default_loop_init_guard_, uv_default_loop_init);
174   return &uv_default_loop_;
175 }
176 
177 
uv_loop_new(void)178 uv_loop_t* uv_loop_new(void) {
179   uv_loop_t* loop;
180 
181   /* Initialize libuv itself first */
182   uv__once_init();
183 
184   loop = (uv_loop_t*)malloc(sizeof(uv_loop_t));
185 
186   if (!loop) {
187     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
188   }
189 
190   uv_loop_init(loop);
191   return loop;
192 }
193 
194 
uv_loop_delete(uv_loop_t * loop)195 void uv_loop_delete(uv_loop_t* loop) {
196   if (loop != &uv_default_loop_) {
197     int i;
198     for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
199       SOCKET sock = loop->poll_peer_sockets[i];
200       if (sock != 0 && sock != INVALID_SOCKET) {
201         closesocket(sock);
202       }
203     }
204 
205     free(loop);
206   }
207 }
208 
209 
uv_backend_fd(const uv_loop_t * loop)210 int uv_backend_fd(const uv_loop_t* loop) {
211   return -1;
212 }
213 
214 
uv_backend_timeout(const uv_loop_t * loop)215 int uv_backend_timeout(const uv_loop_t* loop) {
216   return 0;
217 }
218 
219 
uv_poll(uv_loop_t * loop,int block)220 static void uv_poll(uv_loop_t* loop, int block) {
221   DWORD bytes, timeout;
222   ULONG_PTR key;
223   OVERLAPPED* overlapped;
224   uv_req_t* req;
225 
226   if (block) {
227     timeout = uv_get_poll_timeout(loop);
228   } else {
229     timeout = 0;
230   }
231 
232   GetQueuedCompletionStatus(loop->iocp,
233                             &bytes,
234                             &key,
235                             &overlapped,
236                             timeout);
237 
238   if (overlapped) {
239     /* Package was dequeued */
240     req = uv_overlapped_to_req(overlapped);
241     uv_insert_pending_req(loop, req);
242   } else if (GetLastError() != WAIT_TIMEOUT) {
243     /* Serious error */
244     uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
245   } else {
246     /* We're sure that at least `timeout` milliseconds have expired, but */
247     /* this may not be reflected yet in the GetTickCount() return value. */
248     /* Therefore we ensure it's taken into account here. */
249     uv__time_forward(loop, timeout);
250   }
251 }
252 
253 
uv_poll_ex(uv_loop_t * loop,int block)254 static void uv_poll_ex(uv_loop_t* loop, int block) {
255   BOOL success;
256   DWORD timeout;
257   uv_req_t* req;
258   OVERLAPPED_ENTRY overlappeds[128];
259   ULONG count;
260   ULONG i;
261 
262   if (block) {
263     timeout = uv_get_poll_timeout(loop);
264   } else {
265     timeout = 0;
266   }
267 
268   success = pGetQueuedCompletionStatusEx(loop->iocp,
269                                          overlappeds,
270                                          ARRAY_SIZE(overlappeds),
271                                          &count,
272                                          timeout,
273                                          FALSE);
274 
275   if (success) {
276     for (i = 0; i < count; i++) {
277       /* Package was dequeued */
278       req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
279       uv_insert_pending_req(loop, req);
280     }
281   } else if (GetLastError() != WAIT_TIMEOUT) {
282     /* Serious error */
283     uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
284   } else if (timeout > 0) {
285     /* We're sure that at least `timeout` milliseconds have expired, but */
286     /* this may not be reflected yet in the GetTickCount() return value. */
287     /* Therefore we ensure it's taken into account here. */
288     uv__time_forward(loop, timeout);
289   }
290 }
291 
292 
uv__loop_alive(const uv_loop_t * loop)293 static int uv__loop_alive(const uv_loop_t* loop) {
294   return loop->active_handles > 0 ||
295          !QUEUE_EMPTY(&loop->active_reqs) ||
296          loop->endgame_handles != NULL;
297 }
298 
299 
uv_loop_alive(const uv_loop_t * loop)300 int uv_loop_alive(const uv_loop_t* loop) {
301     return uv__loop_alive(loop);
302 }
303 
304 
uv_run(uv_loop_t * loop,uv_run_mode mode)305 int uv_run(uv_loop_t *loop, uv_run_mode mode) {
306   int r;
307   void (*poll)(uv_loop_t* loop, int block);
308 
309   if (pGetQueuedCompletionStatusEx)
310     poll = &uv_poll_ex;
311   else
312     poll = &uv_poll;
313 
314   r = uv__loop_alive(loop);
315   if (!r)
316     uv_update_time(loop);
317 
318   while (r != 0 && loop->stop_flag == 0) {
319     uv_update_time(loop);
320     uv_process_timers(loop);
321 
322     uv_process_reqs(loop);
323     uv_idle_invoke(loop);
324     uv_prepare_invoke(loop);
325 
326     (*poll)(loop, loop->idle_handles == NULL &&
327                   loop->pending_reqs_tail == NULL &&
328                   loop->endgame_handles == NULL &&
329                   !loop->stop_flag &&
330                   (loop->active_handles > 0 ||
331                    !QUEUE_EMPTY(&loop->active_reqs)) &&
332                   !(mode & UV_RUN_NOWAIT));
333 
334     uv_check_invoke(loop);
335     uv_process_endgames(loop);
336 
337     if (mode == UV_RUN_ONCE) {
338       /* UV_RUN_ONCE implies forward progess: at least one callback must have
339        * been invoked when it returns. uv__io_poll() can return without doing
340        * I/O (meaning: no callbacks) when its timeout expires - which means we
341        * have pending timers that satisfy the forward progress constraint.
342        *
343        * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
344        * the check.
345        */
346       uv_update_time(loop);
347       uv_process_timers(loop);
348     }
349 
350     r = uv__loop_alive(loop);
351     if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
352       break;
353   }
354 
355   /* The if statement lets the compiler compile it to a conditional store.
356    * Avoids dirtying a cache line.
357    */
358   if (loop->stop_flag != 0)
359     loop->stop_flag = 0;
360 
361   return r;
362 }
363