Merge remote-tracking branch ry/v0.10 into master
[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 #if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
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   loop->last_tick_count = 0;
94   uv_update_time(loop);
95
96   QUEUE_INIT(&loop->handle_queue);
97   QUEUE_INIT(&loop->active_reqs);
98   loop->active_handles = 0;
99
100   loop->pending_reqs_tail = NULL;
101
102   loop->endgame_handles = NULL;
103
104   RB_INIT(&loop->timers);
105
106   loop->check_handles = NULL;
107   loop->prepare_handles = NULL;
108   loop->idle_handles = NULL;
109
110   loop->next_prepare_handle = NULL;
111   loop->next_check_handle = NULL;
112   loop->next_idle_handle = NULL;
113
114   memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
115
116   loop->active_tcp_streams = 0;
117   loop->active_udp_streams = 0;
118
119   loop->timer_counter = 0;
120   loop->stop_flag = 0;
121
122   loop->last_err = uv_ok_;
123 }
124
125
126 static void uv_default_loop_init(void) {
127   /* Initialize libuv itself first */
128   uv__once_init();
129
130   /* Initialize the main loop */
131   uv_loop_init(&uv_default_loop_);
132 }
133
134
135 void uv__once_init(void) {
136   uv_once(&uv_init_guard_, uv_init);
137 }
138
139
140 uv_loop_t* uv_default_loop(void) {
141   uv_once(&uv_default_loop_init_guard_, uv_default_loop_init);
142   return &uv_default_loop_;
143 }
144
145
146 uv_loop_t* uv_loop_new(void) {
147   uv_loop_t* loop;
148
149   /* Initialize libuv itself first */
150   uv__once_init();
151
152   loop = (uv_loop_t*)malloc(sizeof(uv_loop_t));
153
154   if (!loop) {
155     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
156   }
157
158   uv_loop_init(loop);
159   return loop;
160 }
161
162
163 void uv_loop_delete(uv_loop_t* loop) {
164   if (loop != &uv_default_loop_) {
165     int i;
166     for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
167       SOCKET sock = loop->poll_peer_sockets[i];
168       if (sock != 0 && sock != INVALID_SOCKET) {
169         closesocket(sock);
170       }
171     }
172
173     free(loop);
174   }
175 }
176
177
178 int uv_backend_fd(const uv_loop_t* loop) {
179   return -1;
180 }
181
182
183 int uv_backend_timeout(const uv_loop_t* loop) {
184   return 0;
185 }
186
187
188 static void uv_poll(uv_loop_t* loop, int block) {
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   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     uv_insert_pending_req(loop, req);
210   } else if (GetLastError() != WAIT_TIMEOUT) {
211     /* Serious error */
212     uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
213   } else {
214     /* We're sure that at least `timeout` milliseconds have expired, but */
215     /* this may not be reflected yet in the GetTickCount() return value. */
216     /* Therefore we ensure it's taken into account here. */
217     uv__time_forward(loop, timeout);
218   }
219 }
220
221
222 static void uv_poll_ex(uv_loop_t* loop, int block) {
223   BOOL success;
224   DWORD timeout;
225   uv_req_t* req;
226   OVERLAPPED_ENTRY overlappeds[128];
227   ULONG count;
228   ULONG i;
229
230   if (block) {
231     timeout = uv_get_poll_timeout(loop);
232   } else {
233     timeout = 0;
234   }
235
236   success = pGetQueuedCompletionStatusEx(loop->iocp,
237                                          overlappeds,
238                                          ARRAY_SIZE(overlappeds),
239                                          &count,
240                                          timeout,
241                                          FALSE);
242
243   if (success) {
244     for (i = 0; i < count; i++) {
245       /* Package was dequeued */
246       req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
247       uv_insert_pending_req(loop, req);
248     }
249   } else if (GetLastError() != WAIT_TIMEOUT) {
250     /* Serious error */
251     uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
252   } else if (timeout > 0) {
253     /* We're sure that at least `timeout` milliseconds have expired, but */
254     /* this may not be reflected yet in the GetTickCount() return value. */
255     /* Therefore we ensure it's taken into account here. */
256     uv__time_forward(loop, timeout);
257   }
258 }
259
260
261 static int uv__loop_alive(uv_loop_t* loop) {
262   return loop->active_handles > 0 ||
263          !QUEUE_EMPTY(&loop->active_reqs) ||
264          loop->endgame_handles != NULL;
265 }
266
267
268 int uv_run(uv_loop_t *loop, uv_run_mode mode) {
269   int r;
270   void (*poll)(uv_loop_t* loop, int block);
271
272   if (pGetQueuedCompletionStatusEx)
273     poll = &uv_poll_ex;
274   else
275     poll = &uv_poll;
276
277   if (!uv__loop_alive(loop))
278     return 0;
279
280   r = uv__loop_alive(loop);
281   while (r != 0 && loop->stop_flag == 0) {
282     uv_update_time(loop);
283     uv_process_timers(loop);
284
285     /* Call idle callbacks if nothing to do. */
286     if (loop->pending_reqs_tail == NULL &&
287         loop->endgame_handles == NULL) {
288       uv_idle_invoke(loop);
289     }
290
291     uv_process_reqs(loop);
292     uv_process_endgames(loop);
293
294     uv_prepare_invoke(loop);
295
296     (*poll)(loop, loop->idle_handles == NULL &&
297                   loop->pending_reqs_tail == NULL &&
298                   loop->endgame_handles == NULL &&
299                   !loop->stop_flag &&
300                   (loop->active_handles > 0 ||
301                    !QUEUE_EMPTY(&loop->active_reqs)) &&
302                   !(mode & UV_RUN_NOWAIT));
303
304     uv_check_invoke(loop);
305     r = uv__loop_alive(loop);
306     if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
307       break;
308   }
309
310   /* The if statement lets the compiler compile it to a conditional store.
311    * Avoids dirtying a cache line.
312    */
313   if (loop->stop_flag != 0)
314     loop->stop_flag = 0;
315
316   return r;
317 }