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