deps: upgrade libuv to a0c1d84
[platform/upstream/nodejs.git] / deps / uv / src / win / core.c
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
30 #include "uv.h"
31 #include "internal.h"
32 #include "handle-inl.h"
33 #include "req-inl.h"
34
35
36 /* The only event loop we support right now */
37 static uv_loop_t uv_default_loop_;
38
39 /* uv_once intialization guards */
40 static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
41 static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;
42
43
44 static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
45     const wchar_t* function, const wchar_t * file, unsigned int line,
46     uintptr_t reserved) {
47   /* No-op. */
48 }
49
50
51 static void uv_init(void) {
52   /* Tell Windows that we will handle critical errors. */
53   SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
54                SEM_NOOPENFILEERRORBOX);
55
56   /* Tell the CRT to not exit the application when an invalid parameter is */
57   /* passed. The main issue is that invalid FDs will trigger this behavior. */
58 #ifdef _WRITE_ABORT_MSG
59   _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
60 #endif
61
62   /* Fetch winapi function pointers. This must be done first because other */
63   /* intialization code might need these function pointers to be loaded. */
64   uv_winapi_init();
65
66   /* Initialize winsock */
67   uv_winsock_init();
68
69   /* Initialize FS */
70   uv_fs_init();
71
72   /* Initialize signal stuff */
73   uv_signals_init();
74
75   /* Initialize console */
76   uv_console_init();
77
78   /* Initialize utilities */
79   uv__util_init();
80 }
81
82
83 static void uv_loop_init(uv_loop_t* loop) {
84   /* Create an I/O completion port */
85   loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
86   if (loop->iocp == NULL) {
87     uv_fatal_error(GetLastError(), "CreateIoCompletionPort");
88   }
89
90   /* To prevent uninitialized memory access, loop->time must be intialized */
91   /* to zero before calling uv_update_time for the first time. */
92   loop->time = 0;
93   uv_update_time(loop);
94
95   ngx_queue_init(&loop->handle_queue);
96   ngx_queue_init(&loop->active_reqs);
97   loop->active_handles = 0;
98
99   loop->pending_reqs_tail = NULL;
100
101   loop->endgame_handles = NULL;
102
103   RB_INIT(&loop->timers);
104
105   loop->check_handles = NULL;
106   loop->prepare_handles = NULL;
107   loop->idle_handles = NULL;
108
109   loop->next_prepare_handle = NULL;
110   loop->next_check_handle = NULL;
111   loop->next_idle_handle = NULL;
112
113   memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
114
115   loop->active_tcp_streams = 0;
116   loop->active_udp_streams = 0;
117
118   loop->timer_counter = 0;
119   loop->stop_flag = 0;
120
121   loop->last_err = uv_ok_;
122 }
123
124
125 static void uv_default_loop_init(void) {
126   /* Initialize libuv itself first */
127   uv__once_init();
128
129   /* Initialize the main loop */
130   uv_loop_init(&uv_default_loop_);
131 }
132
133
134 void uv__once_init(void) {
135   uv_once(&uv_init_guard_, uv_init);
136 }
137
138
139 uv_loop_t* uv_default_loop(void) {
140   uv_once(&uv_default_loop_init_guard_, uv_default_loop_init);
141   return &uv_default_loop_;
142 }
143
144
145 uv_loop_t* uv_loop_new(void) {
146   uv_loop_t* loop;
147
148   /* Initialize libuv itself first */
149   uv__once_init();
150
151   loop = (uv_loop_t*)malloc(sizeof(uv_loop_t));
152
153   if (!loop) {
154     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
155   }
156
157   uv_loop_init(loop);
158   return loop;
159 }
160
161
162 void uv_loop_delete(uv_loop_t* loop) {
163   if (loop != &uv_default_loop_) {
164     int i;
165     for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
166       SOCKET sock = loop->poll_peer_sockets[i];
167       if (sock != 0 && sock != INVALID_SOCKET) {
168         closesocket(sock);
169       }
170     }
171
172     free(loop);
173   }
174 }
175
176
177 int uv_backend_fd(const uv_loop_t* loop) {
178   return -1;
179 }
180
181
182 int uv_backend_timeout(const uv_loop_t* loop) {
183   return 0;
184 }
185
186
187 static void uv_poll(uv_loop_t* loop, int block) {
188   BOOL success;
189   DWORD bytes, timeout;
190   ULONG_PTR key;
191   OVERLAPPED* overlapped;
192   uv_req_t* req;
193
194   if (block) {
195     timeout = uv_get_poll_timeout(loop);
196   } else {
197     timeout = 0;
198   }
199
200   success = GetQueuedCompletionStatus(loop->iocp,
201                                       &bytes,
202                                       &key,
203                                       &overlapped,
204                                       timeout);
205
206   if (overlapped) {
207     /* Package was dequeued */
208     req = uv_overlapped_to_req(overlapped);
209
210     uv_insert_pending_req(loop, req);
211
212   } else if (GetLastError() != WAIT_TIMEOUT) {
213     /* Serious error */
214     uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
215   }
216 }
217
218
219 static void uv_poll_ex(uv_loop_t* loop, int block) {
220   BOOL success;
221   DWORD timeout;
222   uv_req_t* req;
223   OVERLAPPED_ENTRY overlappeds[128];
224   ULONG count;
225   ULONG i;
226
227   if (block) {
228     timeout = uv_get_poll_timeout(loop);
229   } else {
230     timeout = 0;
231   }
232
233   assert(pGetQueuedCompletionStatusEx);
234
235   success = pGetQueuedCompletionStatusEx(loop->iocp,
236                                          overlappeds,
237                                          ARRAY_SIZE(overlappeds),
238                                          &count,
239                                          timeout,
240                                          FALSE);
241   if (success) {
242     for (i = 0; i < count; i++) {
243       /* Package was dequeued */
244       req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
245       uv_insert_pending_req(loop, req);
246     }
247   } else if (GetLastError() != WAIT_TIMEOUT) {
248     /* Serious error */
249     uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
250   }
251 }
252
253
254 static int uv__loop_alive(uv_loop_t* loop) {
255   return loop->active_handles > 0 ||
256          !ngx_queue_empty(&loop->active_reqs) ||
257          loop->endgame_handles != NULL;
258 }
259
260
261 int uv_run(uv_loop_t *loop, uv_run_mode mode) {
262   int r;
263   void (*poll)(uv_loop_t* loop, int block);
264
265   if (pGetQueuedCompletionStatusEx)
266     poll = &uv_poll_ex;
267   else
268     poll = &uv_poll;
269
270   if (!uv__loop_alive(loop))
271     return 0;
272
273   r = uv__loop_alive(loop);
274   while (r != 0 && loop->stop_flag == 0) {
275     uv_update_time(loop);
276     uv_process_timers(loop);
277
278     /* Call idle callbacks if nothing to do. */
279     if (loop->pending_reqs_tail == NULL &&
280         loop->endgame_handles == NULL) {
281       uv_idle_invoke(loop);
282     }
283
284     uv_process_reqs(loop);
285     uv_process_endgames(loop);
286
287     uv_prepare_invoke(loop);
288
289     (*poll)(loop, loop->idle_handles == NULL &&
290                   loop->pending_reqs_tail == NULL &&
291                   loop->endgame_handles == NULL &&
292                   !loop->stop_flag &&
293                   (loop->active_handles > 0 ||
294                    !ngx_queue_empty(&loop->active_reqs)) &&
295                   !(mode & UV_RUN_NOWAIT));
296
297     uv_check_invoke(loop);
298     r = uv__loop_alive(loop);
299     if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
300       break;
301   }
302
303   /* The if statement lets the compiler compile it to a conditional store.
304    * Avoids dirtying a cache line.
305    */
306   if (loop->stop_flag != 0)
307     loop->stop_flag = 0;
308
309   return r;
310 }