libuv-svace-build
1029 строк · 22.8 Кб
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#else36# include <net/if.h> /* if_nametoindex */37# include <sys/un.h> /* AF_UNIX, sockaddr_un */38#endif39
40
41typedef struct {42uv_malloc_func local_malloc;43uv_realloc_func local_realloc;44uv_calloc_func local_calloc;45uv_free_func local_free;46} uv__allocator_t;47
48static uv__allocator_t uv__allocator = {49malloc,50realloc,51calloc,52free,53};54
55char* uv__strdup(const char* s) {56size_t len = strlen(s) + 1;57char* m = uv__malloc(len);58if (m == NULL)59return NULL;60return memcpy(m, s, len);61}
62
63char* uv__strndup(const char* s, size_t n) {64char* m;65size_t len = strlen(s);66if (n < len)67len = n;68m = uv__malloc(len + 1);69if (m == NULL)70return NULL;71m[len] = '\0';72return memcpy(m, s, len);73}
74
75void* uv__malloc(size_t size) {76if (size > 0)77return uv__allocator.local_malloc(size);78return NULL;79}
80
81void uv__free(void* ptr) {82int saved_errno;83
84/* Libuv expects that free() does not clobber errno. The system allocator85* honors that assumption but custom allocators may not be so careful.
86*/
87saved_errno = errno;88uv__allocator.local_free(ptr);89errno = saved_errno;90}
91
92void* uv__calloc(size_t count, size_t size) {93return uv__allocator.local_calloc(count, size);94}
95
96void* uv__realloc(void* ptr, size_t size) {97if (size > 0)98return uv__allocator.local_realloc(ptr, size);99uv__free(ptr);100return NULL;101}
102
103void* uv__reallocf(void* ptr, size_t size) {104void* newptr;105
106newptr = uv__realloc(ptr, size);107if (newptr == NULL)108if (size > 0)109uv__free(ptr);110
111return newptr;112}
113
114int uv_replace_allocator(uv_malloc_func malloc_func,115uv_realloc_func realloc_func,116uv_calloc_func calloc_func,117uv_free_func free_func) {118if (malloc_func == NULL || realloc_func == NULL ||119calloc_func == NULL || free_func == NULL) {120return UV_EINVAL;121}122
123uv__allocator.local_malloc = malloc_func;124uv__allocator.local_realloc = realloc_func;125uv__allocator.local_calloc = calloc_func;126uv__allocator.local_free = free_func;127
128return 0;129}
130
131
132void uv_os_free_passwd(uv_passwd_t* pwd) {133if (pwd == NULL)134return;135
136/* On unix, the memory for name, shell, and homedir are allocated in a single137* uv__malloc() call. The base of the pointer is stored in pwd->username, so
138* that is the field that needs to be freed.
139*/
140uv__free(pwd->username);141#ifdef _WIN32142uv__free(pwd->homedir);143#endif144pwd->username = NULL;145pwd->shell = NULL;146pwd->homedir = NULL;147}
148
149
150void uv_os_free_group(uv_group_t *grp) {151if (grp == NULL)152return;153
154/* The memory for is allocated in a single uv__malloc() call. The base of the155* pointer is stored in grp->members, so that is the only field that needs to
156* be freed.
157*/
158uv__free(grp->members);159grp->members = NULL;160grp->groupname = NULL;161}
162
163
164#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);165
166size_t uv_handle_size(uv_handle_type type) {167switch (type) {168UV_HANDLE_TYPE_MAP(XX)169default:170return -1;171}172}
173
174size_t uv_req_size(uv_req_type type) {175switch(type) {176UV_REQ_TYPE_MAP(XX)177default:178return -1;179}180}
181
182#undef XX183
184
185size_t uv_loop_size(void) {186return sizeof(uv_loop_t);187}
188
189
190uv_buf_t uv_buf_init(char* base, unsigned int len) {191uv_buf_t buf;192buf.base = base;193buf.len = len;194return buf;195}
196
197
198static const char* uv__unknown_err_code(int err) {199char buf[32];200char* copy;201
202snprintf(buf, sizeof(buf), "Unknown system error %d", err);203copy = uv__strdup(buf);204
205return copy != NULL ? copy : "Unknown system error";206}
207
208#define UV_ERR_NAME_GEN_R(name, _) \209case UV_## name: \210uv__strscpy(buf, #name, buflen); break;211char* uv_err_name_r(int err, char* buf, size_t buflen) {212switch (err) {213UV_ERRNO_MAP(UV_ERR_NAME_GEN_R)214default: snprintf(buf, buflen, "Unknown system error %d", err);215}216return buf;217}
218#undef UV_ERR_NAME_GEN_R219
220
221#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;222const char* uv_err_name(int err) {223switch (err) {224UV_ERRNO_MAP(UV_ERR_NAME_GEN)225}226return uv__unknown_err_code(err);227}
228#undef UV_ERR_NAME_GEN229
230
231#define UV_STRERROR_GEN_R(name, msg) \232case UV_ ## name: \233snprintf(buf, buflen, "%s", msg); break;234char* uv_strerror_r(int err, char* buf, size_t buflen) {235switch (err) {236UV_ERRNO_MAP(UV_STRERROR_GEN_R)237default: snprintf(buf, buflen, "Unknown system error %d", err);238}239return buf;240}
241#undef UV_STRERROR_GEN_R242
243
244#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;245const char* uv_strerror(int err) {246switch (err) {247UV_ERRNO_MAP(UV_STRERROR_GEN)248}249return uv__unknown_err_code(err);250}
251#undef UV_STRERROR_GEN252
253
254int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {255memset(addr, 0, sizeof(*addr));256addr->sin_family = AF_INET;257addr->sin_port = htons(port);258#ifdef SIN6_LEN259addr->sin_len = sizeof(*addr);260#endif261return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));262}
263
264
265int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {266char address_part[40];267size_t address_part_size;268const char* zone_index;269
270memset(addr, 0, sizeof(*addr));271addr->sin6_family = AF_INET6;272addr->sin6_port = htons(port);273#ifdef SIN6_LEN274addr->sin6_len = sizeof(*addr);275#endif276
277zone_index = strchr(ip, '%');278if (zone_index != NULL) {279address_part_size = zone_index - ip;280if (address_part_size >= sizeof(address_part))281address_part_size = sizeof(address_part) - 1;282
283memcpy(address_part, ip, address_part_size);284address_part[address_part_size] = '\0';285ip = address_part;286
287zone_index++; /* skip '%' */288/* NOTE: unknown interface (id=0) is silently ignored */289#ifdef _WIN32290addr->sin6_scope_id = atoi(zone_index);291#else292addr->sin6_scope_id = if_nametoindex(zone_index);293#endif294}295
296return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);297}
298
299
300int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {301return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);302}
303
304
305int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {306return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);307}
308
309
310int uv_ip_name(const struct sockaddr *src, char *dst, size_t size) {311switch (src->sa_family) {312case AF_INET:313return uv_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr,314dst, size);315case AF_INET6:316return uv_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr,317dst, size);318default:319return UV_EAFNOSUPPORT;320}321}
322
323
324int uv_tcp_bind(uv_tcp_t* handle,325const struct sockaddr* addr,326unsigned int flags) {327unsigned int addrlen;328
329if (handle->type != UV_TCP)330return UV_EINVAL;331if (uv__is_closing(handle)) {332return UV_EINVAL;333}334if (addr->sa_family == AF_INET)335addrlen = sizeof(struct sockaddr_in);336else if (addr->sa_family == AF_INET6)337addrlen = sizeof(struct sockaddr_in6);338else339return UV_EINVAL;340
341return uv__tcp_bind(handle, addr, addrlen, flags);342}
343
344
345int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned flags) {346unsigned extra_flags;347int domain;348int rc;349
350/* Use the lower 8 bits for the domain. */351domain = flags & 0xFF;352if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)353return UV_EINVAL;354
355/* Use the higher bits for extra flags. */356extra_flags = flags & ~0xFF;357if (extra_flags & ~UV_UDP_RECVMMSG)358return UV_EINVAL;359
360rc = uv__udp_init_ex(loop, handle, flags, domain);361
362if (rc == 0)363if (extra_flags & UV_UDP_RECVMMSG)364handle->flags |= UV_HANDLE_UDP_RECVMMSG;365
366return rc;367}
368
369
370int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {371return uv_udp_init_ex(loop, handle, AF_UNSPEC);372}
373
374
375int uv_udp_bind(uv_udp_t* handle,376const struct sockaddr* addr,377unsigned int flags) {378unsigned int addrlen;379
380if (handle->type != UV_UDP)381return UV_EINVAL;382
383if (addr->sa_family == AF_INET)384addrlen = sizeof(struct sockaddr_in);385else if (addr->sa_family == AF_INET6)386addrlen = sizeof(struct sockaddr_in6);387else388return UV_EINVAL;389
390return uv__udp_bind(handle, addr, addrlen, flags);391}
392
393
394int uv_tcp_connect(uv_connect_t* req,395uv_tcp_t* handle,396const struct sockaddr* addr,397uv_connect_cb cb) {398unsigned int addrlen;399
400if (handle->type != UV_TCP)401return UV_EINVAL;402
403if (addr->sa_family == AF_INET)404addrlen = sizeof(struct sockaddr_in);405else if (addr->sa_family == AF_INET6)406addrlen = sizeof(struct sockaddr_in6);407else408return UV_EINVAL;409
410return uv__tcp_connect(req, handle, addr, addrlen, cb);411}
412
413
414int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) {415unsigned int addrlen;416
417if (handle->type != UV_UDP)418return UV_EINVAL;419
420/* Disconnect the handle */421if (addr == NULL) {422if (!(handle->flags & UV_HANDLE_UDP_CONNECTED))423return UV_ENOTCONN;424
425return uv__udp_disconnect(handle);426}427
428if (addr->sa_family == AF_INET)429addrlen = sizeof(struct sockaddr_in);430else if (addr->sa_family == AF_INET6)431addrlen = sizeof(struct sockaddr_in6);432else433return UV_EINVAL;434
435if (handle->flags & UV_HANDLE_UDP_CONNECTED)436return UV_EISCONN;437
438return uv__udp_connect(handle, addr, addrlen);439}
440
441
442int uv__udp_is_connected(uv_udp_t* handle) {443struct sockaddr_storage addr;444int addrlen;445if (handle->type != UV_UDP)446return 0;447
448addrlen = sizeof(addr);449if (uv_udp_getpeername(handle, (struct sockaddr*) &addr, &addrlen) != 0)450return 0;451
452return addrlen > 0;453}
454
455
456int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) {457unsigned int addrlen;458
459if (handle->type != UV_UDP)460return UV_EINVAL;461
462if (addr != NULL && (handle->flags & UV_HANDLE_UDP_CONNECTED))463return UV_EISCONN;464
465if (addr == NULL && !(handle->flags & UV_HANDLE_UDP_CONNECTED))466return UV_EDESTADDRREQ;467
468if (addr != NULL) {469if (addr->sa_family == AF_INET)470addrlen = sizeof(struct sockaddr_in);471else if (addr->sa_family == AF_INET6)472addrlen = sizeof(struct sockaddr_in6);473#if defined(AF_UNIX) && !defined(_WIN32)474else if (addr->sa_family == AF_UNIX)475addrlen = sizeof(struct sockaddr_un);476#endif477else478return UV_EINVAL;479} else {480addrlen = 0;481}482
483return addrlen;484}
485
486
487int uv_udp_send(uv_udp_send_t* req,488uv_udp_t* handle,489const uv_buf_t bufs[],490unsigned int nbufs,491const struct sockaddr* addr,492uv_udp_send_cb send_cb) {493int addrlen;494
495addrlen = uv__udp_check_before_send(handle, addr);496if (addrlen < 0)497return addrlen;498
499return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);500}
501
502
503int uv_udp_try_send(uv_udp_t* handle,504const uv_buf_t bufs[],505unsigned int nbufs,506const struct sockaddr* addr) {507int addrlen;508
509addrlen = uv__udp_check_before_send(handle, addr);510if (addrlen < 0)511return addrlen;512
513return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);514}
515
516
517int uv_udp_recv_start(uv_udp_t* handle,518uv_alloc_cb alloc_cb,519uv_udp_recv_cb recv_cb) {520if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)521return UV_EINVAL;522else523return uv__udp_recv_start(handle, alloc_cb, recv_cb);524}
525
526
527int uv_udp_recv_stop(uv_udp_t* handle) {528if (handle->type != UV_UDP)529return UV_EINVAL;530else531return uv__udp_recv_stop(handle);532}
533
534
535void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {536struct uv__queue queue;537struct uv__queue* q;538uv_handle_t* h;539
540uv__queue_move(&loop->handle_queue, &queue);541while (!uv__queue_empty(&queue)) {542q = uv__queue_head(&queue);543h = uv__queue_data(q, uv_handle_t, handle_queue);544
545uv__queue_remove(q);546uv__queue_insert_tail(&loop->handle_queue, q);547
548if (h->flags & UV_HANDLE_INTERNAL) continue;549walk_cb(h, arg);550}551}
552
553
554static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {555const char* type;556struct uv__queue* q;557uv_handle_t* h;558
559if (loop == NULL)560loop = uv_default_loop();561
562if (stream == NULL)563stream = stderr;564
565uv__queue_foreach(q, &loop->handle_queue) {566h = uv__queue_data(q, uv_handle_t, handle_queue);567
568if (only_active && !uv__is_active(h))569continue;570
571switch (h->type) {572#define X(uc, lc) case UV_##uc: type = #lc; break;573UV_HANDLE_TYPE_MAP(X)574#undef X575default: type = "<unknown>";576}577
578fprintf(stream,579"[%c%c%c] %-8s %p\n",580"R-"[!(h->flags & UV_HANDLE_REF)],581"A-"[!(h->flags & UV_HANDLE_ACTIVE)],582"I-"[!(h->flags & UV_HANDLE_INTERNAL)],583type,584(void*)h);585}586}
587
588
589void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {590uv__print_handles(loop, 0, stream);591}
592
593
594void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {595uv__print_handles(loop, 1, stream);596}
597
598
599void uv_ref(uv_handle_t* handle) {600uv__handle_ref(handle);601}
602
603
604void uv_unref(uv_handle_t* handle) {605uv__handle_unref(handle);606}
607
608
609int uv_has_ref(const uv_handle_t* handle) {610return uv__has_ref(handle);611}
612
613
614void uv_stop(uv_loop_t* loop) {615loop->stop_flag = 1;616}
617
618
619uint64_t uv_now(const uv_loop_t* loop) {620return loop->time;621}
622
623
624
625size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {626unsigned int i;627size_t bytes;628
629bytes = 0;630for (i = 0; i < nbufs; i++)631bytes += (size_t) bufs[i].len;632
633return bytes;634}
635
636int uv_recv_buffer_size(uv_handle_t* handle, int* value) {637return uv__socket_sockopt(handle, SO_RCVBUF, value);638}
639
640int uv_send_buffer_size(uv_handle_t* handle, int *value) {641return uv__socket_sockopt(handle, SO_SNDBUF, value);642}
643
644int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {645size_t required_len;646
647if (!uv__is_active(handle)) {648*size = 0;649return UV_EINVAL;650}651
652required_len = strlen(handle->path);653if (required_len >= *size) {654*size = required_len + 1;655return UV_ENOBUFS;656}657
658memcpy(buffer, handle->path, required_len);659*size = required_len;660buffer[required_len] = '\0';661
662return 0;663}
664
665/* The windows implementation does not have the same structure layout as
666* the unix implementation (nbufs is not directly inside req but is
667* contained in a nested union/struct) so this function locates it.
668*/
669static unsigned int* uv__get_nbufs(uv_fs_t* req) {670#ifdef _WIN32671return &req->fs.info.nbufs;672#else673return &req->nbufs;674#endif675}
676
677/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows
678* systems. So, the memory should be released using free(). On Windows,
679* uv__malloc() is used, so use uv__free() to free memory.
680*/
681#ifdef _WIN32682# define uv__fs_scandir_free uv__free683#else684# define uv__fs_scandir_free free685#endif686
687void uv__fs_scandir_cleanup(uv_fs_t* req) {688uv__dirent_t** dents;689unsigned int* nbufs;690unsigned int i;691unsigned int n;692
693if (req->result >= 0) {694dents = req->ptr;695nbufs = uv__get_nbufs(req);696
697i = 0;698if (*nbufs > 0)699i = *nbufs - 1;700
701n = (unsigned int) req->result;702for (; i < n; i++)703uv__fs_scandir_free(dents[i]);704}705
706uv__fs_scandir_free(req->ptr);707req->ptr = NULL;708}
709
710
711int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {712uv__dirent_t** dents;713uv__dirent_t* dent;714unsigned int* nbufs;715
716/* Check to see if req passed */717if (req->result < 0)718return req->result;719
720/* Ptr will be null if req was canceled or no files found */721if (!req->ptr)722return UV_EOF;723
724nbufs = uv__get_nbufs(req);725assert(nbufs);726
727dents = req->ptr;728
729/* Free previous entity */730if (*nbufs > 0)731uv__fs_scandir_free(dents[*nbufs - 1]);732
733/* End was already reached */734if (*nbufs == (unsigned int) req->result) {735uv__fs_scandir_free(dents);736req->ptr = NULL;737return UV_EOF;738}739
740dent = dents[(*nbufs)++];741
742ent->name = dent->d_name;743ent->type = uv__fs_get_dirent_type(dent);744
745return 0;746}
747
748uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent) {749uv_dirent_type_t type;750
751#ifdef HAVE_DIRENT_TYPES752switch (dent->d_type) {753case UV__DT_DIR:754type = UV_DIRENT_DIR;755break;756case UV__DT_FILE:757type = UV_DIRENT_FILE;758break;759case UV__DT_LINK:760type = UV_DIRENT_LINK;761break;762case UV__DT_FIFO:763type = UV_DIRENT_FIFO;764break;765case UV__DT_SOCKET:766type = UV_DIRENT_SOCKET;767break;768case UV__DT_CHAR:769type = UV_DIRENT_CHAR;770break;771case UV__DT_BLOCK:772type = UV_DIRENT_BLOCK;773break;774default:775type = UV_DIRENT_UNKNOWN;776}777#else778type = UV_DIRENT_UNKNOWN;779#endif780
781return type;782}
783
784void uv__fs_readdir_cleanup(uv_fs_t* req) {785uv_dir_t* dir;786uv_dirent_t* dirents;787int i;788
789if (req->ptr == NULL)790return;791
792dir = req->ptr;793dirents = dir->dirents;794req->ptr = NULL;795
796if (dirents == NULL)797return;798
799for (i = 0; i < req->result; ++i) {800uv__free((char*) dirents[i].name);801dirents[i].name = NULL;802}803}
804
805
806int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {807va_list ap;808int err;809
810va_start(ap, option);811/* Any platform-agnostic options should be handled here. */812err = uv__loop_configure(loop, option, ap);813va_end(ap);814
815return err;816}
817
818
819static uv_loop_t default_loop_struct;820static uv_loop_t* default_loop_ptr;821
822
823uv_loop_t* uv_default_loop(void) {824if (default_loop_ptr != NULL)825return default_loop_ptr;826
827if (uv_loop_init(&default_loop_struct))828return NULL;829
830default_loop_ptr = &default_loop_struct;831return default_loop_ptr;832}
833
834
835uv_loop_t* uv_loop_new(void) {836uv_loop_t* loop;837
838loop = uv__malloc(sizeof(*loop));839if (loop == NULL)840return NULL;841
842if (uv_loop_init(loop)) {843uv__free(loop);844return NULL;845}846
847return loop;848}
849
850
851int uv_loop_close(uv_loop_t* loop) {852struct uv__queue* q;853uv_handle_t* h;854#ifndef NDEBUG855void* saved_data;856#endif857
858if (uv__has_active_reqs(loop))859return UV_EBUSY;860
861uv__queue_foreach(q, &loop->handle_queue) {862h = uv__queue_data(q, uv_handle_t, handle_queue);863if (!(h->flags & UV_HANDLE_INTERNAL))864return UV_EBUSY;865}866
867uv__loop_close(loop);868
869#ifndef NDEBUG870saved_data = loop->data;871memset(loop, -1, sizeof(*loop));872loop->data = saved_data;873#endif874if (loop == default_loop_ptr)875default_loop_ptr = NULL;876
877return 0;878}
879
880
881void uv_loop_delete(uv_loop_t* loop) {882uv_loop_t* default_loop;883int err;884
885default_loop = default_loop_ptr;886
887err = uv_loop_close(loop);888(void) err; /* Squelch compiler warnings. */889assert(err == 0);890if (loop != default_loop)891uv__free(loop);892}
893
894
895int uv_read_start(uv_stream_t* stream,896uv_alloc_cb alloc_cb,897uv_read_cb read_cb) {898if (stream == NULL || alloc_cb == NULL || read_cb == NULL)899return UV_EINVAL;900
901if (stream->flags & UV_HANDLE_CLOSING)902return UV_EINVAL;903
904if (stream->flags & UV_HANDLE_READING)905return UV_EALREADY;906
907if (!(stream->flags & UV_HANDLE_READABLE))908return UV_ENOTCONN;909
910return uv__read_start(stream, alloc_cb, read_cb);911}
912
913
914void uv_os_free_environ(uv_env_item_t* envitems, int count) {915int i;916
917for (i = 0; i < count; i++) {918uv__free(envitems[i].name);919}920
921uv__free(envitems);922}
923
924
925void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {926#ifdef __linux__927(void) &count;928uv__free(cpu_infos);929#else930int i;931
932for (i = 0; i < count; i++)933uv__free(cpu_infos[i].model);934
935uv__free(cpu_infos);936#endif /* __linux__ */937}
938
939
940/* Also covers __clang__ and __INTEL_COMPILER. Disabled on Windows because
941* threads have already been forcibly terminated by the operating system
942* by the time destructors run, ergo, it's not safe to try to clean them up.
943*/
944#if defined(__GNUC__) && !defined(_WIN32)945__attribute__((destructor))946#endif947void uv_library_shutdown(void) {948static int was_shutdown;949
950if (uv__exchange_int_relaxed(&was_shutdown, 1))951return;952
953uv__process_title_cleanup();954uv__signal_cleanup();955#ifdef __MVS__956/* TODO(itodorov) - zos: revisit when Woz compiler is available. */957uv__os390_cleanup();958#else959uv__threadpool_cleanup();960#endif961}
962
963
964void uv__metrics_update_idle_time(uv_loop_t* loop) {965uv__loop_metrics_t* loop_metrics;966uint64_t entry_time;967uint64_t exit_time;968
969if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME))970return;971
972loop_metrics = uv__get_loop_metrics(loop);973
974/* The thread running uv__metrics_update_idle_time() is always the same975* thread that sets provider_entry_time. So it's unnecessary to lock before
976* retrieving this value.
977*/
978if (loop_metrics->provider_entry_time == 0)979return;980
981exit_time = uv_hrtime();982
983uv_mutex_lock(&loop_metrics->lock);984entry_time = loop_metrics->provider_entry_time;985loop_metrics->provider_entry_time = 0;986loop_metrics->provider_idle_time += exit_time - entry_time;987uv_mutex_unlock(&loop_metrics->lock);988}
989
990
991void uv__metrics_set_provider_entry_time(uv_loop_t* loop) {992uv__loop_metrics_t* loop_metrics;993uint64_t now;994
995if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME))996return;997
998now = uv_hrtime();999loop_metrics = uv__get_loop_metrics(loop);1000uv_mutex_lock(&loop_metrics->lock);1001loop_metrics->provider_entry_time = now;1002uv_mutex_unlock(&loop_metrics->lock);1003}
1004
1005
1006int uv_metrics_info(uv_loop_t* loop, uv_metrics_t* metrics) {1007memcpy(metrics,1008&uv__get_loop_metrics(loop)->metrics,1009sizeof(*metrics));1010
1011return 0;1012}
1013
1014
1015uint64_t uv_metrics_idle_time(uv_loop_t* loop) {1016uv__loop_metrics_t* loop_metrics;1017uint64_t entry_time;1018uint64_t idle_time;1019
1020loop_metrics = uv__get_loop_metrics(loop);1021uv_mutex_lock(&loop_metrics->lock);1022idle_time = loop_metrics->provider_idle_time;1023entry_time = loop_metrics->provider_entry_time;1024uv_mutex_unlock(&loop_metrics->lock);1025
1026if (entry_time > 0)1027idle_time += uv_hrtime() - entry_time;1028return idle_time;1029}
1030