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