e53a0f8e28637a58ceec7852d1a79874fc1a9548
[platform/upstream/cmake.git] / Utilities / cmlibuv / 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 <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
29 #include <crtdbg.h>
30 #endif
31
32 #include "uv.h"
33 #include "internal.h"
34 #include "queue.h"
35 #include "handle-inl.h"
36 #include "heap-inl.h"
37 #include "req-inl.h"
38
39 /* uv_once initialization guards */
40 static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
41
42
43 #if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
44 /* Our crt debug report handler allows us to temporarily disable asserts
45  * just for the current thread.
46  */
47
48 UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
49
50 static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
51   if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
52     return FALSE;
53
54   if (ret_val) {
55     /* Set ret_val to 0 to continue with normal execution.
56      * Set ret_val to 1 to trigger a breakpoint.
57     */
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 #else
69 UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
70 #endif
71
72
73 #if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
74 static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
75     const wchar_t* function, const wchar_t * file, unsigned int line,
76     uintptr_t reserved) {
77   /* No-op. */
78 }
79 #endif
80
81 static uv_loop_t** uv__loops;
82 static int uv__loops_size;
83 static int uv__loops_capacity;
84 #define UV__LOOPS_CHUNK_SIZE 8
85 static uv_mutex_t uv__loops_lock;
86
87 static void uv__loops_init(void) {
88   uv_mutex_init(&uv__loops_lock);
89 }
90
91 static int uv__loops_add(uv_loop_t* loop) {
92   uv_loop_t** new_loops;
93   int new_capacity, i;
94
95   uv_mutex_lock(&uv__loops_lock);
96
97   if (uv__loops_size == uv__loops_capacity) {
98     new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
99     new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
100     if (!new_loops)
101       goto failed_loops_realloc;
102     uv__loops = new_loops;
103     for (i = uv__loops_capacity; i < new_capacity; ++i)
104       uv__loops[i] = NULL;
105     uv__loops_capacity = new_capacity;
106   }
107   uv__loops[uv__loops_size] = loop;
108   ++uv__loops_size;
109
110   uv_mutex_unlock(&uv__loops_lock);
111   return 0;
112
113 failed_loops_realloc:
114   uv_mutex_unlock(&uv__loops_lock);
115   return ERROR_OUTOFMEMORY;
116 }
117
118 static void uv__loops_remove(uv_loop_t* loop) {
119   int loop_index;
120   int smaller_capacity;
121   uv_loop_t** new_loops;
122
123   uv_mutex_lock(&uv__loops_lock);
124
125   for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
126     if (uv__loops[loop_index] == loop)
127       break;
128   }
129   /* If loop was not found, ignore */
130   if (loop_index == uv__loops_size)
131     goto loop_removed;
132
133   uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
134   uv__loops[uv__loops_size - 1] = NULL;
135   --uv__loops_size;
136
137   if (uv__loops_size == 0) {
138     uv__loops_capacity = 0;
139     uv__free(uv__loops);
140     uv__loops = NULL;
141     goto loop_removed;
142   }
143
144   /* If we didn't grow to big skip downsizing */
145   if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
146     goto loop_removed;
147
148   /* Downsize only if more than half of buffer is free */
149   smaller_capacity = uv__loops_capacity / 2;
150   if (uv__loops_size >= smaller_capacity)
151     goto loop_removed;
152   new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
153   if (!new_loops)
154     goto loop_removed;
155   uv__loops = new_loops;
156   uv__loops_capacity = smaller_capacity;
157
158 loop_removed:
159   uv_mutex_unlock(&uv__loops_lock);
160 }
161
162 void uv__wake_all_loops(void) {
163   int i;
164   uv_loop_t* loop;
165
166   uv_mutex_lock(&uv__loops_lock);
167   for (i = 0; i < uv__loops_size; ++i) {
168     loop = uv__loops[i];
169     assert(loop);
170     if (loop->iocp != INVALID_HANDLE_VALUE)
171       PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
172   }
173   uv_mutex_unlock(&uv__loops_lock);
174 }
175
176 static void uv_init(void) {
177   /* Tell Windows that we will handle critical errors. */
178   SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
179                SEM_NOOPENFILEERRORBOX);
180
181   /* Tell the CRT to not exit the application when an invalid parameter is
182    * passed. The main issue is that invalid FDs will trigger this behavior.
183    */
184 #if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
185   _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
186 #endif
187
188   /* We also need to setup our debug report handler because some CRT
189    * functions (eg _get_osfhandle) raise an assert when called with invalid
190    * FDs even though they return the proper error code in the release build.
191    */
192 #if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
193   _CrtSetReportHook(uv__crt_dbg_report_handler);
194 #endif
195
196   /* Initialize tracking of all uv loops */
197   uv__loops_init();
198
199   /* Fetch winapi function pointers. This must be done first because other
200    * initialization code might need these function pointers to be loaded.
201    */
202   uv_winapi_init();
203
204   /* Initialize winsock */
205   uv_winsock_init();
206
207   /* Initialize FS */
208   uv_fs_init();
209
210   /* Initialize signal stuff */
211   uv_signals_init();
212
213   /* Initialize console */
214   uv_console_init();
215
216   /* Initialize utilities */
217   uv__util_init();
218
219   /* Initialize system wakeup detection */
220   uv__init_detect_system_wakeup();
221 }
222
223
224 int uv_loop_init(uv_loop_t* loop) {
225   uv__loop_internal_fields_t* lfields;
226   struct heap* timer_heap;
227   int err;
228
229   /* Initialize libuv itself first */
230   uv__once_init();
231
232   /* Create an I/O completion port */
233   loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
234   if (loop->iocp == NULL)
235     return uv_translate_sys_error(GetLastError());
236
237   lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
238   if (lfields == NULL)
239     return UV_ENOMEM;
240   loop->internal_fields = lfields;
241
242   err = uv_mutex_init(&lfields->loop_metrics.lock);
243   if (err)
244     goto fail_metrics_mutex_init;
245
246   /* To prevent uninitialized memory access, loop->time must be initialized
247    * to zero before calling uv_update_time for the first time.
248    */
249   loop->time = 0;
250   uv_update_time(loop);
251
252   QUEUE_INIT(&loop->wq);
253   QUEUE_INIT(&loop->handle_queue);
254   loop->active_reqs.count = 0;
255   loop->active_handles = 0;
256
257   loop->pending_reqs_tail = NULL;
258
259   loop->endgame_handles = NULL;
260
261   loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap));
262   if (timer_heap == NULL) {
263     err = UV_ENOMEM;
264     goto fail_timers_alloc;
265   }
266
267   heap_init(timer_heap);
268
269   loop->check_handles = NULL;
270   loop->prepare_handles = NULL;
271   loop->idle_handles = NULL;
272
273   loop->next_prepare_handle = NULL;
274   loop->next_check_handle = NULL;
275   loop->next_idle_handle = NULL;
276
277   memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
278
279   loop->active_tcp_streams = 0;
280   loop->active_udp_streams = 0;
281
282   loop->timer_counter = 0;
283   loop->stop_flag = 0;
284
285   err = uv_mutex_init(&loop->wq_mutex);
286   if (err)
287     goto fail_mutex_init;
288
289   err = uv_async_init(loop, &loop->wq_async, uv__work_done);
290   if (err)
291     goto fail_async_init;
292
293   uv__handle_unref(&loop->wq_async);
294   loop->wq_async.flags |= UV_HANDLE_INTERNAL;
295
296   err = uv__loops_add(loop);
297   if (err)
298     goto fail_async_init;
299
300   return 0;
301
302 fail_async_init:
303   uv_mutex_destroy(&loop->wq_mutex);
304
305 fail_mutex_init:
306   uv__free(timer_heap);
307   loop->timer_heap = NULL;
308
309 fail_timers_alloc:
310   uv_mutex_destroy(&lfields->loop_metrics.lock);
311
312 fail_metrics_mutex_init:
313   uv__free(lfields);
314   loop->internal_fields = NULL;
315   CloseHandle(loop->iocp);
316   loop->iocp = INVALID_HANDLE_VALUE;
317
318   return err;
319 }
320
321
322 void uv_update_time(uv_loop_t* loop) {
323   uint64_t new_time = uv__hrtime(1000);
324   assert(new_time >= loop->time);
325   loop->time = new_time;
326 }
327
328
329 void uv__once_init(void) {
330   uv_once(&uv_init_guard_, uv_init);
331 }
332
333
334 void uv__loop_close(uv_loop_t* loop) {
335   uv__loop_internal_fields_t* lfields;
336   size_t i;
337
338   uv__loops_remove(loop);
339
340   /* Close the async handle without needing an extra loop iteration.
341    * We might have a pending message, but we're just going to destroy the IOCP
342    * soon, so we can just discard it now without the usual risk of a getting
343    * another notification from GetQueuedCompletionStatusEx after calling the
344    * close_cb (which we also skip defining). We'll assert later that queue was
345    * actually empty and all reqs handled. */
346   loop->wq_async.async_sent = 0;
347   loop->wq_async.close_cb = NULL;
348   uv__handle_closing(&loop->wq_async);
349   uv__handle_close(&loop->wq_async);
350
351   for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
352     SOCKET sock = loop->poll_peer_sockets[i];
353     if (sock != 0 && sock != INVALID_SOCKET)
354       closesocket(sock);
355   }
356
357   uv_mutex_lock(&loop->wq_mutex);
358   assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
359   assert(!uv__has_active_reqs(loop));
360   uv_mutex_unlock(&loop->wq_mutex);
361   uv_mutex_destroy(&loop->wq_mutex);
362
363   uv__free(loop->timer_heap);
364   loop->timer_heap = NULL;
365
366   lfields = uv__get_internal_fields(loop);
367   uv_mutex_destroy(&lfields->loop_metrics.lock);
368   uv__free(lfields);
369   loop->internal_fields = NULL;
370
371   CloseHandle(loop->iocp);
372 }
373
374
375 int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
376   uv__loop_internal_fields_t* lfields;
377
378   lfields = uv__get_internal_fields(loop);
379   if (option == UV_METRICS_IDLE_TIME) {
380     lfields->flags |= UV_METRICS_IDLE_TIME;
381     return 0;
382   }
383
384   return UV_ENOSYS;
385 }
386
387
388 int uv_backend_fd(const uv_loop_t* loop) {
389   return -1;
390 }
391
392
393 int uv_loop_fork(uv_loop_t* loop) {
394   return UV_ENOSYS;
395 }
396
397
398 int uv_backend_timeout(const uv_loop_t* loop) {
399   if (loop->stop_flag != 0)
400     return 0;
401
402   if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
403     return 0;
404
405   if (loop->pending_reqs_tail)
406     return 0;
407
408   if (loop->endgame_handles)
409     return 0;
410
411   if (loop->idle_handles)
412     return 0;
413
414   return uv__next_timeout(loop);
415 }
416
417
418 static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
419   DWORD bytes;
420   ULONG_PTR key;
421   OVERLAPPED* overlapped;
422   uv_req_t* req;
423   int repeat;
424   uint64_t timeout_time;
425   uint64_t user_timeout;
426   int reset_timeout;
427
428   timeout_time = loop->time + timeout;
429
430   if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
431     reset_timeout = 1;
432     user_timeout = timeout;
433     timeout = 0;
434   } else {
435     reset_timeout = 0;
436   }
437
438   for (repeat = 0; ; repeat++) {
439     /* Only need to set the provider_entry_time if timeout != 0. The function
440      * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
441      */
442     if (timeout != 0)
443       uv__metrics_set_provider_entry_time(loop);
444
445     GetQueuedCompletionStatus(loop->iocp,
446                               &bytes,
447                               &key,
448                               &overlapped,
449                               timeout);
450
451     if (reset_timeout != 0) {
452       timeout = user_timeout;
453       reset_timeout = 0;
454     }
455
456     /* Placed here because on success the loop will break whether there is an
457      * empty package or not, or if GetQueuedCompletionStatus returned early then
458      * the timeout will be updated and the loop will run again. In either case
459      * the idle time will need to be updated.
460      */
461     uv__metrics_update_idle_time(loop);
462
463     if (overlapped) {
464       /* Package was dequeued */
465       req = uv_overlapped_to_req(overlapped);
466       uv_insert_pending_req(loop, req);
467
468       /* Some time might have passed waiting for I/O,
469        * so update the loop time here.
470        */
471       uv_update_time(loop);
472     } else if (GetLastError() != WAIT_TIMEOUT) {
473       /* Serious error */
474       uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
475     } else if (timeout > 0) {
476       /* GetQueuedCompletionStatus can occasionally return a little early.
477        * Make sure that the desired timeout target time is reached.
478        */
479       uv_update_time(loop);
480       if (timeout_time > loop->time) {
481         timeout = (DWORD)(timeout_time - loop->time);
482         /* The first call to GetQueuedCompletionStatus should return very
483          * close to the target time and the second should reach it, but
484          * this is not stated in the documentation. To make sure a busy
485          * loop cannot happen, the timeout is increased exponentially
486          * starting on the third round.
487          */
488         timeout += repeat ? (1 << (repeat - 1)) : 0;
489         continue;
490       }
491     }
492     break;
493   }
494 }
495
496
497 static void uv__poll(uv_loop_t* loop, DWORD timeout) {
498   BOOL success;
499   uv_req_t* req;
500   OVERLAPPED_ENTRY overlappeds[128];
501   ULONG count;
502   ULONG i;
503   int repeat;
504   uint64_t timeout_time;
505   uint64_t user_timeout;
506   int reset_timeout;
507
508   timeout_time = loop->time + timeout;
509
510   if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
511     reset_timeout = 1;
512     user_timeout = timeout;
513     timeout = 0;
514   } else {
515     reset_timeout = 0;
516   }
517
518   for (repeat = 0; ; repeat++) {
519     /* Only need to set the provider_entry_time if timeout != 0. The function
520      * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
521      */
522     if (timeout != 0)
523       uv__metrics_set_provider_entry_time(loop);
524
525     success = pGetQueuedCompletionStatusEx(loop->iocp,
526                                            overlappeds,
527                                            ARRAY_SIZE(overlappeds),
528                                            &count,
529                                            timeout,
530                                            FALSE);
531
532     if (reset_timeout != 0) {
533       timeout = user_timeout;
534       reset_timeout = 0;
535     }
536
537     /* Placed here because on success the loop will break whether there is an
538      * empty package or not, or if GetQueuedCompletionStatus returned early then
539      * the timeout will be updated and the loop will run again. In either case
540      * the idle time will need to be updated.
541      */
542     uv__metrics_update_idle_time(loop);
543
544     if (success) {
545       for (i = 0; i < count; i++) {
546         /* Package was dequeued, but see if it is not a empty package
547          * meant only to wake us up.
548          */
549         if (overlappeds[i].lpOverlapped) {
550           req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
551           uv_insert_pending_req(loop, req);
552         }
553       }
554
555       /* Some time might have passed waiting for I/O,
556        * so update the loop time here.
557        */
558       uv_update_time(loop);
559     } else if (GetLastError() != WAIT_TIMEOUT) {
560       /* Serious error */
561       uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
562     } else if (timeout > 0) {
563       /* GetQueuedCompletionStatus can occasionally return a little early.
564        * Make sure that the desired timeout target time is reached.
565        */
566       uv_update_time(loop);
567       if (timeout_time > loop->time) {
568         timeout = (DWORD)(timeout_time - loop->time);
569         /* The first call to GetQueuedCompletionStatus should return very
570          * close to the target time and the second should reach it, but
571          * this is not stated in the documentation. To make sure a busy
572          * loop cannot happen, the timeout is increased exponentially
573          * starting on the third round.
574          */
575         timeout += repeat ? (1 << (repeat - 1)) : 0;
576         continue;
577       }
578     }
579     break;
580   }
581 }
582
583
584 static int uv__loop_alive(const uv_loop_t* loop) {
585   return uv__has_active_handles(loop) ||
586          uv__has_active_reqs(loop) ||
587          loop->endgame_handles != NULL;
588 }
589
590
591 int uv_loop_alive(const uv_loop_t* loop) {
592     return uv__loop_alive(loop);
593 }
594
595
596 int uv_run(uv_loop_t *loop, uv_run_mode mode) {
597   DWORD timeout;
598   int r;
599   int ran_pending;
600
601   r = uv__loop_alive(loop);
602   if (!r)
603     uv_update_time(loop);
604
605   while (r != 0 && loop->stop_flag == 0) {
606     uv_update_time(loop);
607     uv__run_timers(loop);
608
609     ran_pending = uv_process_reqs(loop);
610     uv_idle_invoke(loop);
611     uv_prepare_invoke(loop);
612
613     timeout = 0;
614     if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
615       timeout = uv_backend_timeout(loop);
616
617     if (pGetQueuedCompletionStatusEx)
618       uv__poll(loop, timeout);
619     else
620       uv__poll_wine(loop, timeout);
621
622     /* Run one final update on the provider_idle_time in case uv__poll*
623      * returned because the timeout expired, but no events were received. This
624      * call will be ignored if the provider_entry_time was either never set (if
625      * the timeout == 0) or was already updated b/c an event was received.
626      */
627     uv__metrics_update_idle_time(loop);
628
629     uv_check_invoke(loop);
630     uv_process_endgames(loop);
631
632     if (mode == UV_RUN_ONCE) {
633       /* UV_RUN_ONCE implies forward progress: at least one callback must have
634        * been invoked when it returns. uv__io_poll() can return without doing
635        * I/O (meaning: no callbacks) when its timeout expires - which means we
636        * have pending timers that satisfy the forward progress constraint.
637        *
638        * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
639        * the check.
640        */
641       uv__run_timers(loop);
642     }
643
644     r = uv__loop_alive(loop);
645     if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
646       break;
647   }
648
649   /* The if statement lets the compiler compile it to a conditional store.
650    * Avoids dirtying a cache line.
651    */
652   if (loop->stop_flag != 0)
653     loop->stop_flag = 0;
654
655   return r;
656 }
657
658
659 int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
660   uv_os_fd_t fd_out;
661
662   switch (handle->type) {
663   case UV_TCP:
664     fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
665     break;
666
667   case UV_NAMED_PIPE:
668     fd_out = ((uv_pipe_t*) handle)->handle;
669     break;
670
671   case UV_TTY:
672     fd_out = ((uv_tty_t*) handle)->handle;
673     break;
674
675   case UV_UDP:
676     fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
677     break;
678
679   case UV_POLL:
680     fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
681     break;
682
683   default:
684     return UV_EINVAL;
685   }
686
687   if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
688     return UV_EBADF;
689
690   *fd = fd_out;
691   return 0;
692 }
693
694
695 int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
696   int r;
697   int len;
698   SOCKET socket;
699
700   if (handle == NULL || value == NULL)
701     return UV_EINVAL;
702
703   if (handle->type == UV_TCP)
704     socket = ((uv_tcp_t*) handle)->socket;
705   else if (handle->type == UV_UDP)
706     socket = ((uv_udp_t*) handle)->socket;
707   else
708     return UV_ENOTSUP;
709
710   len = sizeof(*value);
711
712   if (*value == 0)
713     r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
714   else
715     r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
716
717   if (r == SOCKET_ERROR)
718     return uv_translate_sys_error(WSAGetLastError());
719
720   return 0;
721 }
722
723 int uv_cpumask_size(void) {
724   return (int)(sizeof(DWORD_PTR) * 8);
725 }
726
727 int uv__getsockpeername(const uv_handle_t* handle,
728                         uv__peersockfunc func,
729                         struct sockaddr* name,
730                         int* namelen,
731                         int delayed_error) {
732
733   int result;
734   uv_os_fd_t fd;
735
736   result = uv_fileno(handle, &fd);
737   if (result != 0)
738     return result;
739
740   if (delayed_error)
741     return uv_translate_sys_error(delayed_error);
742
743   result = func((SOCKET) fd, name, namelen);
744   if (result != 0)
745     return uv_translate_sys_error(WSAGetLastError());
746
747   return 0;
748 }