xref: /netbsd-src/external/mit/libuv/dist/src/uv-common.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
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 "uv.h"
23 #include "uv-common.h"
24 
25 #include <assert.h>
26 #include <errno.h>
27 #include <stdarg.h>
28 #include <stddef.h> /* NULL */
29 #include <stdio.h>
30 #include <stdlib.h> /* malloc */
31 #include <string.h> /* memset */
32 
33 #if defined(_WIN32)
34 # include <malloc.h> /* malloc */
35 #else
36 # include <net/if.h> /* if_nametoindex */
37 # include <sys/un.h> /* AF_UNIX, sockaddr_un */
38 #endif
39 
40 
41 typedef struct {
42   uv_malloc_func local_malloc;
43   uv_realloc_func local_realloc;
44   uv_calloc_func local_calloc;
45   uv_free_func local_free;
46 } uv__allocator_t;
47 
48 static uv__allocator_t uv__allocator = {
49   malloc,
50   realloc,
51   calloc,
52   free,
53 };
54 
55 char* uv__strdup(const char* s) {
56   size_t len = strlen(s) + 1;
57   char* m = uv__malloc(len);
58   if (m == NULL)
59     return NULL;
60   return memcpy(m, s, len);
61 }
62 
63 char* uv__strndup(const char* s, size_t n) {
64   char* m;
65   size_t len = strlen(s);
66   if (n < len)
67     len = n;
68   m = uv__malloc(len + 1);
69   if (m == NULL)
70     return NULL;
71   m[len] = '\0';
72   return memcpy(m, s, len);
73 }
74 
75 void* uv__malloc(size_t size) {
76   if (size > 0)
77     return uv__allocator.local_malloc(size);
78   return NULL;
79 }
80 
81 void uv__free(void* ptr) {
82   int saved_errno;
83 
84   /* Libuv expects that free() does not clobber errno.  The system allocator
85    * honors that assumption but custom allocators may not be so careful.
86    */
87   saved_errno = errno;
88   uv__allocator.local_free(ptr);
89   errno = saved_errno;
90 }
91 
92 void* uv__calloc(size_t count, size_t size) {
93   return uv__allocator.local_calloc(count, size);
94 }
95 
96 void* uv__realloc(void* ptr, size_t size) {
97   if (size > 0)
98     return uv__allocator.local_realloc(ptr, size);
99   uv__free(ptr);
100   return NULL;
101 }
102 
103 void* uv__reallocf(void* ptr, size_t size) {
104   void* newptr;
105 
106   newptr = uv__realloc(ptr, size);
107   if (newptr == NULL)
108     if (size > 0)
109       uv__free(ptr);
110 
111   return newptr;
112 }
113 
114 int uv_replace_allocator(uv_malloc_func malloc_func,
115                          uv_realloc_func realloc_func,
116                          uv_calloc_func calloc_func,
117                          uv_free_func free_func) {
118   if (malloc_func == NULL || realloc_func == NULL ||
119       calloc_func == NULL || free_func == NULL) {
120     return UV_EINVAL;
121   }
122 
123   uv__allocator.local_malloc = malloc_func;
124   uv__allocator.local_realloc = realloc_func;
125   uv__allocator.local_calloc = calloc_func;
126   uv__allocator.local_free = free_func;
127 
128   return 0;
129 }
130 
131 #define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
132 
133 size_t uv_handle_size(uv_handle_type type) {
134   switch (type) {
135     UV_HANDLE_TYPE_MAP(XX)
136     default:
137       return -1;
138   }
139 }
140 
141 size_t uv_req_size(uv_req_type type) {
142   switch(type) {
143     UV_REQ_TYPE_MAP(XX)
144     default:
145       return -1;
146   }
147 }
148 
149 #undef XX
150 
151 
152 size_t uv_loop_size(void) {
153   return sizeof(uv_loop_t);
154 }
155 
156 
157 uv_buf_t uv_buf_init(char* base, unsigned int len) {
158   uv_buf_t buf;
159   buf.base = base;
160   buf.len = len;
161   return buf;
162 }
163 
164 
165 static const char* uv__unknown_err_code(int err) {
166   char buf[32];
167   char* copy;
168 
169   snprintf(buf, sizeof(buf), "Unknown system error %d", err);
170   copy = uv__strdup(buf);
171 
172   return copy != NULL ? copy : "Unknown system error";
173 }
174 
175 #define UV_ERR_NAME_GEN_R(name, _) \
176 case UV_## name: \
177   uv__strscpy(buf, #name, buflen); break;
178 char* uv_err_name_r(int err, char* buf, size_t buflen) {
179   switch (err) {
180     UV_ERRNO_MAP(UV_ERR_NAME_GEN_R)
181     default: snprintf(buf, buflen, "Unknown system error %d", err);
182   }
183   return buf;
184 }
185 #undef UV_ERR_NAME_GEN_R
186 
187 
188 #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
189 const char* uv_err_name(int err) {
190   switch (err) {
191     UV_ERRNO_MAP(UV_ERR_NAME_GEN)
192   }
193   return uv__unknown_err_code(err);
194 }
195 #undef UV_ERR_NAME_GEN
196 
197 
198 #define UV_STRERROR_GEN_R(name, msg) \
199 case UV_ ## name: \
200   snprintf(buf, buflen, "%s", msg); break;
201 char* uv_strerror_r(int err, char* buf, size_t buflen) {
202   switch (err) {
203     UV_ERRNO_MAP(UV_STRERROR_GEN_R)
204     default: snprintf(buf, buflen, "Unknown system error %d", err);
205   }
206   return buf;
207 }
208 #undef UV_STRERROR_GEN_R
209 
210 
211 #define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
212 const char* uv_strerror(int err) {
213   switch (err) {
214     UV_ERRNO_MAP(UV_STRERROR_GEN)
215   }
216   return uv__unknown_err_code(err);
217 }
218 #undef UV_STRERROR_GEN
219 
220 
221 int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
222   memset(addr, 0, sizeof(*addr));
223   addr->sin_family = AF_INET;
224   addr->sin_port = htons(port);
225 #ifdef SIN6_LEN
226   addr->sin_len = sizeof(*addr);
227 #endif
228   return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
229 }
230 
231 
232 int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
233   char address_part[40];
234   size_t address_part_size;
235   const char* zone_index;
236 
237   memset(addr, 0, sizeof(*addr));
238   addr->sin6_family = AF_INET6;
239   addr->sin6_port = htons(port);
240 #ifdef SIN6_LEN
241   addr->sin6_len = sizeof(*addr);
242 #endif
243 
244   zone_index = strchr(ip, '%');
245   if (zone_index != NULL) {
246     address_part_size = zone_index - ip;
247     if (address_part_size >= sizeof(address_part))
248       address_part_size = sizeof(address_part) - 1;
249 
250     memcpy(address_part, ip, address_part_size);
251     address_part[address_part_size] = '\0';
252     ip = address_part;
253 
254     zone_index++; /* skip '%' */
255     /* NOTE: unknown interface (id=0) is silently ignored */
256 #ifdef _WIN32
257     addr->sin6_scope_id = atoi(zone_index);
258 #else
259     addr->sin6_scope_id = if_nametoindex(zone_index);
260 #endif
261   }
262 
263   return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
264 }
265 
266 
267 int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {
268   return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
269 }
270 
271 
272 int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
273   return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
274 }
275 
276 
277 int uv_tcp_bind(uv_tcp_t* handle,
278                 const struct sockaddr* addr,
279                 unsigned int flags) {
280   unsigned int addrlen;
281 
282   if (handle->type != UV_TCP)
283     return UV_EINVAL;
284 
285   if (addr->sa_family == AF_INET)
286     addrlen = sizeof(struct sockaddr_in);
287   else if (addr->sa_family == AF_INET6)
288     addrlen = sizeof(struct sockaddr_in6);
289   else
290     return UV_EINVAL;
291 
292   return uv__tcp_bind(handle, addr, addrlen, flags);
293 }
294 
295 
296 int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned flags) {
297   unsigned extra_flags;
298   int domain;
299   int rc;
300 
301   /* Use the lower 8 bits for the domain. */
302   domain = flags & 0xFF;
303   if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
304     return UV_EINVAL;
305 
306   /* Use the higher bits for extra flags. */
307   extra_flags = flags & ~0xFF;
308   if (extra_flags & ~UV_UDP_RECVMMSG)
309     return UV_EINVAL;
310 
311   rc = uv__udp_init_ex(loop, handle, flags, domain);
312 
313   if (rc == 0)
314     if (extra_flags & UV_UDP_RECVMMSG)
315       handle->flags |= UV_HANDLE_UDP_RECVMMSG;
316 
317   return rc;
318 }
319 
320 
321 int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
322   return uv_udp_init_ex(loop, handle, AF_UNSPEC);
323 }
324 
325 
326 int uv_udp_bind(uv_udp_t* handle,
327                 const struct sockaddr* addr,
328                 unsigned int flags) {
329   unsigned int addrlen;
330 
331   if (handle->type != UV_UDP)
332     return UV_EINVAL;
333 
334   if (addr->sa_family == AF_INET)
335     addrlen = sizeof(struct sockaddr_in);
336   else if (addr->sa_family == AF_INET6)
337     addrlen = sizeof(struct sockaddr_in6);
338   else
339     return UV_EINVAL;
340 
341   return uv__udp_bind(handle, addr, addrlen, flags);
342 }
343 
344 
345 int uv_tcp_connect(uv_connect_t* req,
346                    uv_tcp_t* handle,
347                    const struct sockaddr* addr,
348                    uv_connect_cb cb) {
349   unsigned int addrlen;
350 
351   if (handle->type != UV_TCP)
352     return UV_EINVAL;
353 
354   if (addr->sa_family == AF_INET)
355     addrlen = sizeof(struct sockaddr_in);
356   else if (addr->sa_family == AF_INET6)
357     addrlen = sizeof(struct sockaddr_in6);
358   else
359     return UV_EINVAL;
360 
361   return uv__tcp_connect(req, handle, addr, addrlen, cb);
362 }
363 
364 
365 int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) {
366   unsigned int addrlen;
367 
368   if (handle->type != UV_UDP)
369     return UV_EINVAL;
370 
371   /* Disconnect the handle */
372   if (addr == NULL) {
373     if (!(handle->flags & UV_HANDLE_UDP_CONNECTED))
374       return UV_ENOTCONN;
375 
376     return uv__udp_disconnect(handle);
377   }
378 
379   if (addr->sa_family == AF_INET)
380     addrlen = sizeof(struct sockaddr_in);
381   else if (addr->sa_family == AF_INET6)
382     addrlen = sizeof(struct sockaddr_in6);
383   else
384     return UV_EINVAL;
385 
386   if (handle->flags & UV_HANDLE_UDP_CONNECTED)
387     return UV_EISCONN;
388 
389   return uv__udp_connect(handle, addr, addrlen);
390 }
391 
392 
393 int uv__udp_is_connected(uv_udp_t* handle) {
394   struct sockaddr_storage addr;
395   int addrlen;
396   if (handle->type != UV_UDP)
397     return 0;
398 
399   addrlen = sizeof(addr);
400   if (uv_udp_getpeername(handle, (struct sockaddr*) &addr, &addrlen) != 0)
401     return 0;
402 
403   return addrlen > 0;
404 }
405 
406 
407 int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) {
408   unsigned int addrlen;
409 
410   if (handle->type != UV_UDP)
411     return UV_EINVAL;
412 
413   if (addr != NULL && (handle->flags & UV_HANDLE_UDP_CONNECTED))
414     return UV_EISCONN;
415 
416   if (addr == NULL && !(handle->flags & UV_HANDLE_UDP_CONNECTED))
417     return UV_EDESTADDRREQ;
418 
419   if (addr != NULL) {
420     if (addr->sa_family == AF_INET)
421       addrlen = sizeof(struct sockaddr_in);
422     else if (addr->sa_family == AF_INET6)
423       addrlen = sizeof(struct sockaddr_in6);
424 #if defined(AF_UNIX) && !defined(_WIN32)
425     else if (addr->sa_family == AF_UNIX)
426       addrlen = sizeof(struct sockaddr_un);
427 #endif
428     else
429       return UV_EINVAL;
430   } else {
431     addrlen = 0;
432   }
433 
434   return addrlen;
435 }
436 
437 
438 int uv_udp_send(uv_udp_send_t* req,
439                 uv_udp_t* handle,
440                 const uv_buf_t bufs[],
441                 unsigned int nbufs,
442                 const struct sockaddr* addr,
443                 uv_udp_send_cb send_cb) {
444   int addrlen;
445 
446   addrlen = uv__udp_check_before_send(handle, addr);
447   if (addrlen < 0)
448     return addrlen;
449 
450   return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
451 }
452 
453 
454 int uv_udp_try_send(uv_udp_t* handle,
455                     const uv_buf_t bufs[],
456                     unsigned int nbufs,
457                     const struct sockaddr* addr) {
458   int addrlen;
459 
460   addrlen = uv__udp_check_before_send(handle, addr);
461   if (addrlen < 0)
462     return addrlen;
463 
464   return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
465 }
466 
467 
468 int uv_udp_recv_start(uv_udp_t* handle,
469                       uv_alloc_cb alloc_cb,
470                       uv_udp_recv_cb recv_cb) {
471   if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)
472     return UV_EINVAL;
473   else
474     return uv__udp_recv_start(handle, alloc_cb, recv_cb);
475 }
476 
477 
478 int uv_udp_recv_stop(uv_udp_t* handle) {
479   if (handle->type != UV_UDP)
480     return UV_EINVAL;
481   else
482     return uv__udp_recv_stop(handle);
483 }
484 
485 
486 void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
487   QUEUE queue;
488   QUEUE* q;
489   uv_handle_t* h;
490 
491   QUEUE_MOVE(&loop->handle_queue, &queue);
492   while (!QUEUE_EMPTY(&queue)) {
493     q = QUEUE_HEAD(&queue);
494     h = QUEUE_DATA(q, uv_handle_t, handle_queue);
495 
496     QUEUE_REMOVE(q);
497     QUEUE_INSERT_TAIL(&loop->handle_queue, q);
498 
499     if (h->flags & UV_HANDLE_INTERNAL) continue;
500     walk_cb(h, arg);
501   }
502 }
503 
504 
505 static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
506   const char* type;
507   QUEUE* q;
508   uv_handle_t* h;
509 
510   if (loop == NULL)
511     loop = uv_default_loop();
512 
513   QUEUE_FOREACH(q, &loop->handle_queue) {
514     h = QUEUE_DATA(q, uv_handle_t, handle_queue);
515 
516     if (only_active && !uv__is_active(h))
517       continue;
518 
519     switch (h->type) {
520 #define X(uc, lc) case UV_##uc: type = #lc; break;
521       UV_HANDLE_TYPE_MAP(X)
522 #undef X
523       default: type = "<unknown>";
524     }
525 
526     fprintf(stream,
527             "[%c%c%c] %-8s %p\n",
528             "R-"[!(h->flags & UV_HANDLE_REF)],
529             "A-"[!(h->flags & UV_HANDLE_ACTIVE)],
530             "I-"[!(h->flags & UV_HANDLE_INTERNAL)],
531             type,
532             (void*)h);
533   }
534 }
535 
536 
537 void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
538   uv__print_handles(loop, 0, stream);
539 }
540 
541 
542 void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
543   uv__print_handles(loop, 1, stream);
544 }
545 
546 
547 void uv_ref(uv_handle_t* handle) {
548   uv__handle_ref(handle);
549 }
550 
551 
552 void uv_unref(uv_handle_t* handle) {
553   uv__handle_unref(handle);
554 }
555 
556 
557 int uv_has_ref(const uv_handle_t* handle) {
558   return uv__has_ref(handle);
559 }
560 
561 
562 void uv_stop(uv_loop_t* loop) {
563   loop->stop_flag = 1;
564 }
565 
566 
567 uint64_t uv_now(const uv_loop_t* loop) {
568   return loop->time;
569 }
570 
571 
572 
573 size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
574   unsigned int i;
575   size_t bytes;
576 
577   bytes = 0;
578   for (i = 0; i < nbufs; i++)
579     bytes += (size_t) bufs[i].len;
580 
581   return bytes;
582 }
583 
584 int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
585   return uv__socket_sockopt(handle, SO_RCVBUF, value);
586 }
587 
588 int uv_send_buffer_size(uv_handle_t* handle, int *value) {
589   return uv__socket_sockopt(handle, SO_SNDBUF, value);
590 }
591 
592 int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
593   size_t required_len;
594 
595   if (!uv__is_active(handle)) {
596     *size = 0;
597     return UV_EINVAL;
598   }
599 
600   required_len = strlen(handle->path);
601   if (required_len >= *size) {
602     *size = required_len + 1;
603     return UV_ENOBUFS;
604   }
605 
606   memcpy(buffer, handle->path, required_len);
607   *size = required_len;
608   buffer[required_len] = '\0';
609 
610   return 0;
611 }
612 
613 /* The windows implementation does not have the same structure layout as
614  * the unix implementation (nbufs is not directly inside req but is
615  * contained in a nested union/struct) so this function locates it.
616 */
617 static unsigned int* uv__get_nbufs(uv_fs_t* req) {
618 #ifdef _WIN32
619   return &req->fs.info.nbufs;
620 #else
621   return &req->nbufs;
622 #endif
623 }
624 
625 /* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows
626  * systems. So, the memory should be released using free(). On Windows,
627  * uv__malloc() is used, so use uv__free() to free memory.
628 */
629 #ifdef _WIN32
630 # define uv__fs_scandir_free uv__free
631 #else
632 # define uv__fs_scandir_free free
633 #endif
634 
635 void uv__fs_scandir_cleanup(uv_fs_t* req) {
636   uv__dirent_t** dents;
637 
638   unsigned int* nbufs = uv__get_nbufs(req);
639 
640   dents = req->ptr;
641   if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
642     (*nbufs)--;
643   for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
644     uv__fs_scandir_free(dents[*nbufs]);
645 
646   uv__fs_scandir_free(req->ptr);
647   req->ptr = NULL;
648 }
649 
650 
651 int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
652   uv__dirent_t** dents;
653   uv__dirent_t* dent;
654   unsigned int* nbufs;
655 
656   /* Check to see if req passed */
657   if (req->result < 0)
658     return req->result;
659 
660   /* Ptr will be null if req was canceled or no files found */
661   if (!req->ptr)
662     return UV_EOF;
663 
664   nbufs = uv__get_nbufs(req);
665   assert(nbufs);
666 
667   dents = req->ptr;
668 
669   /* Free previous entity */
670   if (*nbufs > 0)
671     uv__fs_scandir_free(dents[*nbufs - 1]);
672 
673   /* End was already reached */
674   if (*nbufs == (unsigned int) req->result) {
675     uv__fs_scandir_free(dents);
676     req->ptr = NULL;
677     return UV_EOF;
678   }
679 
680   dent = dents[(*nbufs)++];
681 
682   ent->name = dent->d_name;
683   ent->type = uv__fs_get_dirent_type(dent);
684 
685   return 0;
686 }
687 
688 uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent) {
689   uv_dirent_type_t type;
690 
691 #ifdef HAVE_DIRENT_TYPES
692   switch (dent->d_type) {
693     case UV__DT_DIR:
694       type = UV_DIRENT_DIR;
695       break;
696     case UV__DT_FILE:
697       type = UV_DIRENT_FILE;
698       break;
699     case UV__DT_LINK:
700       type = UV_DIRENT_LINK;
701       break;
702     case UV__DT_FIFO:
703       type = UV_DIRENT_FIFO;
704       break;
705     case UV__DT_SOCKET:
706       type = UV_DIRENT_SOCKET;
707       break;
708     case UV__DT_CHAR:
709       type = UV_DIRENT_CHAR;
710       break;
711     case UV__DT_BLOCK:
712       type = UV_DIRENT_BLOCK;
713       break;
714     default:
715       type = UV_DIRENT_UNKNOWN;
716   }
717 #else
718   type = UV_DIRENT_UNKNOWN;
719 #endif
720 
721   return type;
722 }
723 
724 void uv__fs_readdir_cleanup(uv_fs_t* req) {
725   uv_dir_t* dir;
726   uv_dirent_t* dirents;
727   int i;
728 
729   if (req->ptr == NULL)
730     return;
731 
732   dir = req->ptr;
733   dirents = dir->dirents;
734   req->ptr = NULL;
735 
736   if (dirents == NULL)
737     return;
738 
739   for (i = 0; i < req->result; ++i) {
740     uv__free((char*) dirents[i].name);
741     dirents[i].name = NULL;
742   }
743 }
744 
745 
746 int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
747   va_list ap;
748   int err;
749 
750   va_start(ap, option);
751   /* Any platform-agnostic options should be handled here. */
752   err = uv__loop_configure(loop, option, ap);
753   va_end(ap);
754 
755   return err;
756 }
757 
758 
759 static uv_loop_t default_loop_struct;
760 static uv_loop_t* default_loop_ptr;
761 
762 
763 uv_loop_t* uv_default_loop(void) {
764   if (default_loop_ptr != NULL)
765     return default_loop_ptr;
766 
767   if (uv_loop_init(&default_loop_struct))
768     return NULL;
769 
770   default_loop_ptr = &default_loop_struct;
771   return default_loop_ptr;
772 }
773 
774 
775 uv_loop_t* uv_loop_new(void) {
776   uv_loop_t* loop;
777 
778   loop = uv__malloc(sizeof(*loop));
779   if (loop == NULL)
780     return NULL;
781 
782   if (uv_loop_init(loop)) {
783     uv__free(loop);
784     return NULL;
785   }
786 
787   return loop;
788 }
789 
790 
791 int uv_loop_close(uv_loop_t* loop) {
792   QUEUE* q;
793   uv_handle_t* h;
794 #ifndef NDEBUG
795   void* saved_data;
796 #endif
797 
798   if (uv__has_active_reqs(loop))
799     return UV_EBUSY;
800 
801   QUEUE_FOREACH(q, &loop->handle_queue) {
802     h = QUEUE_DATA(q, uv_handle_t, handle_queue);
803     if (!(h->flags & UV_HANDLE_INTERNAL))
804       return UV_EBUSY;
805   }
806 
807   uv__loop_close(loop);
808 
809 #ifndef NDEBUG
810   saved_data = loop->data;
811   memset(loop, -1, sizeof(*loop));
812   loop->data = saved_data;
813 #endif
814   if (loop == default_loop_ptr)
815     default_loop_ptr = NULL;
816 
817   return 0;
818 }
819 
820 
821 void uv_loop_delete(uv_loop_t* loop) {
822   uv_loop_t* default_loop;
823   int err;
824 
825   default_loop = default_loop_ptr;
826 
827   err = uv_loop_close(loop);
828   (void) err;    /* Squelch compiler warnings. */
829   assert(err == 0);
830   if (loop != default_loop)
831     uv__free(loop);
832 }
833 
834 
835 void uv_os_free_environ(uv_env_item_t* envitems, int count) {
836   int i;
837 
838   for (i = 0; i < count; i++) {
839     uv__free(envitems[i].name);
840   }
841 
842   uv__free(envitems);
843 }
844 
845 
846 void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
847   int i;
848 
849   for (i = 0; i < count; i++)
850     uv__free(cpu_infos[i].model);
851 
852   uv__free(cpu_infos);
853 }
854 
855 
856 #ifdef __GNUC__  /* Also covers __clang__ and __INTEL_COMPILER. */
857 __attribute__((destructor))
858 #endif
859 void uv_library_shutdown(void) {
860   static int was_shutdown;
861 
862   if (was_shutdown)
863     return;
864 
865   uv__process_title_cleanup();
866   uv__signal_cleanup();
867   uv__threadpool_cleanup();
868   was_shutdown = 1;
869 }
870