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
uv__strdup(const char * s)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
uv__strndup(const char * s,size_t n)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
uv__malloc(size_t size)75 void* uv__malloc(size_t size) {
76 if (size > 0)
77 return uv__allocator.local_malloc(size);
78 return NULL;
79 }
80
uv__free(void * ptr)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
uv__calloc(size_t count,size_t size)92 void* uv__calloc(size_t count, size_t size) {
93 return uv__allocator.local_calloc(count, size);
94 }
95
uv__realloc(void * ptr,size_t size)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
uv__reallocf(void * ptr,size_t size)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
uv_replace_allocator(uv_malloc_func malloc_func,uv_realloc_func realloc_func,uv_calloc_func calloc_func,uv_free_func free_func)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
uv_handle_size(uv_handle_type type)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
uv_req_size(uv_req_type type)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
uv_loop_size(void)152 size_t uv_loop_size(void) {
153 return sizeof(uv_loop_t);
154 }
155
156
uv_buf_init(char * base,unsigned int len)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
uv__unknown_err_code(int err)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;
uv_err_name_r(int err,char * buf,size_t buflen)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;
uv_err_name(int err)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;
uv_strerror_r(int err,char * buf,size_t buflen)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;
uv_strerror(int err)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 #if !defined(CMAKE_BOOTSTRAP) || defined(_WIN32)
221
uv_ip4_addr(const char * ip,int port,struct sockaddr_in * addr)222 int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
223 memset(addr, 0, sizeof(*addr));
224 addr->sin_family = AF_INET;
225 addr->sin_port = htons(port);
226 #ifdef SIN6_LEN
227 addr->sin_len = sizeof(*addr);
228 #endif
229 return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
230 }
231
232
uv_ip6_addr(const char * ip,int port,struct sockaddr_in6 * addr)233 int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
234 char address_part[40];
235 size_t address_part_size;
236 const char* zone_index;
237
238 memset(addr, 0, sizeof(*addr));
239 addr->sin6_family = AF_INET6;
240 addr->sin6_port = htons(port);
241 #ifdef SIN6_LEN
242 addr->sin6_len = sizeof(*addr);
243 #endif
244
245 zone_index = strchr(ip, '%');
246 if (zone_index != NULL) {
247 address_part_size = zone_index - ip;
248 if (address_part_size >= sizeof(address_part))
249 address_part_size = sizeof(address_part) - 1;
250
251 memcpy(address_part, ip, address_part_size);
252 address_part[address_part_size] = '\0';
253 ip = address_part;
254
255 zone_index++; /* skip '%' */
256 /* NOTE: unknown interface (id=0) is silently ignored */
257 #ifdef _WIN32
258 addr->sin6_scope_id = atoi(zone_index);
259 #else
260 addr->sin6_scope_id = if_nametoindex(zone_index);
261 #endif
262 }
263
264 return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
265 }
266
267
uv_ip4_name(const struct sockaddr_in * src,char * dst,size_t size)268 int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {
269 return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
270 }
271
272
uv_ip6_name(const struct sockaddr_in6 * src,char * dst,size_t size)273 int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
274 return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
275 }
276
277
uv_tcp_bind(uv_tcp_t * handle,const struct sockaddr * addr,unsigned int flags)278 int uv_tcp_bind(uv_tcp_t* handle,
279 const struct sockaddr* addr,
280 unsigned int flags) {
281 unsigned int addrlen;
282
283 if (handle->type != UV_TCP)
284 return UV_EINVAL;
285
286 if (addr->sa_family == AF_INET)
287 addrlen = sizeof(struct sockaddr_in);
288 else if (addr->sa_family == AF_INET6)
289 addrlen = sizeof(struct sockaddr_in6);
290 else
291 return UV_EINVAL;
292
293 return uv__tcp_bind(handle, addr, addrlen, flags);
294 }
295
296
uv_udp_init_ex(uv_loop_t * loop,uv_udp_t * handle,unsigned flags)297 int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned flags) {
298 unsigned extra_flags;
299 int domain;
300 int rc;
301
302 /* Use the lower 8 bits for the domain. */
303 domain = flags & 0xFF;
304 if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
305 return UV_EINVAL;
306
307 /* Use the higher bits for extra flags. */
308 extra_flags = flags & ~0xFF;
309 if (extra_flags & ~UV_UDP_RECVMMSG)
310 return UV_EINVAL;
311
312 rc = uv__udp_init_ex(loop, handle, flags, domain);
313
314 if (rc == 0)
315 if (extra_flags & UV_UDP_RECVMMSG)
316 handle->flags |= UV_HANDLE_UDP_RECVMMSG;
317
318 return rc;
319 }
320
321
uv_udp_init(uv_loop_t * loop,uv_udp_t * handle)322 int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
323 return uv_udp_init_ex(loop, handle, AF_UNSPEC);
324 }
325
326
uv_udp_bind(uv_udp_t * handle,const struct sockaddr * addr,unsigned int flags)327 int uv_udp_bind(uv_udp_t* handle,
328 const struct sockaddr* addr,
329 unsigned int flags) {
330 unsigned int addrlen;
331
332 if (handle->type != UV_UDP)
333 return UV_EINVAL;
334
335 if (addr->sa_family == AF_INET)
336 addrlen = sizeof(struct sockaddr_in);
337 else if (addr->sa_family == AF_INET6)
338 addrlen = sizeof(struct sockaddr_in6);
339 else
340 return UV_EINVAL;
341
342 return uv__udp_bind(handle, addr, addrlen, flags);
343 }
344
345
uv_tcp_connect(uv_connect_t * req,uv_tcp_t * handle,const struct sockaddr * addr,uv_connect_cb cb)346 int uv_tcp_connect(uv_connect_t* req,
347 uv_tcp_t* handle,
348 const struct sockaddr* addr,
349 uv_connect_cb cb) {
350 unsigned int addrlen;
351
352 if (handle->type != UV_TCP)
353 return UV_EINVAL;
354
355 if (addr->sa_family == AF_INET)
356 addrlen = sizeof(struct sockaddr_in);
357 else if (addr->sa_family == AF_INET6)
358 addrlen = sizeof(struct sockaddr_in6);
359 else
360 return UV_EINVAL;
361
362 return uv__tcp_connect(req, handle, addr, addrlen, cb);
363 }
364
365
uv_udp_connect(uv_udp_t * handle,const struct sockaddr * addr)366 int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) {
367 unsigned int addrlen;
368
369 if (handle->type != UV_UDP)
370 return UV_EINVAL;
371
372 /* Disconnect the handle */
373 if (addr == NULL) {
374 if (!(handle->flags & UV_HANDLE_UDP_CONNECTED))
375 return UV_ENOTCONN;
376
377 return uv__udp_disconnect(handle);
378 }
379
380 if (addr->sa_family == AF_INET)
381 addrlen = sizeof(struct sockaddr_in);
382 else if (addr->sa_family == AF_INET6)
383 addrlen = sizeof(struct sockaddr_in6);
384 else
385 return UV_EINVAL;
386
387 if (handle->flags & UV_HANDLE_UDP_CONNECTED)
388 return UV_EISCONN;
389
390 return uv__udp_connect(handle, addr, addrlen);
391 }
392
393
uv__udp_is_connected(uv_udp_t * handle)394 int uv__udp_is_connected(uv_udp_t* handle) {
395 struct sockaddr_storage addr;
396 int addrlen;
397 if (handle->type != UV_UDP)
398 return 0;
399
400 addrlen = sizeof(addr);
401 if (uv_udp_getpeername(handle, (struct sockaddr*) &addr, &addrlen) != 0)
402 return 0;
403
404 return addrlen > 0;
405 }
406
407
uv__udp_check_before_send(uv_udp_t * handle,const struct sockaddr * addr)408 int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) {
409 unsigned int addrlen;
410
411 if (handle->type != UV_UDP)
412 return UV_EINVAL;
413
414 if (addr != NULL && (handle->flags & UV_HANDLE_UDP_CONNECTED))
415 return UV_EISCONN;
416
417 if (addr == NULL && !(handle->flags & UV_HANDLE_UDP_CONNECTED))
418 return UV_EDESTADDRREQ;
419
420 if (addr != NULL) {
421 if (addr->sa_family == AF_INET)
422 addrlen = sizeof(struct sockaddr_in);
423 else if (addr->sa_family == AF_INET6)
424 addrlen = sizeof(struct sockaddr_in6);
425 #if defined(AF_UNIX) && !defined(_WIN32)
426 else if (addr->sa_family == AF_UNIX)
427 addrlen = sizeof(struct sockaddr_un);
428 #endif
429 else
430 return UV_EINVAL;
431 } else {
432 addrlen = 0;
433 }
434
435 return addrlen;
436 }
437
438
uv_udp_send(uv_udp_send_t * req,uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr,uv_udp_send_cb send_cb)439 int uv_udp_send(uv_udp_send_t* req,
440 uv_udp_t* handle,
441 const uv_buf_t bufs[],
442 unsigned int nbufs,
443 const struct sockaddr* addr,
444 uv_udp_send_cb send_cb) {
445 int addrlen;
446
447 addrlen = uv__udp_check_before_send(handle, addr);
448 if (addrlen < 0)
449 return addrlen;
450
451 return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
452 }
453
454
uv_udp_try_send(uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr)455 int uv_udp_try_send(uv_udp_t* handle,
456 const uv_buf_t bufs[],
457 unsigned int nbufs,
458 const struct sockaddr* addr) {
459 int addrlen;
460
461 addrlen = uv__udp_check_before_send(handle, addr);
462 if (addrlen < 0)
463 return addrlen;
464
465 return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
466 }
467
468
uv_udp_recv_start(uv_udp_t * handle,uv_alloc_cb alloc_cb,uv_udp_recv_cb recv_cb)469 int uv_udp_recv_start(uv_udp_t* handle,
470 uv_alloc_cb alloc_cb,
471 uv_udp_recv_cb recv_cb) {
472 if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)
473 return UV_EINVAL;
474 else
475 return uv__udp_recv_start(handle, alloc_cb, recv_cb);
476 }
477
478
uv_udp_recv_stop(uv_udp_t * handle)479 int uv_udp_recv_stop(uv_udp_t* handle) {
480 if (handle->type != UV_UDP)
481 return UV_EINVAL;
482 else
483 return uv__udp_recv_stop(handle);
484 }
485
486 #endif
487
uv_walk(uv_loop_t * loop,uv_walk_cb walk_cb,void * arg)488 void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
489 QUEUE queue;
490 QUEUE* q;
491 uv_handle_t* h;
492
493 QUEUE_MOVE(&loop->handle_queue, &queue);
494 while (!QUEUE_EMPTY(&queue)) {
495 q = QUEUE_HEAD(&queue);
496 h = QUEUE_DATA(q, uv_handle_t, handle_queue);
497
498 QUEUE_REMOVE(q);
499 QUEUE_INSERT_TAIL(&loop->handle_queue, q);
500
501 if (h->flags & UV_HANDLE_INTERNAL) continue;
502 walk_cb(h, arg);
503 }
504 }
505
506
uv__print_handles(uv_loop_t * loop,int only_active,FILE * stream)507 static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
508 const char* type;
509 QUEUE* q;
510 uv_handle_t* h;
511
512 if (loop == NULL)
513 loop = uv_default_loop();
514
515 QUEUE_FOREACH(q, &loop->handle_queue) {
516 h = QUEUE_DATA(q, uv_handle_t, handle_queue);
517
518 if (only_active && !uv__is_active(h))
519 continue;
520
521 switch (h->type) {
522 #define X(uc, lc) case UV_##uc: type = #lc; break;
523 UV_HANDLE_TYPE_MAP(X)
524 #undef X
525 default: type = "<unknown>";
526 }
527
528 fprintf(stream,
529 "[%c%c%c] %-8s %p\n",
530 "R-"[!(h->flags & UV_HANDLE_REF)],
531 "A-"[!(h->flags & UV_HANDLE_ACTIVE)],
532 "I-"[!(h->flags & UV_HANDLE_INTERNAL)],
533 type,
534 (void*)h);
535 }
536 }
537
538
uv_print_all_handles(uv_loop_t * loop,FILE * stream)539 void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
540 uv__print_handles(loop, 0, stream);
541 }
542
543
uv_print_active_handles(uv_loop_t * loop,FILE * stream)544 void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
545 uv__print_handles(loop, 1, stream);
546 }
547
548
uv_ref(uv_handle_t * handle)549 void uv_ref(uv_handle_t* handle) {
550 uv__handle_ref(handle);
551 }
552
553
uv_unref(uv_handle_t * handle)554 void uv_unref(uv_handle_t* handle) {
555 uv__handle_unref(handle);
556 }
557
558
uv_has_ref(const uv_handle_t * handle)559 int uv_has_ref(const uv_handle_t* handle) {
560 return uv__has_ref(handle);
561 }
562
563
uv_stop(uv_loop_t * loop)564 void uv_stop(uv_loop_t* loop) {
565 loop->stop_flag = 1;
566 }
567
568
uv_now(const uv_loop_t * loop)569 uint64_t uv_now(const uv_loop_t* loop) {
570 return loop->time;
571 }
572
573
574
uv__count_bufs(const uv_buf_t bufs[],unsigned int nbufs)575 size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
576 unsigned int i;
577 size_t bytes;
578
579 bytes = 0;
580 for (i = 0; i < nbufs; i++)
581 bytes += (size_t) bufs[i].len;
582
583 return bytes;
584 }
585
uv_recv_buffer_size(uv_handle_t * handle,int * value)586 int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
587 return uv__socket_sockopt(handle, SO_RCVBUF, value);
588 }
589
uv_send_buffer_size(uv_handle_t * handle,int * value)590 int uv_send_buffer_size(uv_handle_t* handle, int *value) {
591 return uv__socket_sockopt(handle, SO_SNDBUF, value);
592 }
593
uv_fs_event_getpath(uv_fs_event_t * handle,char * buffer,size_t * size)594 int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
595 size_t required_len;
596
597 if (!uv__is_active(handle)) {
598 *size = 0;
599 return UV_EINVAL;
600 }
601
602 required_len = strlen(handle->path);
603 if (required_len >= *size) {
604 *size = required_len + 1;
605 return UV_ENOBUFS;
606 }
607
608 memcpy(buffer, handle->path, required_len);
609 *size = required_len;
610 buffer[required_len] = '\0';
611
612 return 0;
613 }
614
615 /* The windows implementation does not have the same structure layout as
616 * the unix implementation (nbufs is not directly inside req but is
617 * contained in a nested union/struct) so this function locates it.
618 */
uv__get_nbufs(uv_fs_t * req)619 static unsigned int* uv__get_nbufs(uv_fs_t* req) {
620 #ifdef _WIN32
621 return &req->fs.info.nbufs;
622 #else
623 return &req->nbufs;
624 #endif
625 }
626
627 /* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows
628 * systems. So, the memory should be released using free(). On Windows,
629 * uv__malloc() is used, so use uv__free() to free memory.
630 */
631 #ifdef _WIN32
632 # define uv__fs_scandir_free uv__free
633 #else
634 # define uv__fs_scandir_free free
635 #endif
636
uv__fs_scandir_cleanup(uv_fs_t * req)637 void uv__fs_scandir_cleanup(uv_fs_t* req) {
638 uv__dirent_t** dents;
639
640 unsigned int* nbufs = uv__get_nbufs(req);
641
642 dents = req->ptr;
643 if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
644 (*nbufs)--;
645 for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
646 uv__fs_scandir_free(dents[*nbufs]);
647
648 uv__fs_scandir_free(req->ptr);
649 req->ptr = NULL;
650 }
651
652
uv_fs_scandir_next(uv_fs_t * req,uv_dirent_t * ent)653 int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
654 uv__dirent_t** dents;
655 uv__dirent_t* dent;
656 unsigned int* nbufs;
657
658 /* Check to see if req passed */
659 if (req->result < 0)
660 return req->result;
661
662 /* Ptr will be null if req was canceled or no files found */
663 if (!req->ptr)
664 return UV_EOF;
665
666 nbufs = uv__get_nbufs(req);
667 assert(nbufs);
668
669 dents = req->ptr;
670
671 /* Free previous entity */
672 if (*nbufs > 0)
673 uv__fs_scandir_free(dents[*nbufs - 1]);
674
675 /* End was already reached */
676 if (*nbufs == (unsigned int) req->result) {
677 uv__fs_scandir_free(dents);
678 req->ptr = NULL;
679 return UV_EOF;
680 }
681
682 dent = dents[(*nbufs)++];
683
684 ent->name = dent->d_name;
685 ent->type = uv__fs_get_dirent_type(dent);
686
687 return 0;
688 }
689
uv__fs_get_dirent_type(uv__dirent_t * dent)690 uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent) {
691 uv_dirent_type_t type;
692
693 #ifdef HAVE_DIRENT_TYPES
694 switch (dent->d_type) {
695 case UV__DT_DIR:
696 type = UV_DIRENT_DIR;
697 break;
698 case UV__DT_FILE:
699 type = UV_DIRENT_FILE;
700 break;
701 case UV__DT_LINK:
702 type = UV_DIRENT_LINK;
703 break;
704 case UV__DT_FIFO:
705 type = UV_DIRENT_FIFO;
706 break;
707 case UV__DT_SOCKET:
708 type = UV_DIRENT_SOCKET;
709 break;
710 case UV__DT_CHAR:
711 type = UV_DIRENT_CHAR;
712 break;
713 case UV__DT_BLOCK:
714 type = UV_DIRENT_BLOCK;
715 break;
716 default:
717 type = UV_DIRENT_UNKNOWN;
718 }
719 #else
720 type = UV_DIRENT_UNKNOWN;
721 #endif
722
723 return type;
724 }
725
uv__fs_readdir_cleanup(uv_fs_t * req)726 void uv__fs_readdir_cleanup(uv_fs_t* req) {
727 uv_dir_t* dir;
728 uv_dirent_t* dirents;
729 int i;
730
731 if (req->ptr == NULL)
732 return;
733
734 dir = req->ptr;
735 dirents = dir->dirents;
736 req->ptr = NULL;
737
738 if (dirents == NULL)
739 return;
740
741 for (i = 0; i < req->result; ++i) {
742 uv__free((char*) dirents[i].name);
743 dirents[i].name = NULL;
744 }
745 }
746
747
uv_loop_configure(uv_loop_t * loop,uv_loop_option option,...)748 int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
749 va_list ap;
750 int err;
751
752 va_start(ap, option);
753 /* Any platform-agnostic options should be handled here. */
754 err = uv__loop_configure(loop, option, ap);
755 va_end(ap);
756
757 return err;
758 }
759
760
761 static uv_loop_t default_loop_struct;
762 static uv_loop_t* default_loop_ptr;
763
764
uv_default_loop(void)765 uv_loop_t* uv_default_loop(void) {
766 if (default_loop_ptr != NULL)
767 return default_loop_ptr;
768
769 if (uv_loop_init(&default_loop_struct))
770 return NULL;
771
772 default_loop_ptr = &default_loop_struct;
773 return default_loop_ptr;
774 }
775
776
uv_loop_new(void)777 uv_loop_t* uv_loop_new(void) {
778 uv_loop_t* loop;
779
780 loop = uv__malloc(sizeof(*loop));
781 if (loop == NULL)
782 return NULL;
783
784 if (uv_loop_init(loop)) {
785 uv__free(loop);
786 return NULL;
787 }
788
789 return loop;
790 }
791
792
uv_loop_close(uv_loop_t * loop)793 int uv_loop_close(uv_loop_t* loop) {
794 QUEUE* q;
795 uv_handle_t* h;
796 #ifndef NDEBUG
797 void* saved_data;
798 #endif
799
800 if (uv__has_active_reqs(loop))
801 return UV_EBUSY;
802
803 QUEUE_FOREACH(q, &loop->handle_queue) {
804 h = QUEUE_DATA(q, uv_handle_t, handle_queue);
805 if (!(h->flags & UV_HANDLE_INTERNAL))
806 return UV_EBUSY;
807 }
808
809 uv__loop_close(loop);
810
811 #ifndef NDEBUG
812 saved_data = loop->data;
813 memset(loop, -1, sizeof(*loop));
814 loop->data = saved_data;
815 #endif
816 if (loop == default_loop_ptr)
817 default_loop_ptr = NULL;
818
819 return 0;
820 }
821
822
uv_loop_delete(uv_loop_t * loop)823 void uv_loop_delete(uv_loop_t* loop) {
824 uv_loop_t* default_loop;
825 int err;
826
827 default_loop = default_loop_ptr;
828
829 err = uv_loop_close(loop);
830 (void) err; /* Squelch compiler warnings. */
831 assert(err == 0);
832 if (loop != default_loop)
833 uv__free(loop);
834 }
835
836
uv_os_free_environ(uv_env_item_t * envitems,int count)837 void uv_os_free_environ(uv_env_item_t* envitems, int count) {
838 int i;
839
840 for (i = 0; i < count; i++) {
841 uv__free(envitems[i].name);
842 }
843
844 uv__free(envitems);
845 }
846
847
uv_free_cpu_info(uv_cpu_info_t * cpu_infos,int count)848 void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
849 int i;
850
851 for (i = 0; i < count; i++)
852 uv__free(cpu_infos[i].model);
853
854 uv__free(cpu_infos);
855 }
856
857
858 #ifdef __GNUC__ /* Also covers __clang__ and __INTEL_COMPILER. */
859 __attribute__((destructor))
860 #endif
uv_library_shutdown(void)861 void uv_library_shutdown(void) {
862 static int was_shutdown;
863
864 if (uv__load_relaxed(&was_shutdown))
865 return;
866
867 uv__process_title_cleanup();
868 uv__signal_cleanup();
869 uv__threadpool_cleanup();
870 uv__store_relaxed(&was_shutdown, 1);
871 }
872
873
uv__metrics_update_idle_time(uv_loop_t * loop)874 void uv__metrics_update_idle_time(uv_loop_t* loop) {
875 uv__loop_metrics_t* loop_metrics;
876 uint64_t entry_time;
877 uint64_t exit_time;
878
879 if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME))
880 return;
881
882 loop_metrics = uv__get_loop_metrics(loop);
883
884 /* The thread running uv__metrics_update_idle_time() is always the same
885 * thread that sets provider_entry_time. So it's unnecessary to lock before
886 * retrieving this value.
887 */
888 if (loop_metrics->provider_entry_time == 0)
889 return;
890
891 exit_time = uv_hrtime();
892
893 uv_mutex_lock(&loop_metrics->lock);
894 entry_time = loop_metrics->provider_entry_time;
895 loop_metrics->provider_entry_time = 0;
896 loop_metrics->provider_idle_time += exit_time - entry_time;
897 uv_mutex_unlock(&loop_metrics->lock);
898 }
899
900
uv__metrics_set_provider_entry_time(uv_loop_t * loop)901 void uv__metrics_set_provider_entry_time(uv_loop_t* loop) {
902 uv__loop_metrics_t* loop_metrics;
903 uint64_t now;
904
905 if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME))
906 return;
907
908 now = uv_hrtime();
909 loop_metrics = uv__get_loop_metrics(loop);
910 uv_mutex_lock(&loop_metrics->lock);
911 loop_metrics->provider_entry_time = now;
912 uv_mutex_unlock(&loop_metrics->lock);
913 }
914
915
uv_metrics_idle_time(uv_loop_t * loop)916 uint64_t uv_metrics_idle_time(uv_loop_t* loop) {
917 uv__loop_metrics_t* loop_metrics;
918 uint64_t entry_time;
919 uint64_t idle_time;
920
921 loop_metrics = uv__get_loop_metrics(loop);
922 uv_mutex_lock(&loop_metrics->lock);
923 idle_time = loop_metrics->provider_idle_time;
924 entry_time = loop_metrics->provider_entry_time;
925 uv_mutex_unlock(&loop_metrics->lock);
926
927 if (entry_time > 0)
928 idle_time += uv_hrtime() - entry_time;
929 return idle_time;
930 }
931