Brian Silverman | 41cdd3e | 2019-01-19 19:48:58 -0800 | [diff] [blame^] | 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 | #endif |
| 38 | |
| 39 | |
| 40 | typedef struct { |
| 41 | uv_malloc_func local_malloc; |
| 42 | uv_realloc_func local_realloc; |
| 43 | uv_calloc_func local_calloc; |
| 44 | uv_free_func local_free; |
| 45 | } uv__allocator_t; |
| 46 | |
| 47 | static uv__allocator_t uv__allocator = { |
| 48 | malloc, |
| 49 | realloc, |
| 50 | calloc, |
| 51 | free, |
| 52 | }; |
| 53 | |
| 54 | char* uv__strdup(const char* s) { |
| 55 | size_t len = strlen(s) + 1; |
| 56 | char* m = (char*)uv__malloc(len); |
| 57 | if (m == NULL) |
| 58 | return NULL; |
| 59 | return (char*)memcpy(m, s, len); |
| 60 | } |
| 61 | |
| 62 | char* uv__strndup(const char* s, size_t n) { |
| 63 | char* m; |
| 64 | size_t len = strlen(s); |
| 65 | if (n < len) |
| 66 | len = n; |
| 67 | m = (char*)uv__malloc(len + 1); |
| 68 | if (m == NULL) |
| 69 | return NULL; |
| 70 | m[len] = '\0'; |
| 71 | return (char*)memcpy(m, s, len); |
| 72 | } |
| 73 | |
| 74 | void* uv__malloc(size_t size) { |
| 75 | return uv__allocator.local_malloc(size); |
| 76 | } |
| 77 | |
| 78 | void uv__free(void* ptr) { |
| 79 | int saved_errno; |
| 80 | |
| 81 | /* Libuv expects that free() does not clobber errno. The system allocator |
| 82 | * honors that assumption but custom allocators may not be so careful. |
| 83 | */ |
| 84 | saved_errno = errno; |
| 85 | uv__allocator.local_free(ptr); |
| 86 | errno = saved_errno; |
| 87 | } |
| 88 | |
| 89 | void* uv__calloc(size_t count, size_t size) { |
| 90 | return uv__allocator.local_calloc(count, size); |
| 91 | } |
| 92 | |
| 93 | void* uv__realloc(void* ptr, size_t size) { |
| 94 | return uv__allocator.local_realloc(ptr, size); |
| 95 | } |
| 96 | |
| 97 | int uv_replace_allocator(uv_malloc_func malloc_func, |
| 98 | uv_realloc_func realloc_func, |
| 99 | uv_calloc_func calloc_func, |
| 100 | uv_free_func free_func) { |
| 101 | if (malloc_func == NULL || realloc_func == NULL || |
| 102 | calloc_func == NULL || free_func == NULL) { |
| 103 | return UV_EINVAL; |
| 104 | } |
| 105 | |
| 106 | uv__allocator.local_malloc = malloc_func; |
| 107 | uv__allocator.local_realloc = realloc_func; |
| 108 | uv__allocator.local_calloc = calloc_func; |
| 109 | uv__allocator.local_free = free_func; |
| 110 | |
| 111 | return 0; |
| 112 | } |
| 113 | |
| 114 | #define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t); |
| 115 | |
| 116 | size_t uv_handle_size(uv_handle_type type) { |
| 117 | switch (type) { |
| 118 | UV_HANDLE_TYPE_MAP(XX) |
| 119 | default: |
| 120 | return -1; |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | size_t uv_req_size(uv_req_type type) { |
| 125 | switch(type) { |
| 126 | UV_REQ_TYPE_MAP(XX) |
| 127 | default: |
| 128 | return -1; |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | #undef XX |
| 133 | |
| 134 | |
| 135 | size_t uv_loop_size(void) { |
| 136 | return sizeof(uv_loop_t); |
| 137 | } |
| 138 | |
| 139 | |
| 140 | uv_buf_t uv_buf_init(char* base, unsigned int len) { |
| 141 | uv_buf_t buf; |
| 142 | buf.base = base; |
| 143 | buf.len = len; |
| 144 | return buf; |
| 145 | } |
| 146 | |
| 147 | |
| 148 | static const char* uv__unknown_err_code(int err) { |
| 149 | char buf[32]; |
| 150 | char* copy; |
| 151 | |
| 152 | snprintf(buf, sizeof(buf), "Unknown system error %d", err); |
| 153 | copy = uv__strdup(buf); |
| 154 | |
| 155 | return copy != NULL ? copy : "Unknown system error"; |
| 156 | } |
| 157 | |
| 158 | |
| 159 | #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name; |
| 160 | const char* uv_err_name(int err) { |
| 161 | switch (err) { |
| 162 | UV_ERRNO_MAP(UV_ERR_NAME_GEN) |
| 163 | } |
| 164 | return uv__unknown_err_code(err); |
| 165 | } |
| 166 | #undef UV_ERR_NAME_GEN |
| 167 | |
| 168 | |
| 169 | #define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg; |
| 170 | const char* uv_strerror(int err) { |
| 171 | switch (err) { |
| 172 | UV_ERRNO_MAP(UV_STRERROR_GEN) |
| 173 | } |
| 174 | return uv__unknown_err_code(err); |
| 175 | } |
| 176 | #undef UV_STRERROR_GEN |
| 177 | |
| 178 | |
| 179 | int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) { |
| 180 | memset(addr, 0, sizeof(*addr)); |
| 181 | addr->sin_family = AF_INET; |
| 182 | addr->sin_port = htons(port); |
| 183 | return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr)); |
| 184 | } |
| 185 | |
| 186 | |
| 187 | int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) { |
| 188 | char address_part[40]; |
| 189 | size_t address_part_size; |
| 190 | const char* zone_index; |
| 191 | |
| 192 | memset(addr, 0, sizeof(*addr)); |
| 193 | addr->sin6_family = AF_INET6; |
| 194 | addr->sin6_port = htons(port); |
| 195 | |
| 196 | zone_index = strchr(ip, '%'); |
| 197 | if (zone_index != NULL) { |
| 198 | address_part_size = zone_index - ip; |
| 199 | if (address_part_size >= sizeof(address_part)) |
| 200 | address_part_size = sizeof(address_part) - 1; |
| 201 | |
| 202 | memcpy(address_part, ip, address_part_size); |
| 203 | address_part[address_part_size] = '\0'; |
| 204 | ip = address_part; |
| 205 | |
| 206 | zone_index++; /* skip '%' */ |
| 207 | /* NOTE: unknown interface (id=0) is silently ignored */ |
| 208 | #ifdef _WIN32 |
| 209 | addr->sin6_scope_id = atoi(zone_index); |
| 210 | #else |
| 211 | addr->sin6_scope_id = if_nametoindex(zone_index); |
| 212 | #endif |
| 213 | } |
| 214 | |
| 215 | return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr); |
| 216 | } |
| 217 | |
| 218 | |
| 219 | int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) { |
| 220 | return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size); |
| 221 | } |
| 222 | |
| 223 | |
| 224 | int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) { |
| 225 | return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size); |
| 226 | } |
| 227 | |
| 228 | |
| 229 | int uv_tcp_bind(uv_tcp_t* handle, |
| 230 | const struct sockaddr* addr, |
| 231 | unsigned int flags) { |
| 232 | unsigned int addrlen; |
| 233 | |
| 234 | if (handle->type != UV_TCP) |
| 235 | return UV_EINVAL; |
| 236 | |
| 237 | if (addr->sa_family == AF_INET) |
| 238 | addrlen = sizeof(struct sockaddr_in); |
| 239 | else if (addr->sa_family == AF_INET6) |
| 240 | addrlen = sizeof(struct sockaddr_in6); |
| 241 | else |
| 242 | return UV_EINVAL; |
| 243 | |
| 244 | return uv__tcp_bind(handle, addr, addrlen, flags); |
| 245 | } |
| 246 | |
| 247 | |
| 248 | int uv_udp_bind(uv_udp_t* handle, |
| 249 | const struct sockaddr* addr, |
| 250 | unsigned int flags) { |
| 251 | unsigned int addrlen; |
| 252 | |
| 253 | if (handle->type != UV_UDP) |
| 254 | return UV_EINVAL; |
| 255 | |
| 256 | if (addr->sa_family == AF_INET) |
| 257 | addrlen = sizeof(struct sockaddr_in); |
| 258 | else if (addr->sa_family == AF_INET6) |
| 259 | addrlen = sizeof(struct sockaddr_in6); |
| 260 | else |
| 261 | return UV_EINVAL; |
| 262 | |
| 263 | return uv__udp_bind(handle, addr, addrlen, flags); |
| 264 | } |
| 265 | |
| 266 | |
| 267 | int uv_tcp_connect(uv_connect_t* req, |
| 268 | uv_tcp_t* handle, |
| 269 | const struct sockaddr* addr, |
| 270 | uv_connect_cb cb) { |
| 271 | unsigned int addrlen; |
| 272 | |
| 273 | if (handle->type != UV_TCP) |
| 274 | return UV_EINVAL; |
| 275 | |
| 276 | if (addr->sa_family == AF_INET) |
| 277 | addrlen = sizeof(struct sockaddr_in); |
| 278 | else if (addr->sa_family == AF_INET6) |
| 279 | addrlen = sizeof(struct sockaddr_in6); |
| 280 | else |
| 281 | return UV_EINVAL; |
| 282 | |
| 283 | return uv__tcp_connect(req, handle, addr, addrlen, cb); |
| 284 | } |
| 285 | |
| 286 | |
| 287 | int uv_udp_send(uv_udp_send_t* req, |
| 288 | uv_udp_t* handle, |
| 289 | const uv_buf_t bufs[], |
| 290 | unsigned int nbufs, |
| 291 | const struct sockaddr* addr, |
| 292 | uv_udp_send_cb send_cb) { |
| 293 | unsigned int addrlen; |
| 294 | |
| 295 | if (handle->type != UV_UDP) |
| 296 | return UV_EINVAL; |
| 297 | |
| 298 | if (addr->sa_family == AF_INET) |
| 299 | addrlen = sizeof(struct sockaddr_in); |
| 300 | else if (addr->sa_family == AF_INET6) |
| 301 | addrlen = sizeof(struct sockaddr_in6); |
| 302 | else |
| 303 | return UV_EINVAL; |
| 304 | |
| 305 | return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb); |
| 306 | } |
| 307 | |
| 308 | |
| 309 | int uv_udp_try_send(uv_udp_t* handle, |
| 310 | const uv_buf_t bufs[], |
| 311 | unsigned int nbufs, |
| 312 | const struct sockaddr* addr) { |
| 313 | unsigned int addrlen; |
| 314 | |
| 315 | if (handle->type != UV_UDP) |
| 316 | return UV_EINVAL; |
| 317 | |
| 318 | if (addr->sa_family == AF_INET) |
| 319 | addrlen = sizeof(struct sockaddr_in); |
| 320 | else if (addr->sa_family == AF_INET6) |
| 321 | addrlen = sizeof(struct sockaddr_in6); |
| 322 | else |
| 323 | return UV_EINVAL; |
| 324 | |
| 325 | return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen); |
| 326 | } |
| 327 | |
| 328 | |
| 329 | int uv_udp_recv_start(uv_udp_t* handle, |
| 330 | uv_alloc_cb alloc_cb, |
| 331 | uv_udp_recv_cb recv_cb) { |
| 332 | if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL) |
| 333 | return UV_EINVAL; |
| 334 | else |
| 335 | return uv__udp_recv_start(handle, alloc_cb, recv_cb); |
| 336 | } |
| 337 | |
| 338 | |
| 339 | int uv_udp_recv_stop(uv_udp_t* handle) { |
| 340 | if (handle->type != UV_UDP) |
| 341 | return UV_EINVAL; |
| 342 | else |
| 343 | return uv__udp_recv_stop(handle); |
| 344 | } |
| 345 | |
| 346 | |
| 347 | void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { |
| 348 | QUEUE queue; |
| 349 | QUEUE* q; |
| 350 | uv_handle_t* h; |
| 351 | |
| 352 | QUEUE_MOVE(&loop->handle_queue, &queue); |
| 353 | while (!QUEUE_EMPTY(&queue)) { |
| 354 | q = QUEUE_HEAD(&queue); |
| 355 | h = QUEUE_DATA(q, uv_handle_t, handle_queue); |
| 356 | |
| 357 | QUEUE_REMOVE(q); |
| 358 | QUEUE_INSERT_TAIL(&loop->handle_queue, q); |
| 359 | |
| 360 | if (h->flags & UV__HANDLE_INTERNAL) continue; |
| 361 | walk_cb(h, arg); |
| 362 | } |
| 363 | } |
| 364 | |
| 365 | |
| 366 | static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { |
| 367 | const char* type; |
| 368 | QUEUE* q; |
| 369 | uv_handle_t* h; |
| 370 | |
| 371 | if (loop == NULL) |
| 372 | loop = uv_default_loop(); |
| 373 | |
| 374 | QUEUE_FOREACH(q, &loop->handle_queue) { |
| 375 | h = QUEUE_DATA(q, uv_handle_t, handle_queue); |
| 376 | |
| 377 | if (only_active && !uv__is_active(h)) |
| 378 | continue; |
| 379 | |
| 380 | switch (h->type) { |
| 381 | #define X(uc, lc) case UV_##uc: type = #lc; break; |
| 382 | UV_HANDLE_TYPE_MAP(X) |
| 383 | #undef X |
| 384 | default: type = "<unknown>"; |
| 385 | } |
| 386 | |
| 387 | fprintf(stream, |
| 388 | "[%c%c%c] %-8s %p\n", |
| 389 | "R-"[!(h->flags & UV__HANDLE_REF)], |
| 390 | "A-"[!(h->flags & UV__HANDLE_ACTIVE)], |
| 391 | "I-"[!(h->flags & UV__HANDLE_INTERNAL)], |
| 392 | type, |
| 393 | (void*)h); |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | |
| 398 | void uv_print_all_handles(uv_loop_t* loop, FILE* stream) { |
| 399 | uv__print_handles(loop, 0, stream); |
| 400 | } |
| 401 | |
| 402 | |
| 403 | void uv_print_active_handles(uv_loop_t* loop, FILE* stream) { |
| 404 | uv__print_handles(loop, 1, stream); |
| 405 | } |
| 406 | |
| 407 | |
| 408 | void uv_ref(uv_handle_t* handle) { |
| 409 | uv__handle_ref(handle); |
| 410 | } |
| 411 | |
| 412 | |
| 413 | void uv_unref(uv_handle_t* handle) { |
| 414 | uv__handle_unref(handle); |
| 415 | } |
| 416 | |
| 417 | |
| 418 | int uv_has_ref(const uv_handle_t* handle) { |
| 419 | return uv__has_ref(handle); |
| 420 | } |
| 421 | |
| 422 | |
| 423 | void uv_stop(uv_loop_t* loop) { |
| 424 | loop->stop_flag = 1; |
| 425 | } |
| 426 | |
| 427 | |
| 428 | uint64_t uv_now(const uv_loop_t* loop) { |
| 429 | return loop->time; |
| 430 | } |
| 431 | |
| 432 | |
| 433 | |
| 434 | size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) { |
| 435 | unsigned int i; |
| 436 | size_t bytes; |
| 437 | |
| 438 | bytes = 0; |
| 439 | for (i = 0; i < nbufs; i++) |
| 440 | bytes += (size_t) bufs[i].len; |
| 441 | |
| 442 | return bytes; |
| 443 | } |
| 444 | |
| 445 | int uv_recv_buffer_size(uv_handle_t* handle, int* value) { |
| 446 | return uv__socket_sockopt(handle, SO_RCVBUF, value); |
| 447 | } |
| 448 | |
| 449 | int uv_send_buffer_size(uv_handle_t* handle, int *value) { |
| 450 | return uv__socket_sockopt(handle, SO_SNDBUF, value); |
| 451 | } |
| 452 | |
| 453 | int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { |
| 454 | size_t required_len; |
| 455 | |
| 456 | if (!uv__is_active(handle)) { |
| 457 | *size = 0; |
| 458 | return UV_EINVAL; |
| 459 | } |
| 460 | |
| 461 | required_len = strlen(handle->path); |
| 462 | if (required_len >= *size) { |
| 463 | *size = required_len + 1; |
| 464 | return UV_ENOBUFS; |
| 465 | } |
| 466 | |
| 467 | memcpy(buffer, handle->path, required_len); |
| 468 | *size = required_len; |
| 469 | buffer[required_len] = '\0'; |
| 470 | |
| 471 | return 0; |
| 472 | } |
| 473 | |
| 474 | /* The windows implementation does not have the same structure layout as |
| 475 | * the unix implementation (nbufs is not directly inside req but is |
| 476 | * contained in a nested union/struct) so this function locates it. |
| 477 | */ |
| 478 | static unsigned int* uv__get_nbufs(uv_fs_t* req) { |
| 479 | #ifdef _WIN32 |
| 480 | return &req->fs.info.nbufs; |
| 481 | #else |
| 482 | return &req->nbufs; |
| 483 | #endif |
| 484 | } |
| 485 | |
| 486 | /* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows |
| 487 | * systems. So, the memory should be released using free(). On Windows, |
| 488 | * uv__malloc() is used, so use uv__free() to free memory. |
| 489 | */ |
| 490 | #ifdef _WIN32 |
| 491 | # define uv__fs_scandir_free uv__free |
| 492 | #else |
| 493 | # define uv__fs_scandir_free free |
| 494 | #endif |
| 495 | |
| 496 | void uv__fs_scandir_cleanup(uv_fs_t* req) { |
| 497 | uv__dirent_t** dents; |
| 498 | |
| 499 | unsigned int* nbufs = uv__get_nbufs(req); |
| 500 | |
| 501 | dents = (uv__dirent_t**)(req->ptr); |
| 502 | if (*nbufs > 0 && *nbufs != (unsigned int) req->result) |
| 503 | (*nbufs)--; |
| 504 | for (; *nbufs < (unsigned int) req->result; (*nbufs)++) |
| 505 | uv__fs_scandir_free(dents[*nbufs]); |
| 506 | |
| 507 | uv__fs_scandir_free(req->ptr); |
| 508 | req->ptr = NULL; |
| 509 | } |
| 510 | |
| 511 | |
| 512 | int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { |
| 513 | uv__dirent_t** dents; |
| 514 | uv__dirent_t* dent; |
| 515 | unsigned int* nbufs; |
| 516 | |
| 517 | /* Check to see if req passed */ |
| 518 | if (req->result < 0) |
| 519 | return req->result; |
| 520 | |
| 521 | /* Ptr will be null if req was canceled or no files found */ |
| 522 | if (!req->ptr) |
| 523 | return UV_EOF; |
| 524 | |
| 525 | nbufs = uv__get_nbufs(req); |
| 526 | assert(nbufs); |
| 527 | |
| 528 | dents = (uv__dirent_t**)(req->ptr); |
| 529 | |
| 530 | /* Free previous entity */ |
| 531 | if (*nbufs > 0) |
| 532 | uv__fs_scandir_free(dents[*nbufs - 1]); |
| 533 | |
| 534 | /* End was already reached */ |
| 535 | if (*nbufs == (unsigned int) req->result) { |
| 536 | uv__fs_scandir_free(dents); |
| 537 | req->ptr = NULL; |
| 538 | return UV_EOF; |
| 539 | } |
| 540 | |
| 541 | dent = dents[(*nbufs)++]; |
| 542 | |
| 543 | ent->name = dent->d_name; |
| 544 | #ifdef HAVE_DIRENT_TYPES |
| 545 | switch (dent->d_type) { |
| 546 | case UV__DT_DIR: |
| 547 | ent->type = UV_DIRENT_DIR; |
| 548 | break; |
| 549 | case UV__DT_FILE: |
| 550 | ent->type = UV_DIRENT_FILE; |
| 551 | break; |
| 552 | case UV__DT_LINK: |
| 553 | ent->type = UV_DIRENT_LINK; |
| 554 | break; |
| 555 | case UV__DT_FIFO: |
| 556 | ent->type = UV_DIRENT_FIFO; |
| 557 | break; |
| 558 | case UV__DT_SOCKET: |
| 559 | ent->type = UV_DIRENT_SOCKET; |
| 560 | break; |
| 561 | case UV__DT_CHAR: |
| 562 | ent->type = UV_DIRENT_CHAR; |
| 563 | break; |
| 564 | case UV__DT_BLOCK: |
| 565 | ent->type = UV_DIRENT_BLOCK; |
| 566 | break; |
| 567 | default: |
| 568 | ent->type = UV_DIRENT_UNKNOWN; |
| 569 | } |
| 570 | #else |
| 571 | ent->type = UV_DIRENT_UNKNOWN; |
| 572 | #endif |
| 573 | |
| 574 | return 0; |
| 575 | } |
| 576 | |
| 577 | |
| 578 | #ifdef __clang__ |
| 579 | # pragma clang diagnostic push |
| 580 | # pragma clang diagnostic ignored "-Wvarargs" |
| 581 | #endif |
| 582 | |
| 583 | int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) { |
| 584 | va_list ap; |
| 585 | int err; |
| 586 | |
| 587 | va_start(ap, option); |
| 588 | /* Any platform-agnostic options should be handled here. */ |
| 589 | err = uv__loop_configure(loop, option, ap); |
| 590 | va_end(ap); |
| 591 | |
| 592 | return err; |
| 593 | } |
| 594 | |
| 595 | #ifdef __clang__ |
| 596 | # pragma clang diagnostic pop |
| 597 | #endif |
| 598 | |
| 599 | |
| 600 | static uv_loop_t default_loop_struct; |
| 601 | static uv_loop_t* default_loop_ptr; |
| 602 | |
| 603 | |
| 604 | uv_loop_t* uv_default_loop(void) { |
| 605 | if (default_loop_ptr != NULL) |
| 606 | return default_loop_ptr; |
| 607 | |
| 608 | if (uv_loop_init(&default_loop_struct)) |
| 609 | return NULL; |
| 610 | |
| 611 | default_loop_ptr = &default_loop_struct; |
| 612 | return default_loop_ptr; |
| 613 | } |
| 614 | |
| 615 | |
| 616 | uv_loop_t* uv_loop_new(void) { |
| 617 | uv_loop_t* loop; |
| 618 | |
| 619 | loop = (uv_loop_t*)uv__malloc(sizeof(*loop)); |
| 620 | if (loop == NULL) |
| 621 | return NULL; |
| 622 | |
| 623 | if (uv_loop_init(loop)) { |
| 624 | uv__free(loop); |
| 625 | return NULL; |
| 626 | } |
| 627 | |
| 628 | return loop; |
| 629 | } |
| 630 | |
| 631 | |
| 632 | int uv_loop_close(uv_loop_t* loop) { |
| 633 | QUEUE* q; |
| 634 | uv_handle_t* h; |
| 635 | #ifndef NDEBUG |
| 636 | void* saved_data; |
| 637 | #endif |
| 638 | |
| 639 | if (uv__has_active_reqs(loop)) |
| 640 | return UV_EBUSY; |
| 641 | |
| 642 | QUEUE_FOREACH(q, &loop->handle_queue) { |
| 643 | h = QUEUE_DATA(q, uv_handle_t, handle_queue); |
| 644 | if (!(h->flags & UV__HANDLE_INTERNAL)) |
| 645 | return UV_EBUSY; |
| 646 | } |
| 647 | |
| 648 | uv__loop_close(loop); |
| 649 | |
| 650 | #ifndef NDEBUG |
| 651 | saved_data = loop->data; |
| 652 | memset(loop, -1, sizeof(*loop)); |
| 653 | loop->data = saved_data; |
| 654 | #endif |
| 655 | if (loop == default_loop_ptr) |
| 656 | default_loop_ptr = NULL; |
| 657 | |
| 658 | return 0; |
| 659 | } |
| 660 | |
| 661 | |
| 662 | void uv_loop_delete(uv_loop_t* loop) { |
| 663 | uv_loop_t* default_loop; |
| 664 | int err; |
| 665 | |
| 666 | default_loop = default_loop_ptr; |
| 667 | |
| 668 | err = uv_loop_close(loop); |
| 669 | (void) err; /* Squelch compiler warnings. */ |
| 670 | assert(err == 0); |
| 671 | if (loop != default_loop) |
| 672 | uv__free(loop); |
| 673 | } |