Merge branches/quickjs to trunk. This is the way.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3621 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2021-01-02 18:10:00 +00:00
parent d293637741
commit 79022e1e1f
703 changed files with 419987 additions and 30640 deletions

287
deps/libuv/src/fs-poll.c vendored Normal file
View File

@ -0,0 +1,287 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "uv-common.h"
#ifdef _WIN32
#include "win/internal.h"
#include "win/handle-inl.h"
#define uv__make_close_pending(h) uv_want_endgame((h)->loop, (h))
#else
#include "unix/internal.h"
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
struct poll_ctx {
uv_fs_poll_t* parent_handle;
int busy_polling;
unsigned int interval;
uint64_t start_time;
uv_loop_t* loop;
uv_fs_poll_cb poll_cb;
uv_timer_t timer_handle;
uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
uv_stat_t statbuf;
struct poll_ctx* previous; /* context from previous start()..stop() period */
char path[1]; /* variable length */
};
static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b);
static void poll_cb(uv_fs_t* req);
static void timer_cb(uv_timer_t* timer);
static void timer_close_cb(uv_handle_t* handle);
static uv_stat_t zero_statbuf;
int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
handle->poll_ctx = NULL;
return 0;
}
int uv_fs_poll_start(uv_fs_poll_t* handle,
uv_fs_poll_cb cb,
const char* path,
unsigned int interval) {
struct poll_ctx* ctx;
uv_loop_t* loop;
size_t len;
int err;
if (uv_is_active((uv_handle_t*)handle))
return 0;
loop = handle->loop;
len = strlen(path);
ctx = uv__calloc(1, sizeof(*ctx) + len);
if (ctx == NULL)
return UV_ENOMEM;
ctx->loop = loop;
ctx->poll_cb = cb;
ctx->interval = interval ? interval : 1;
ctx->start_time = uv_now(loop);
ctx->parent_handle = handle;
memcpy(ctx->path, path, len + 1);
err = uv_timer_init(loop, &ctx->timer_handle);
if (err < 0)
goto error;
ctx->timer_handle.flags |= UV_HANDLE_INTERNAL;
uv__handle_unref(&ctx->timer_handle);
err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
if (err < 0)
goto error;
if (handle->poll_ctx != NULL)
ctx->previous = handle->poll_ctx;
handle->poll_ctx = ctx;
uv__handle_start(handle);
return 0;
error:
uv__free(ctx);
return err;
}
int uv_fs_poll_stop(uv_fs_poll_t* handle) {
struct poll_ctx* ctx;
if (!uv_is_active((uv_handle_t*)handle))
return 0;
ctx = handle->poll_ctx;
assert(ctx != NULL);
assert(ctx->parent_handle == handle);
/* Close the timer if it's active. If it's inactive, there's a stat request
* in progress and poll_cb will take care of the cleanup.
*/
if (uv_is_active((uv_handle_t*)&ctx->timer_handle))
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
uv__handle_stop(handle);
return 0;
}
int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
struct poll_ctx* ctx;
size_t required_len;
if (!uv_is_active((uv_handle_t*)handle)) {
*size = 0;
return UV_EINVAL;
}
ctx = handle->poll_ctx;
assert(ctx != NULL);
required_len = strlen(ctx->path);
if (required_len >= *size) {
*size = required_len + 1;
return UV_ENOBUFS;
}
memcpy(buffer, ctx->path, required_len);
*size = required_len;
buffer[required_len] = '\0';
return 0;
}
void uv__fs_poll_close(uv_fs_poll_t* handle) {
uv_fs_poll_stop(handle);
if (handle->poll_ctx == NULL)
uv__make_close_pending((uv_handle_t*)handle);
}
static void timer_cb(uv_timer_t* timer) {
struct poll_ctx* ctx;
ctx = container_of(timer, struct poll_ctx, timer_handle);
assert(ctx->parent_handle != NULL);
assert(ctx->parent_handle->poll_ctx == ctx);
ctx->start_time = uv_now(ctx->loop);
if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb))
abort();
}
static void poll_cb(uv_fs_t* req) {
uv_stat_t* statbuf;
struct poll_ctx* ctx;
uint64_t interval;
uv_fs_poll_t* handle;
ctx = container_of(req, struct poll_ctx, fs_req);
handle = ctx->parent_handle;
if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle))
goto out;
if (req->result != 0) {
if (ctx->busy_polling != req->result) {
ctx->poll_cb(ctx->parent_handle,
req->result,
&ctx->statbuf,
&zero_statbuf);
ctx->busy_polling = req->result;
}
goto out;
}
statbuf = &req->statbuf;
if (ctx->busy_polling != 0)
if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf))
ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf);
ctx->statbuf = *statbuf;
ctx->busy_polling = 1;
out:
uv_fs_req_cleanup(req);
if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle)) {
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
return;
}
/* Reschedule timer, subtract the delay from doing the stat(). */
interval = ctx->interval;
interval -= (uv_now(ctx->loop) - ctx->start_time) % interval;
if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0))
abort();
}
static void timer_close_cb(uv_handle_t* timer) {
struct poll_ctx* ctx;
struct poll_ctx* it;
struct poll_ctx* last;
uv_fs_poll_t* handle;
ctx = container_of(timer, struct poll_ctx, timer_handle);
handle = ctx->parent_handle;
if (ctx == handle->poll_ctx) {
handle->poll_ctx = ctx->previous;
if (handle->poll_ctx == NULL && uv__is_closing(handle))
uv__make_close_pending((uv_handle_t*)handle);
} else {
for (last = handle->poll_ctx, it = last->previous;
it != ctx;
last = it, it = it->previous) {
assert(last->previous != NULL);
}
last->previous = ctx->previous;
}
uv__free(ctx);
}
static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec
&& a->st_mtim.tv_nsec == b->st_mtim.tv_nsec
&& a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec
&& a->st_ctim.tv_sec == b->st_ctim.tv_sec
&& a->st_mtim.tv_sec == b->st_mtim.tv_sec
&& a->st_birthtim.tv_sec == b->st_birthtim.tv_sec
&& a->st_size == b->st_size
&& a->st_mode == b->st_mode
&& a->st_uid == b->st_uid
&& a->st_gid == b->st_gid
&& a->st_ino == b->st_ino
&& a->st_dev == b->st_dev
&& a->st_flags == b->st_flags
&& a->st_gen == b->st_gen;
}
#if defined(_WIN32)
#include "win/internal.h"
#include "win/handle-inl.h"
void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED));
uv__handle_close(handle);
}
#endif /* _WIN32 */

245
deps/libuv/src/heap-inl.h vendored Normal file
View File

@ -0,0 +1,245 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef UV_SRC_HEAP_H_
#define UV_SRC_HEAP_H_
#include <stddef.h> /* NULL */
#if defined(__GNUC__)
# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration
#else
# define HEAP_EXPORT(declaration) static declaration
#endif
struct heap_node {
struct heap_node* left;
struct heap_node* right;
struct heap_node* parent;
};
/* A binary min heap. The usual properties hold: the root is the lowest
* element in the set, the height of the tree is at most log2(nodes) and
* it's always a complete binary tree.
*
* The heap function try hard to detect corrupted tree nodes at the cost
* of a minor reduction in performance. Compile with -DNDEBUG to disable.
*/
struct heap {
struct heap_node* min;
unsigned int nelts;
};
/* Return non-zero if a < b. */
typedef int (*heap_compare_fn)(const struct heap_node* a,
const struct heap_node* b);
/* Public functions. */
HEAP_EXPORT(void heap_init(struct heap* heap));
HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap));
HEAP_EXPORT(void heap_insert(struct heap* heap,
struct heap_node* newnode,
heap_compare_fn less_than));
HEAP_EXPORT(void heap_remove(struct heap* heap,
struct heap_node* node,
heap_compare_fn less_than));
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than));
/* Implementation follows. */
HEAP_EXPORT(void heap_init(struct heap* heap)) {
heap->min = NULL;
heap->nelts = 0;
}
HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) {
return heap->min;
}
/* Swap parent with child. Child moves closer to the root, parent moves away. */
static void heap_node_swap(struct heap* heap,
struct heap_node* parent,
struct heap_node* child) {
struct heap_node* sibling;
struct heap_node t;
t = *parent;
*parent = *child;
*child = t;
parent->parent = child;
if (child->left == child) {
child->left = parent;
sibling = child->right;
} else {
child->right = parent;
sibling = child->left;
}
if (sibling != NULL)
sibling->parent = child;
if (parent->left != NULL)
parent->left->parent = parent;
if (parent->right != NULL)
parent->right->parent = parent;
if (child->parent == NULL)
heap->min = child;
else if (child->parent->left == parent)
child->parent->left = child;
else
child->parent->right = child;
}
HEAP_EXPORT(void heap_insert(struct heap* heap,
struct heap_node* newnode,
heap_compare_fn less_than)) {
struct heap_node** parent;
struct heap_node** child;
unsigned int path;
unsigned int n;
unsigned int k;
newnode->left = NULL;
newnode->right = NULL;
newnode->parent = NULL;
/* Calculate the path from the root to the insertion point. This is a min
* heap so we always insert at the left-most free node of the bottom row.
*/
path = 0;
for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2)
path = (path << 1) | (n & 1);
/* Now traverse the heap using the path we calculated in the previous step. */
parent = child = &heap->min;
while (k > 0) {
parent = child;
if (path & 1)
child = &(*child)->right;
else
child = &(*child)->left;
path >>= 1;
k -= 1;
}
/* Insert the new node. */
newnode->parent = *parent;
*child = newnode;
heap->nelts += 1;
/* Walk up the tree and check at each node if the heap property holds.
* It's a min heap so parent < child must be true.
*/
while (newnode->parent != NULL && less_than(newnode, newnode->parent))
heap_node_swap(heap, newnode->parent, newnode);
}
HEAP_EXPORT(void heap_remove(struct heap* heap,
struct heap_node* node,
heap_compare_fn less_than)) {
struct heap_node* smallest;
struct heap_node** max;
struct heap_node* child;
unsigned int path;
unsigned int k;
unsigned int n;
if (heap->nelts == 0)
return;
/* Calculate the path from the min (the root) to the max, the left-most node
* of the bottom row.
*/
path = 0;
for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2)
path = (path << 1) | (n & 1);
/* Now traverse the heap using the path we calculated in the previous step. */
max = &heap->min;
while (k > 0) {
if (path & 1)
max = &(*max)->right;
else
max = &(*max)->left;
path >>= 1;
k -= 1;
}
heap->nelts -= 1;
/* Unlink the max node. */
child = *max;
*max = NULL;
if (child == node) {
/* We're removing either the max or the last node in the tree. */
if (child == heap->min) {
heap->min = NULL;
}
return;
}
/* Replace the to be deleted node with the max node. */
child->left = node->left;
child->right = node->right;
child->parent = node->parent;
if (child->left != NULL) {
child->left->parent = child;
}
if (child->right != NULL) {
child->right->parent = child;
}
if (node->parent == NULL) {
heap->min = child;
} else if (node->parent->left == node) {
node->parent->left = child;
} else {
node->parent->right = child;
}
/* Walk down the subtree and check at each node if the heap property holds.
* It's a min heap so parent < child must be true. If the parent is bigger,
* swap it with the smallest child.
*/
for (;;) {
smallest = child;
if (child->left != NULL && less_than(child->left, smallest))
smallest = child->left;
if (child->right != NULL && less_than(child->right, smallest))
smallest = child->right;
if (smallest == child)
break;
heap_node_swap(heap, child, smallest);
}
/* Walk up the subtree and check that each parent is less than the node
* this is required, because `max` node is not guaranteed to be the
* actual maximum in tree
*/
while (child->parent != NULL && less_than(child, child->parent))
heap_node_swap(heap, child->parent, child);
}
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
heap_remove(heap, heap->min, less_than);
}
#undef HEAP_EXPORT
#endif /* UV_SRC_HEAP_H_ */

291
deps/libuv/src/idna.c vendored Normal file
View File

@ -0,0 +1,291 @@
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Derived from https://github.com/bnoordhuis/punycode
* but updated to support IDNA 2008.
*/
#include "uv.h"
#include "idna.h"
#include <string.h>
static unsigned uv__utf8_decode1_slow(const char** p,
const char* pe,
unsigned a) {
unsigned b;
unsigned c;
unsigned d;
unsigned min;
if (a > 0xF7)
return -1;
switch (*p - pe) {
default:
if (a > 0xEF) {
min = 0x10000;
a = a & 7;
b = (unsigned char) *(*p)++;
c = (unsigned char) *(*p)++;
d = (unsigned char) *(*p)++;
break;
}
/* Fall through. */
case 2:
if (a > 0xDF) {
min = 0x800;
b = 0x80 | (a & 15);
c = (unsigned char) *(*p)++;
d = (unsigned char) *(*p)++;
a = 0;
break;
}
/* Fall through. */
case 1:
if (a > 0xBF) {
min = 0x80;
b = 0x80;
c = 0x80 | (a & 31);
d = (unsigned char) *(*p)++;
a = 0;
break;
}
return -1; /* Invalid continuation byte. */
}
if (0x80 != (0xC0 & (b ^ c ^ d)))
return -1; /* Invalid sequence. */
b &= 63;
c &= 63;
d &= 63;
a = (a << 18) | (b << 12) | (c << 6) | d;
if (a < min)
return -1; /* Overlong sequence. */
if (a > 0x10FFFF)
return -1; /* Four-byte sequence > U+10FFFF. */
if (a >= 0xD800 && a <= 0xDFFF)
return -1; /* Surrogate pair. */
return a;
}
unsigned uv__utf8_decode1(const char** p, const char* pe) {
unsigned a;
a = (unsigned char) *(*p)++;
if (a < 128)
return a; /* ASCII, common case. */
return uv__utf8_decode1_slow(p, pe, a);
}
#define foreach_codepoint(c, p, pe) \
for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;)
static int uv__idna_toascii_label(const char* s, const char* se,
char** d, char* de) {
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
const char* ss;
unsigned c;
unsigned h;
unsigned k;
unsigned n;
unsigned m;
unsigned q;
unsigned t;
unsigned x;
unsigned y;
unsigned bias;
unsigned delta;
unsigned todo;
int first;
h = 0;
ss = s;
todo = 0;
foreach_codepoint(c, &s, se) {
if (c < 128)
h++;
else if (c == (unsigned) -1)
return UV_EINVAL;
else
todo++;
}
if (todo > 0) {
if (*d < de) *(*d)++ = 'x';
if (*d < de) *(*d)++ = 'n';
if (*d < de) *(*d)++ = '-';
if (*d < de) *(*d)++ = '-';
}
x = 0;
s = ss;
foreach_codepoint(c, &s, se) {
if (c > 127)
continue;
if (*d < de)
*(*d)++ = c;
if (++x == h)
break; /* Visited all ASCII characters. */
}
if (todo == 0)
return h;
/* Only write separator when we've written ASCII characters first. */
if (h > 0)
if (*d < de)
*(*d)++ = '-';
n = 128;
bias = 72;
delta = 0;
first = 1;
while (todo > 0) {
m = -1;
s = ss;
foreach_codepoint(c, &s, se)
if (c >= n)
if (c < m)
m = c;
x = m - n;
y = h + 1;
if (x > ~delta / y)
return UV_E2BIG; /* Overflow. */
delta += x * y;
n = m;
s = ss;
foreach_codepoint(c, &s, se) {
if (c < n)
if (++delta == 0)
return UV_E2BIG; /* Overflow. */
if (c != n)
continue;
for (k = 36, q = delta; /* empty */; k += 36) {
t = 1;
if (k > bias)
t = k - bias;
if (t > 26)
t = 26;
if (q < t)
break;
/* TODO(bnoordhuis) Since 1 <= t <= 26 and therefore
* 10 <= y <= 35, we can optimize the long division
* into a table-based reciprocal multiplication.
*/
x = q - t;
y = 36 - t; /* 10 <= y <= 35 since 1 <= t <= 26. */
q = x / y;
t = t + x % y; /* 1 <= t <= 35 because of y. */
if (*d < de)
*(*d)++ = alphabet[t];
}
if (*d < de)
*(*d)++ = alphabet[q];
delta /= 2;
if (first) {
delta /= 350;
first = 0;
}
/* No overflow check is needed because |delta| was just
* divided by 2 and |delta+delta >= delta + delta/h|.
*/
h++;
delta += delta / h;
for (bias = 0; delta > 35 * 26 / 2; bias += 36)
delta /= 35;
bias += 36 * delta / (delta + 38);
delta = 0;
todo--;
}
delta++;
n++;
}
return 0;
}
#undef foreach_codepoint
long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
const char* si;
const char* st;
unsigned c;
char* ds;
int rc;
ds = d;
for (si = s; si < se; /* empty */) {
st = si;
c = uv__utf8_decode1(&si, se);
if (c != '.')
if (c != 0x3002) /* 。 */
if (c != 0xFF0E) /* */
if (c != 0xFF61) /* 。 */
continue;
rc = uv__idna_toascii_label(s, st, &d, de);
if (rc < 0)
return rc;
if (d < de)
*d++ = '.';
s = si;
}
if (s < se) {
rc = uv__idna_toascii_label(s, se, &d, de);
if (rc < 0)
return rc;
}
if (d < de)
*d++ = '\0';
return d - ds; /* Number of bytes written. */
}

31
deps/libuv/src/idna.h vendored Normal file
View File

@ -0,0 +1,31 @@
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef UV_SRC_IDNA_H_
#define UV_SRC_IDNA_H_
/* Decode a single codepoint. Returns the codepoint or UINT32_MAX on error.
* |p| is updated on success _and_ error, i.e., bad multi-byte sequences are
* skipped in their entirety, not just the first bad byte.
*/
unsigned uv__utf8_decode1(const char** p, const char* pe);
/* Convert a UTF-8 domain name to IDNA 2008 / Punycode. A return value >= 0
* is the number of bytes written to |d|, including the trailing nul byte.
* A return value < 0 is a libuv error code. |s| and |d| can not overlap.
*/
long uv__idna_toascii(const char* s, const char* se, char* d, char* de);
#endif /* UV_SRC_IDNA_H_ */

302
deps/libuv/src/inet.c vendored Normal file
View File

@ -0,0 +1,302 @@
/*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
# include "uv/stdint-msvc2008.h"
#else
# include <stdint.h>
#endif
#include "uv.h"
#include "uv-common.h"
#define UV__INET_ADDRSTRLEN 16
#define UV__INET6_ADDRSTRLEN 46
static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
static int inet_pton4(const char *src, unsigned char *dst);
static int inet_pton6(const char *src, unsigned char *dst);
int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
switch (af) {
case AF_INET:
return (inet_ntop4(src, dst, size));
case AF_INET6:
return (inet_ntop6(src, dst, size));
default:
return UV_EAFNOSUPPORT;
}
/* NOTREACHED */
}
static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
static const char fmt[] = "%u.%u.%u.%u";
char tmp[UV__INET_ADDRSTRLEN];
int l;
l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
if (l <= 0 || (size_t) l >= size) {
return UV_ENOSPC;
}
uv__strscpy(dst, tmp, size);
return 0;
}
static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[UV__INET6_ADDRSTRLEN], *tp;
struct { int base, len; } best, cur;
unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
int i;
/*
* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
memset(words, '\0', sizeof words);
for (i = 0; i < (int) sizeof(struct in6_addr); i++)
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
best.base = -1;
best.len = 0;
cur.base = -1;
cur.len = 0;
for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
if (words[i] == 0) {
if (cur.base == -1)
cur.base = i, cur.len = 1;
else
cur.len++;
} else {
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1;
}
}
}
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
}
if (best.base != -1 && best.len < 2)
best.base = -1;
/*
* Format the result.
*/
tp = tmp;
for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base &&
i < (best.base + best.len)) {
if (i == best.base)
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*tp++ = ':';
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 && (best.len == 6 ||
(best.len == 7 && words[7] != 0x0001) ||
(best.len == 5 && words[5] == 0xffff))) {
int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
if (err)
return err;
tp += strlen(tp);
break;
}
tp += sprintf(tp, "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
*tp++ = ':';
*tp++ = '\0';
if (UV_E2BIG == uv__strscpy(dst, tmp, size))
return UV_ENOSPC;
return 0;
}
int uv_inet_pton(int af, const char* src, void* dst) {
if (src == NULL || dst == NULL)
return UV_EINVAL;
switch (af) {
case AF_INET:
return (inet_pton4(src, dst));
case AF_INET6: {
int len;
char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
s = (char*) src;
p = strchr(src, '%');
if (p != NULL) {
s = tmp;
len = p - src;
if (len > UV__INET6_ADDRSTRLEN-1)
return UV_EINVAL;
memcpy(s, src, len);
s[len] = '\0';
}
return inet_pton6(s, dst);
}
default:
return UV_EAFNOSUPPORT;
}
/* NOTREACHED */
}
static int inet_pton4(const char *src, unsigned char *dst) {
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
unsigned char tmp[sizeof(struct in_addr)], *tp;
saw_digit = 0;
octets = 0;
*(tp = tmp) = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr(digits, ch)) != NULL) {
unsigned int nw = *tp * 10 + (pch - digits);
if (saw_digit && *tp == 0)
return UV_EINVAL;
if (nw > 255)
return UV_EINVAL;
*tp = nw;
if (!saw_digit) {
if (++octets > 4)
return UV_EINVAL;
saw_digit = 1;
}
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return UV_EINVAL;
*++tp = 0;
saw_digit = 0;
} else
return UV_EINVAL;
}
if (octets < 4)
return UV_EINVAL;
memcpy(dst, tmp, sizeof(struct in_addr));
return 0;
}
static int inet_pton6(const char *src, unsigned char *dst) {
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, seen_xdigits;
unsigned int val;
memset((tp = tmp), '\0', sizeof tmp);
endp = tp + sizeof tmp;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return UV_EINVAL;
curtok = src;
seen_xdigits = 0;
val = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (++seen_xdigits > 4)
return UV_EINVAL;
continue;
}
if (ch == ':') {
curtok = src;
if (!seen_xdigits) {
if (colonp)
return UV_EINVAL;
colonp = tp;
continue;
} else if (*src == '\0') {
return UV_EINVAL;
}
if (tp + sizeof(uint16_t) > endp)
return UV_EINVAL;
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
seen_xdigits = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
int err = inet_pton4(curtok, tp);
if (err == 0) {
tp += sizeof(struct in_addr);
seen_xdigits = 0;
break; /*%< '\\0' was seen by inet_pton4(). */
}
}
return UV_EINVAL;
}
if (seen_xdigits) {
if (tp + sizeof(uint16_t) > endp)
return UV_EINVAL;
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
}
if (colonp != NULL) {
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
const int n = tp - colonp;
int i;
if (tp == endp)
return UV_EINVAL;
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return UV_EINVAL;
memcpy(dst, tmp, sizeof tmp);
return 0;
}

108
deps/libuv/src/queue.h vendored Normal file
View File

@ -0,0 +1,108 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef QUEUE_H_
#define QUEUE_H_
#include <stddef.h>
typedef void *QUEUE[2];
/* Private macros. */
#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
/* Public macros. */
#define QUEUE_DATA(ptr, type, field) \
((type *) ((char *) (ptr) - offsetof(type, field)))
/* Important note: mutating the list while QUEUE_FOREACH is
* iterating over its elements results in undefined behavior.
*/
#define QUEUE_FOREACH(q, h) \
for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
#define QUEUE_EMPTY(q) \
((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
#define QUEUE_HEAD(q) \
(QUEUE_NEXT(q))
#define QUEUE_INIT(q) \
do { \
QUEUE_NEXT(q) = (q); \
QUEUE_PREV(q) = (q); \
} \
while (0)
#define QUEUE_ADD(h, n) \
do { \
QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
QUEUE_PREV(h) = QUEUE_PREV(n); \
QUEUE_PREV_NEXT(h) = (h); \
} \
while (0)
#define QUEUE_SPLIT(h, q, n) \
do { \
QUEUE_PREV(n) = QUEUE_PREV(h); \
QUEUE_PREV_NEXT(n) = (n); \
QUEUE_NEXT(n) = (q); \
QUEUE_PREV(h) = QUEUE_PREV(q); \
QUEUE_PREV_NEXT(h) = (h); \
QUEUE_PREV(q) = (n); \
} \
while (0)
#define QUEUE_MOVE(h, n) \
do { \
if (QUEUE_EMPTY(h)) \
QUEUE_INIT(n); \
else { \
QUEUE* q = QUEUE_HEAD(h); \
QUEUE_SPLIT(h, q, n); \
} \
} \
while (0)
#define QUEUE_INSERT_HEAD(h, q) \
do { \
QUEUE_NEXT(q) = QUEUE_NEXT(h); \
QUEUE_PREV(q) = (h); \
QUEUE_NEXT_PREV(q) = (q); \
QUEUE_NEXT(h) = (q); \
} \
while (0)
#define QUEUE_INSERT_TAIL(h, q) \
do { \
QUEUE_NEXT(q) = (h); \
QUEUE_PREV(q) = QUEUE_PREV(h); \
QUEUE_PREV_NEXT(q) = (q); \
QUEUE_PREV(h) = (q); \
} \
while (0)
#define QUEUE_REMOVE(q) \
do { \
QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
} \
while (0)
#endif /* QUEUE_H_ */

123
deps/libuv/src/random.c vendored Normal file
View File

@ -0,0 +1,123 @@
/* Copyright libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "uv-common.h"
#ifdef _WIN32
# include "win/internal.h"
#else
# include "unix/internal.h"
#endif
static int uv__random(void* buf, size_t buflen) {
int rc;
#if defined(__PASE__)
rc = uv__random_readpath("/dev/urandom", buf, buflen);
#elif defined(_AIX) || defined(__QNX__)
rc = uv__random_readpath("/dev/random", buf, buflen);
#elif defined(__APPLE__) || defined(__OpenBSD__) || \
(defined(__ANDROID_API__) && __ANDROID_API__ >= 28)
rc = uv__random_getentropy(buf, buflen);
if (rc == UV_ENOSYS)
rc = uv__random_devurandom(buf, buflen);
#elif defined(__NetBSD__)
rc = uv__random_sysctl(buf, buflen);
#elif defined(__FreeBSD__) || defined(__linux__)
rc = uv__random_getrandom(buf, buflen);
if (rc == UV_ENOSYS)
rc = uv__random_devurandom(buf, buflen);
# if defined(__linux__)
switch (rc) {
case UV_EACCES:
case UV_EIO:
case UV_ELOOP:
case UV_EMFILE:
case UV_ENFILE:
case UV_ENOENT:
case UV_EPERM:
rc = uv__random_sysctl(buf, buflen);
break;
}
# endif
#elif defined(_WIN32)
uv__once_init();
rc = uv__random_rtlgenrandom(buf, buflen);
#else
rc = uv__random_devurandom(buf, buflen);
#endif
return rc;
}
static void uv__random_work(struct uv__work* w) {
uv_random_t* req;
req = container_of(w, uv_random_t, work_req);
req->status = uv__random(req->buf, req->buflen);
}
static void uv__random_done(struct uv__work* w, int status) {
uv_random_t* req;
req = container_of(w, uv_random_t, work_req);
uv__req_unregister(req->loop, req);
if (status == 0)
status = req->status;
req->cb(req, status, req->buf, req->buflen);
}
int uv_random(uv_loop_t* loop,
uv_random_t* req,
void *buf,
size_t buflen,
unsigned flags,
uv_random_cb cb) {
if (buflen > 0x7FFFFFFFu)
return UV_E2BIG;
if (flags != 0)
return UV_EINVAL;
if (cb == NULL)
return uv__random(buf, buflen);
uv__req_init(loop, req, UV_RANDOM);
req->loop = loop;
req->status = 0;
req->cb = cb;
req->buf = buf;
req->buflen = buflen;
uv__work_submit(loop,
&req->work_req,
UV__WORK_CPU,
uv__random_work,
uv__random_done);
return 0;
}

38
deps/libuv/src/strscpy.c vendored Normal file
View File

@ -0,0 +1,38 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "strscpy.h"
#include <limits.h> /* SSIZE_MAX */
ssize_t uv__strscpy(char* d, const char* s, size_t n) {
size_t i;
for (i = 0; i < n; i++)
if ('\0' == (d[i] = s[i]))
return i > SSIZE_MAX ? UV_E2BIG : (ssize_t) i;
if (i == 0)
return 0;
d[--i] = '\0';
return UV_E2BIG;
}

39
deps/libuv/src/strscpy.h vendored Normal file
View File

@ -0,0 +1,39 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_STRSCPY_H_
#define UV_STRSCPY_H_
/* Include uv.h for its definitions of size_t and ssize_t.
* size_t can be obtained directly from <stddef.h> but ssize_t requires
* some hoop jumping on Windows that I didn't want to duplicate here.
*/
#include "uv.h"
/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates
* the result, except when |n==0|. Returns the number of bytes copied
* or UV_E2BIG if |d| is too small.
*
* See https://www.kernel.org/doc/htmldocs/kernel-api/API-strscpy.html
*/
ssize_t uv__strscpy(char* d, const char* s, size_t n);
#endif /* UV_STRSCPY_H_ */

388
deps/libuv/src/threadpool.c vendored Normal file
View File

@ -0,0 +1,388 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv-common.h"
#if !defined(_WIN32)
# include "unix/internal.h"
#endif
#include <stdlib.h>
#define MAX_THREADPOOL_SIZE 1024
static uv_once_t once = UV_ONCE_INIT;
static uv_cond_t cond;
static uv_mutex_t mutex;
static unsigned int idle_threads;
static unsigned int slow_io_work_running;
static unsigned int nthreads;
static uv_thread_t* threads;
static uv_thread_t default_threads[4];
static QUEUE exit_message;
static QUEUE wq;
static QUEUE run_slow_work_message;
static QUEUE slow_io_pending_wq;
static unsigned int slow_work_thread_threshold(void) {
return (nthreads + 1) / 2;
}
static void uv__cancelled(struct uv__work* w) {
abort();
}
/* To avoid deadlock with uv_cancel() it's crucial that the worker
* never holds the global mutex and the loop-local mutex at the same time.
*/
static void worker(void* arg) {
struct uv__work* w;
QUEUE* q;
int is_slow_work;
uv_sem_post((uv_sem_t*) arg);
arg = NULL;
uv_mutex_lock(&mutex);
for (;;) {
/* `mutex` should always be locked at this point. */
/* Keep waiting while either no work is present or only slow I/O
and we're at the threshold for that. */
while (QUEUE_EMPTY(&wq) ||
(QUEUE_HEAD(&wq) == &run_slow_work_message &&
QUEUE_NEXT(&run_slow_work_message) == &wq &&
slow_io_work_running >= slow_work_thread_threshold())) {
idle_threads += 1;
uv_cond_wait(&cond, &mutex);
idle_threads -= 1;
}
q = QUEUE_HEAD(&wq);
if (q == &exit_message) {
uv_cond_signal(&cond);
uv_mutex_unlock(&mutex);
break;
}
QUEUE_REMOVE(q);
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */
is_slow_work = 0;
if (q == &run_slow_work_message) {
/* If we're at the slow I/O threshold, re-schedule until after all
other work in the queue is done. */
if (slow_io_work_running >= slow_work_thread_threshold()) {
QUEUE_INSERT_TAIL(&wq, q);
continue;
}
/* If we encountered a request to run slow I/O work but there is none
to run, that means it's cancelled => Start over. */
if (QUEUE_EMPTY(&slow_io_pending_wq))
continue;
is_slow_work = 1;
slow_io_work_running++;
q = QUEUE_HEAD(&slow_io_pending_wq);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
/* If there is more slow I/O work, schedule it to be run as well. */
if (!QUEUE_EMPTY(&slow_io_pending_wq)) {
QUEUE_INSERT_TAIL(&wq, &run_slow_work_message);
if (idle_threads > 0)
uv_cond_signal(&cond);
}
}
uv_mutex_unlock(&mutex);
w = QUEUE_DATA(q, struct uv__work, wq);
w->work(w);
uv_mutex_lock(&w->loop->wq_mutex);
w->work = NULL; /* Signal uv_cancel() that the work req is done
executing. */
QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
uv_async_send(&w->loop->wq_async);
uv_mutex_unlock(&w->loop->wq_mutex);
/* Lock `mutex` since that is expected at the start of the next
* iteration. */
uv_mutex_lock(&mutex);
if (is_slow_work) {
/* `slow_io_work_running` is protected by `mutex`. */
slow_io_work_running--;
}
}
}
static void post(QUEUE* q, enum uv__work_kind kind) {
uv_mutex_lock(&mutex);
if (kind == UV__WORK_SLOW_IO) {
/* Insert into a separate queue. */
QUEUE_INSERT_TAIL(&slow_io_pending_wq, q);
if (!QUEUE_EMPTY(&run_slow_work_message)) {
/* Running slow I/O tasks is already scheduled => Nothing to do here.
The worker that runs said other task will schedule this one as well. */
uv_mutex_unlock(&mutex);
return;
}
q = &run_slow_work_message;
}
QUEUE_INSERT_TAIL(&wq, q);
if (idle_threads > 0)
uv_cond_signal(&cond);
uv_mutex_unlock(&mutex);
}
void uv__threadpool_cleanup(void) {
#ifndef _WIN32
unsigned int i;
if (nthreads == 0)
return;
post(&exit_message, UV__WORK_CPU);
for (i = 0; i < nthreads; i++)
if (uv_thread_join(threads + i))
abort();
if (threads != default_threads)
uv__free(threads);
uv_mutex_destroy(&mutex);
uv_cond_destroy(&cond);
threads = NULL;
nthreads = 0;
#endif
}
static void init_threads(void) {
unsigned int i;
const char* val;
uv_sem_t sem;
nthreads = ARRAY_SIZE(default_threads);
val = getenv("UV_THREADPOOL_SIZE");
if (val != NULL)
nthreads = atoi(val);
if (nthreads == 0)
nthreads = 1;
if (nthreads > MAX_THREADPOOL_SIZE)
nthreads = MAX_THREADPOOL_SIZE;
threads = default_threads;
if (nthreads > ARRAY_SIZE(default_threads)) {
threads = uv__malloc(nthreads * sizeof(threads[0]));
if (threads == NULL) {
nthreads = ARRAY_SIZE(default_threads);
threads = default_threads;
}
}
if (uv_cond_init(&cond))
abort();
if (uv_mutex_init(&mutex))
abort();
QUEUE_INIT(&wq);
QUEUE_INIT(&slow_io_pending_wq);
QUEUE_INIT(&run_slow_work_message);
if (uv_sem_init(&sem, 0))
abort();
for (i = 0; i < nthreads; i++)
if (uv_thread_create(threads + i, worker, &sem))
abort();
for (i = 0; i < nthreads; i++)
uv_sem_wait(&sem);
uv_sem_destroy(&sem);
}
#ifndef _WIN32
static void reset_once(void) {
uv_once_t child_once = UV_ONCE_INIT;
memcpy(&once, &child_once, sizeof(child_once));
}
#endif
static void init_once(void) {
#ifndef _WIN32
/* Re-initialize the threadpool after fork.
* Note that this discards the global mutex and condition as well
* as the work queue.
*/
if (pthread_atfork(NULL, NULL, &reset_once))
abort();
#endif
init_threads();
}
void uv__work_submit(uv_loop_t* loop,
struct uv__work* w,
enum uv__work_kind kind,
void (*work)(struct uv__work* w),
void (*done)(struct uv__work* w, int status)) {
uv_once(&once, init_once);
w->loop = loop;
w->work = work;
w->done = done;
post(&w->wq, kind);
}
static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
int cancelled;
uv_mutex_lock(&mutex);
uv_mutex_lock(&w->loop->wq_mutex);
cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
if (cancelled)
QUEUE_REMOVE(&w->wq);
uv_mutex_unlock(&w->loop->wq_mutex);
uv_mutex_unlock(&mutex);
if (!cancelled)
return UV_EBUSY;
w->work = uv__cancelled;
uv_mutex_lock(&loop->wq_mutex);
QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
uv_async_send(&loop->wq_async);
uv_mutex_unlock(&loop->wq_mutex);
return 0;
}
void uv__work_done(uv_async_t* handle) {
struct uv__work* w;
uv_loop_t* loop;
QUEUE* q;
QUEUE wq;
int err;
loop = container_of(handle, uv_loop_t, wq_async);
uv_mutex_lock(&loop->wq_mutex);
QUEUE_MOVE(&loop->wq, &wq);
uv_mutex_unlock(&loop->wq_mutex);
while (!QUEUE_EMPTY(&wq)) {
q = QUEUE_HEAD(&wq);
QUEUE_REMOVE(q);
w = container_of(q, struct uv__work, wq);
err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
w->done(w, err);
}
}
static void uv__queue_work(struct uv__work* w) {
uv_work_t* req = container_of(w, uv_work_t, work_req);
req->work_cb(req);
}
static void uv__queue_done(struct uv__work* w, int err) {
uv_work_t* req;
req = container_of(w, uv_work_t, work_req);
uv__req_unregister(req->loop, req);
if (req->after_work_cb == NULL)
return;
req->after_work_cb(req, err);
}
int uv_queue_work(uv_loop_t* loop,
uv_work_t* req,
uv_work_cb work_cb,
uv_after_work_cb after_work_cb) {
if (work_cb == NULL)
return UV_EINVAL;
uv__req_init(loop, req, UV_WORK);
req->loop = loop;
req->work_cb = work_cb;
req->after_work_cb = after_work_cb;
uv__work_submit(loop,
&req->work_req,
UV__WORK_CPU,
uv__queue_work,
uv__queue_done);
return 0;
}
int uv_cancel(uv_req_t* req) {
struct uv__work* wreq;
uv_loop_t* loop;
switch (req->type) {
case UV_FS:
loop = ((uv_fs_t*) req)->loop;
wreq = &((uv_fs_t*) req)->work_req;
break;
case UV_GETADDRINFO:
loop = ((uv_getaddrinfo_t*) req)->loop;
wreq = &((uv_getaddrinfo_t*) req)->work_req;
break;
case UV_GETNAMEINFO:
loop = ((uv_getnameinfo_t*) req)->loop;
wreq = &((uv_getnameinfo_t*) req)->work_req;
break;
case UV_RANDOM:
loop = ((uv_random_t*) req)->loop;
wreq = &((uv_random_t*) req)->work_req;
break;
case UV_WORK:
loop = ((uv_work_t*) req)->loop;
wreq = &((uv_work_t*) req)->work_req;
break;
default:
return UV_EINVAL;
}
return uv__work_cancel(loop, req, wreq);
}

184
deps/libuv/src/timer.c vendored Normal file
View File

@ -0,0 +1,184 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "uv-common.h"
#include "heap-inl.h"
#include <assert.h>
#include <limits.h>
static struct heap *timer_heap(const uv_loop_t* loop) {
#ifdef _WIN32
return (struct heap*) loop->timer_heap;
#else
return (struct heap*) &loop->timer_heap;
#endif
}
static int timer_less_than(const struct heap_node* ha,
const struct heap_node* hb) {
const uv_timer_t* a;
const uv_timer_t* b;
a = container_of(ha, uv_timer_t, heap_node);
b = container_of(hb, uv_timer_t, heap_node);
if (a->timeout < b->timeout)
return 1;
if (b->timeout < a->timeout)
return 0;
/* Compare start_id when both have the same timeout. start_id is
* allocated with loop->timer_counter in uv_timer_start().
*/
return a->start_id < b->start_id;
}
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
handle->timer_cb = NULL;
handle->repeat = 0;
return 0;
}
int uv_timer_start(uv_timer_t* handle,
uv_timer_cb cb,
uint64_t timeout,
uint64_t repeat) {
uint64_t clamped_timeout;
if (uv__is_closing(handle) || cb == NULL)
return UV_EINVAL;
if (uv__is_active(handle))
uv_timer_stop(handle);
clamped_timeout = handle->loop->time + timeout;
if (clamped_timeout < timeout)
clamped_timeout = (uint64_t) -1;
handle->timer_cb = cb;
handle->timeout = clamped_timeout;
handle->repeat = repeat;
/* start_id is the second index to be compared in timer_less_than() */
handle->start_id = handle->loop->timer_counter++;
heap_insert(timer_heap(handle->loop),
(struct heap_node*) &handle->heap_node,
timer_less_than);
uv__handle_start(handle);
return 0;
}
int uv_timer_stop(uv_timer_t* handle) {
if (!uv__is_active(handle))
return 0;
heap_remove(timer_heap(handle->loop),
(struct heap_node*) &handle->heap_node,
timer_less_than);
uv__handle_stop(handle);
return 0;
}
int uv_timer_again(uv_timer_t* handle) {
if (handle->timer_cb == NULL)
return UV_EINVAL;
if (handle->repeat) {
uv_timer_stop(handle);
uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
}
return 0;
}
void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
handle->repeat = repeat;
}
uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
return handle->repeat;
}
uint64_t uv_timer_get_due_in(const uv_timer_t* handle) {
if (handle->loop->time >= handle->timeout)
return 0;
return handle->timeout - handle->loop->time;
}
int uv__next_timeout(const uv_loop_t* loop) {
const struct heap_node* heap_node;
const uv_timer_t* handle;
uint64_t diff;
heap_node = heap_min(timer_heap(loop));
if (heap_node == NULL)
return -1; /* block indefinitely */
handle = container_of(heap_node, uv_timer_t, heap_node);
if (handle->timeout <= loop->time)
return 0;
diff = handle->timeout - loop->time;
if (diff > INT_MAX)
diff = INT_MAX;
return (int) diff;
}
void uv__run_timers(uv_loop_t* loop) {
struct heap_node* heap_node;
uv_timer_t* handle;
for (;;) {
heap_node = heap_min(timer_heap(loop));
if (heap_node == NULL)
break;
handle = container_of(heap_node, uv_timer_t, heap_node);
if (handle->timeout > loop->time)
break;
uv_timer_stop(handle);
uv_timer_again(handle);
handle->timer_cb(handle);
}
}
void uv__timer_close(uv_timer_t* handle) {
uv_timer_stop(handle);
}

89
deps/libuv/src/unix/aix-common.c vendored Normal file
View File

@ -0,0 +1,89 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <procinfo.h>
#include <ctype.h>
extern char* original_exepath;
extern uv_mutex_t process_title_mutex;
extern uv_once_t process_title_mutex_once;
extern void init_process_title_mutex_once(void);
uint64_t uv__hrtime(uv_clocktype_t type) {
uint64_t G = 1000000000;
timebasestruct_t t;
read_wall_time(&t, TIMEBASE_SZ);
time_base_to_time(&t, TIMEBASE_SZ);
return (uint64_t) t.tb_high * G + t.tb_low;
}
/*
* We could use a static buffer for the path manipulations that we need outside
* of the function, but this function could be called by multiple consumers and
* we don't want to potentially create a race condition in the use of snprintf.
* There is no direct way of getting the exe path in AIX - either through /procfs
* or through some libc APIs. The below approach is to parse the argv[0]'s pattern
* and use it in conjunction with PATH environment variable to craft one.
*/
int uv_exepath(char* buffer, size_t* size) {
int res;
char args[UV__PATH_MAX];
size_t cached_len;
struct procsinfo pi;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
if (original_exepath != NULL) {
cached_len = strlen(original_exepath);
*size -= 1;
if (*size > cached_len)
*size = cached_len;
memcpy(buffer, original_exepath, *size);
buffer[*size] = '\0';
uv_mutex_unlock(&process_title_mutex);
return 0;
}
uv_mutex_unlock(&process_title_mutex);
pi.pi_pid = getpid();
res = getargs(&pi, sizeof(pi), args, sizeof(args));
if (res < 0)
return UV_EINVAL;
return uv__search_path(args, buffer, size);
}

1304
deps/libuv/src/unix/aix.c vendored Normal file

File diff suppressed because it is too large Load Diff

713
deps/libuv/src/unix/android-ifaddrs.c vendored Normal file
View File

@ -0,0 +1,713 @@
/*
Copyright (c) 2013, Kenneth MacKay
Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "uv/android-ifaddrs.h"
#include "uv-common.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if_packet.h>
typedef struct NetlinkList
{
struct NetlinkList *m_next;
struct nlmsghdr *m_data;
unsigned int m_size;
} NetlinkList;
static int netlink_socket(pid_t *p_pid)
{
struct sockaddr_nl l_addr;
socklen_t l_len;
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if(l_socket < 0)
{
return -1;
}
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
{
close(l_socket);
return -1;
}
l_len = sizeof(l_addr);
if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
{
close(l_socket);
return -1;
}
*p_pid = l_addr.nl_pid;
return l_socket;
}
static int netlink_send(int p_socket, int p_request)
{
char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
struct nlmsghdr *l_hdr;
struct rtgenmsg *l_msg;
struct sockaddr_nl l_addr;
memset(l_buffer, 0, sizeof(l_buffer));
l_hdr = (struct nlmsghdr *)l_buffer;
l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
l_hdr->nlmsg_type = p_request;
l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
l_hdr->nlmsg_pid = 0;
l_hdr->nlmsg_seq = p_socket;
l_msg->rtgen_family = AF_UNSPEC;
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
}
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
{
struct sockaddr_nl l_addr;
struct msghdr l_msg;
struct iovec l_iov;
l_iov.iov_base = p_buffer;
l_iov.iov_len = p_len;
for(;;)
{
int l_result;
l_msg.msg_name = (void *)&l_addr;
l_msg.msg_namelen = sizeof(l_addr);
l_msg.msg_iov = &l_iov;
l_msg.msg_iovlen = 1;
l_msg.msg_control = NULL;
l_msg.msg_controllen = 0;
l_msg.msg_flags = 0;
l_result = recvmsg(p_socket, &l_msg, 0);
if(l_result < 0)
{
if(errno == EINTR)
{
continue;
}
return -2;
}
/* Buffer was too small */
if(l_msg.msg_flags & MSG_TRUNC)
{
return -1;
}
return l_result;
}
}
static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
{
size_t l_size = 4096;
void *l_buffer = NULL;
for(;;)
{
int l_read;
uv__free(l_buffer);
l_buffer = uv__malloc(l_size);
if (l_buffer == NULL)
{
return NULL;
}
l_read = netlink_recv(p_socket, l_buffer, l_size);
*p_size = l_read;
if(l_read == -2)
{
uv__free(l_buffer);
return NULL;
}
if(l_read >= 0)
{
struct nlmsghdr *l_hdr;
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
{
if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
*p_done = 1;
break;
}
if(l_hdr->nlmsg_type == NLMSG_ERROR)
{
uv__free(l_buffer);
return NULL;
}
}
return l_buffer;
}
l_size *= 2;
}
}
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
{
NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
if (l_item == NULL)
{
return NULL;
}
l_item->m_next = NULL;
l_item->m_data = p_data;
l_item->m_size = p_size;
return l_item;
}
static void freeResultList(NetlinkList *p_list)
{
NetlinkList *l_cur;
while(p_list)
{
l_cur = p_list;
p_list = p_list->m_next;
uv__free(l_cur->m_data);
uv__free(l_cur);
}
}
static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
{
int l_size;
int l_done;
NetlinkList *l_list;
NetlinkList *l_end;
if(netlink_send(p_socket, p_request) < 0)
{
return NULL;
}
l_list = NULL;
l_end = NULL;
l_done = 0;
while(!l_done)
{
NetlinkList *l_item;
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
/* Error */
if(!l_hdr)
{
freeResultList(l_list);
return NULL;
}
l_item = newListItem(l_hdr, l_size);
if (!l_item)
{
freeResultList(l_list);
return NULL;
}
if(!l_list)
{
l_list = l_item;
}
else
{
l_end->m_next = l_item;
}
l_end = l_item;
}
return l_list;
}
static size_t maxSize(size_t a, size_t b)
{
return (a > b ? a : b);
}
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
{
switch(p_family)
{
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_PACKET:
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
default:
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
}
}
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
{
switch(p_family)
{
case AF_INET:
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
break;
case AF_INET6:
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
break;
case AF_PACKET:
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
break;
default:
memcpy(p_dest->sa_data, p_data, p_size);
break;
}
p_dest->sa_family = p_family;
}
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
{
if(!*p_resultList)
{
*p_resultList = p_entry;
}
else
{
struct ifaddrs *l_cur = *p_resultList;
while(l_cur->ifa_next)
{
l_cur = l_cur->ifa_next;
}
l_cur->ifa_next = p_entry;
}
}
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
{
struct ifaddrs *l_entry;
char *l_index;
char *l_name;
char *l_addr;
char *l_data;
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
size_t l_nameSize = 0;
size_t l_addrSize = 0;
size_t l_dataSize = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
struct rtattr *l_rta;
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFLA_ADDRESS:
case IFLA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
break;
case IFLA_IFNAME:
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
break;
case IFLA_STATS:
l_dataSize += NLMSG_ALIGN(l_rtaSize);
break;
default:
break;
}
}
l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
if (l_entry == NULL)
{
return -1;
}
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = "";
l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
l_name = l_index + sizeof(int);
l_addr = l_name + l_nameSize;
l_data = l_addr + l_addrSize;
/* Save the interface index so we can look it up when handling the
* addresses.
*/
memcpy(l_index, &l_info->ifi_index, sizeof(int));
l_entry->ifa_flags = l_info->ifi_flags;
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFLA_ADDRESS:
case IFLA_BROADCAST:
{
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
if(l_rta->rta_type == IFLA_ADDRESS)
{
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFLA_IFNAME:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
case IFLA_STATS:
memcpy(l_data, l_rtaData, l_rtaDataSize);
l_entry->ifa_data = l_data;
break;
default:
break;
}
}
addToEnd(p_resultList, l_entry);
return 0;
}
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
{
int l_num = 0;
struct ifaddrs *l_cur = *p_links;
while(l_cur && l_num < p_numLinks)
{
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
int l_index;
memcpy(&l_index, l_indexPtr, sizeof(int));
if(l_index == p_index)
{
return l_cur;
}
l_cur = l_cur->ifa_next;
++l_num;
}
return NULL;
}
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
{
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
size_t l_nameSize = 0;
size_t l_addrSize = 0;
int l_addedNetmask = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
struct rtattr *l_rta;
struct ifaddrs *l_entry;
char *l_name;
char *l_addr;
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
if(l_info->ifa_family == AF_PACKET)
{
continue;
}
switch(l_rta->rta_type)
{
case IFA_ADDRESS:
case IFA_LOCAL:
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
{
/* Make room for netmask */
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
l_addedNetmask = 1;
}
break;
case IFA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
break;
case IFA_LABEL:
l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
break;
default:
break;
}
}
l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
if (l_entry == NULL)
{
return -1;
}
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
l_addr = l_name + l_nameSize;
l_entry->ifa_flags = l_info->ifa_flags;
if(l_interface)
{
l_entry->ifa_flags |= l_interface->ifa_flags;
}
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFA_ADDRESS:
case IFA_BROADCAST:
case IFA_LOCAL:
{
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
if(l_info->ifa_family == AF_INET6)
{
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
{
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
}
}
/* Apparently in a point-to-point network IFA_ADDRESS contains
* the dest address and IFA_LOCAL contains the local address
*/
if(l_rta->rta_type == IFA_ADDRESS)
{
if(l_entry->ifa_addr)
{
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
}
else if(l_rta->rta_type == IFA_LOCAL)
{
if(l_entry->ifa_addr)
{
l_entry->ifa_dstaddr = l_entry->ifa_addr;
}
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFA_LABEL:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
default:
break;
}
}
if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
{
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
unsigned char l_mask[16] = {0};
unsigned i;
for(i=0; i<(l_prefix/8); ++i)
{
l_mask[i] = 0xff;
}
if(l_prefix % 8)
{
l_mask[i] = 0xff << (8 - (l_prefix % 8));
}
makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
}
addToEnd(p_resultList, l_entry);
return 0;
}
static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
{
int l_numLinks = 0;
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
break;
}
if(l_hdr->nlmsg_type == RTM_NEWLINK)
{
if(interpretLink(l_hdr, p_resultList) == -1)
{
return -1;
}
++l_numLinks;
}
}
}
return l_numLinks;
}
static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
{
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
break;
}
if(l_hdr->nlmsg_type == RTM_NEWADDR)
{
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
{
return -1;
}
}
}
}
return 0;
}
int getifaddrs(struct ifaddrs **ifap)
{
int l_socket;
int l_result;
int l_numLinks;
pid_t l_pid;
NetlinkList *l_linkResults;
NetlinkList *l_addrResults;
if(!ifap)
{
return -1;
}
*ifap = NULL;
l_socket = netlink_socket(&l_pid);
if(l_socket < 0)
{
return -1;
}
l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
if(!l_linkResults)
{
close(l_socket);
return -1;
}
l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
if(!l_addrResults)
{
close(l_socket);
freeResultList(l_linkResults);
return -1;
}
l_result = 0;
l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
{
l_result = -1;
}
freeResultList(l_linkResults);
freeResultList(l_addrResults);
close(l_socket);
return l_result;
}
void freeifaddrs(struct ifaddrs *ifa)
{
struct ifaddrs *l_cur;
while(ifa)
{
l_cur = ifa;
ifa = ifa->ifa_next;
uv__free(l_cur);
}
}

253
deps/libuv/src/unix/async.c vendored Normal file
View File

@ -0,0 +1,253 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* This file contains both the uv__async internal infrastructure and the
* user-facing uv_async_t functions.
*/
#include "uv.h"
#include "internal.h"
#include "atomic-ops.h"
#include <errno.h>
#include <stdio.h> /* snprintf() */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h> /* sched_yield() */
#ifdef __linux__
#include <sys/eventfd.h>
#endif
static void uv__async_send(uv_loop_t* loop);
static int uv__async_start(uv_loop_t* loop);
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
int err;
err = uv__async_start(loop);
if (err)
return err;
uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
handle->async_cb = async_cb;
handle->pending = 0;
QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
uv__handle_start(handle);
return 0;
}
int uv_async_send(uv_async_t* handle) {
/* Do a cheap read first. */
if (ACCESS_ONCE(int, handle->pending) != 0)
return 0;
/* Tell the other thread we're busy with the handle. */
if (cmpxchgi(&handle->pending, 0, 1) != 0)
return 0;
/* Wake up the other thread's event loop. */
uv__async_send(handle->loop);
/* Tell the other thread we're done. */
if (cmpxchgi(&handle->pending, 1, 2) != 1)
abort();
return 0;
}
/* Only call this from the event loop thread. */
static int uv__async_spin(uv_async_t* handle) {
int i;
int rc;
for (;;) {
/* 997 is not completely chosen at random. It's a prime number, acyclical
* by nature, and should therefore hopefully dampen sympathetic resonance.
*/
for (i = 0; i < 997; i++) {
/* rc=0 -- handle is not pending.
* rc=1 -- handle is pending, other thread is still working with it.
* rc=2 -- handle is pending, other thread is done.
*/
rc = cmpxchgi(&handle->pending, 2, 0);
if (rc != 1)
return rc;
/* Other thread is busy with this handle, spin until it's done. */
cpu_relax();
}
/* Yield the CPU. We may have preempted the other thread while it's
* inside the critical section and if it's running on the same CPU
* as us, we'll just burn CPU cycles until the end of our time slice.
*/
sched_yield();
}
}
void uv__async_close(uv_async_t* handle) {
uv__async_spin(handle);
QUEUE_REMOVE(&handle->queue);
uv__handle_stop(handle);
}
static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
char buf[1024];
ssize_t r;
QUEUE queue;
QUEUE* q;
uv_async_t* h;
assert(w == &loop->async_io_watcher);
for (;;) {
r = read(w->fd, buf, sizeof(buf));
if (r == sizeof(buf))
continue;
if (r != -1)
break;
if (errno == EAGAIN || errno == EWOULDBLOCK)
break;
if (errno == EINTR)
continue;
abort();
}
QUEUE_MOVE(&loop->async_handles, &queue);
while (!QUEUE_EMPTY(&queue)) {
q = QUEUE_HEAD(&queue);
h = QUEUE_DATA(q, uv_async_t, queue);
QUEUE_REMOVE(q);
QUEUE_INSERT_TAIL(&loop->async_handles, q);
if (0 == uv__async_spin(h))
continue; /* Not pending. */
if (h->async_cb == NULL)
continue;
h->async_cb(h);
}
}
static void uv__async_send(uv_loop_t* loop) {
const void* buf;
ssize_t len;
int fd;
int r;
buf = "";
len = 1;
fd = loop->async_wfd;
#if defined(__linux__)
if (fd == -1) {
static const uint64_t val = 1;
buf = &val;
len = sizeof(val);
fd = loop->async_io_watcher.fd; /* eventfd */
}
#endif
do
r = write(fd, buf, len);
while (r == -1 && errno == EINTR);
if (r == len)
return;
if (r == -1)
if (errno == EAGAIN || errno == EWOULDBLOCK)
return;
abort();
}
static int uv__async_start(uv_loop_t* loop) {
int pipefd[2];
int err;
if (loop->async_io_watcher.fd != -1)
return 0;
#ifdef __linux__
err = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if (err < 0)
return UV__ERR(errno);
pipefd[0] = err;
pipefd[1] = -1;
#else
err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
if (err < 0)
return err;
#endif
uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]);
uv__io_start(loop, &loop->async_io_watcher, POLLIN);
loop->async_wfd = pipefd[1];
return 0;
}
int uv__async_fork(uv_loop_t* loop) {
if (loop->async_io_watcher.fd == -1) /* never started */
return 0;
uv__async_stop(loop);
return uv__async_start(loop);
}
void uv__async_stop(uv_loop_t* loop) {
if (loop->async_io_watcher.fd == -1)
return;
if (loop->async_wfd != -1) {
if (loop->async_wfd != loop->async_io_watcher.fd)
uv__close(loop->async_wfd);
loop->async_wfd = -1;
}
uv__io_stop(loop, &loop->async_io_watcher, POLLIN);
uv__close(loop->async_io_watcher.fd);
loop->async_io_watcher.fd = -1;
}

61
deps/libuv/src/unix/atomic-ops.h vendored Normal file
View File

@ -0,0 +1,61 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef UV_ATOMIC_OPS_H_
#define UV_ATOMIC_OPS_H_
#include "internal.h" /* UV_UNUSED */
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
#include <atomic.h>
#endif
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
UV_UNUSED(static void cpu_relax(void));
/* Prefer hand-rolled assembly over the gcc builtins because the latter also
* issue full memory barriers.
*/
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
#if defined(__i386__) || defined(__x86_64__)
int out;
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
: "=a" (out), "+m" (*(volatile int*) ptr)
: "r" (newval), "0" (oldval)
: "memory");
return out;
#elif defined(__MVS__)
unsigned int op4;
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
(unsigned int*) ptr, *ptr, &op4))
return oldval;
else
return op4;
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
}
UV_UNUSED(static void cpu_relax(void)) {
#if defined(__i386__) || defined(__x86_64__)
__asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
__asm__ volatile("yield");
#endif
}
#endif /* UV_ATOMIC_OPS_H_ */

163
deps/libuv/src/unix/bsd-ifaddrs.c vendored Normal file
View File

@ -0,0 +1,163 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <errno.h>
#include <stddef.h>
#include <ifaddrs.h>
#include <net/if.h>
#if !defined(__CYGWIN__) && !defined(__MSYS__)
#include <net/if_dl.h>
#endif
#if defined(__HAIKU__)
#define IFF_RUNNING IFF_LINK
#endif
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
return 1;
if (ent->ifa_addr == NULL)
return 1;
#if !defined(__CYGWIN__) && !defined(__MSYS__)
/*
* If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family`
* equals to `AF_LINK` or not. Otherwise, the result depends on the operation
* system with `AF_LINK` or `PF_INET`.
*/
if (exclude_type == UV__EXCLUDE_IFPHYS)
return (ent->ifa_addr->sa_family != AF_LINK);
#endif
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || \
defined(__HAIKU__)
/*
* On BSD getifaddrs returns information related to the raw underlying
* devices. We're not interested in this information.
*/
if (ent->ifa_addr->sa_family == AF_LINK)
return 1;
#elif defined(__NetBSD__) || defined(__OpenBSD__)
if (ent->ifa_addr->sa_family != PF_INET &&
ent->ifa_addr->sa_family != PF_INET6)
return 1;
#endif
return 0;
}
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifaddrs* addrs;
struct ifaddrs* ent;
uv_interface_address_t* address;
#if !(defined(__CYGWIN__) || defined(__MSYS__))
int i;
#endif
*count = 0;
*addresses = NULL;
if (getifaddrs(&addrs) != 0)
return UV__ERR(errno);
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
(*count)++;
}
if (*count == 0) {
freeifaddrs(addrs);
return 0;
}
/* Make sure the memory is initiallized to zero using calloc() */
*addresses = uv__calloc(*count, sizeof(**addresses));
if (*addresses == NULL) {
freeifaddrs(addrs);
return UV_ENOMEM;
}
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
address->name = uv__strdup(ent->ifa_name);
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
} else {
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
if (ent->ifa_netmask == NULL) {
memset(&address->netmask, 0, sizeof(address->netmask));
} else if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
}
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
address++;
}
#if !(defined(__CYGWIN__) || defined(__MSYS__))
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
continue;
address = *addresses;
for (i = 0; i < *count; i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {
struct sockaddr_dl* sa_addr;
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
}
address++;
}
}
#endif
freeifaddrs(addrs);
return 0;
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; i++) {
uv__free(addresses[i].name);
}
uv__free(addresses);
}

100
deps/libuv/src/unix/bsd-proctitle.c vendored Normal file
View File

@ -0,0 +1,100 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <sys/types.h>
#include <unistd.h>
static uv_mutex_t process_title_mutex;
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static char* process_title;
static void init_process_title_mutex_once(void) {
if (uv_mutex_init(&process_title_mutex))
abort();
}
void uv__process_title_cleanup(void) {
/* TODO(bnoordhuis) uv_mutex_destroy(&process_title_mutex)
* and reset process_title_mutex_once?
*/
}
char** uv_setup_args(int argc, char** argv) {
process_title = argc > 0 ? uv__strdup(argv[0]) : NULL;
return argv;
}
int uv_set_process_title(const char* title) {
char* new_title;
new_title = uv__strdup(title);
if (new_title == NULL)
return UV_ENOMEM;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
uv__free(process_title);
process_title = new_title;
setproctitle("%s", title);
uv_mutex_unlock(&process_title_mutex);
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
if (buffer == NULL || size == 0)
return UV_EINVAL;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
if (process_title != NULL) {
len = strlen(process_title) + 1;
if (size < len) {
uv_mutex_unlock(&process_title_mutex);
return UV_ENOBUFS;
}
memcpy(buffer, process_title, len);
} else {
len = 0;
}
uv_mutex_unlock(&process_title_mutex);
buffer[len] = '\0';
return 0;
}

1613
deps/libuv/src/unix/core.c vendored Normal file

File diff suppressed because it is too large Load Diff

53
deps/libuv/src/unix/cygwin.c vendored Normal file
View File

@ -0,0 +1,53 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <sys/sysinfo.h>
#include <unistd.h>
int uv_uptime(double* uptime) {
struct sysinfo info;
if (sysinfo(&info) < 0)
return UV__ERR(errno);
*uptime = info.uptime;
return 0;
}
int uv_resident_set_memory(size_t* rss) {
/* FIXME: read /proc/meminfo? */
*rss = 0;
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
/* FIXME: read /proc/stat? */
*cpu_infos = NULL;
*count = 0;
return UV_ENOSYS;
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}

192
deps/libuv/src/unix/darwin-proctitle.c vendored Normal file
View File

@ -0,0 +1,192 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <dlfcn.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <TargetConditionals.h>
#if !TARGET_OS_IPHONE
#include "darwin-stub.h"
#endif
static int uv__pthread_setname_np(const char* name) {
char namebuf[64]; /* MAXTHREADNAMESIZE */
int err;
strncpy(namebuf, name, sizeof(namebuf) - 1);
namebuf[sizeof(namebuf) - 1] = '\0';
err = pthread_setname_np(namebuf);
if (err)
return UV__ERR(err);
return 0;
}
int uv__set_process_title(const char* title) {
#if TARGET_OS_IPHONE
return uv__pthread_setname_np(title);
#else
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
const char*,
CFStringEncoding);
CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
CFTypeRef (*pLSGetCurrentApplicationASN)(void);
OSStatus (*pLSSetApplicationInformationItem)(int,
CFTypeRef,
CFStringRef,
CFStringRef,
CFDictionaryRef*);
void* application_services_handle;
void* core_foundation_handle;
CFBundleRef launch_services_bundle;
CFStringRef* display_name_key;
CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
CFBundleRef (*pCFBundleGetMainBundle)(void);
CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
void*);
CFTypeRef asn;
int err;
err = UV_ENOENT;
application_services_handle = dlopen("/System/Library/Frameworks/"
"ApplicationServices.framework/"
"Versions/A/ApplicationServices",
RTLD_LAZY | RTLD_LOCAL);
core_foundation_handle = dlopen("/System/Library/Frameworks/"
"CoreFoundation.framework/"
"Versions/A/CoreFoundation",
RTLD_LAZY | RTLD_LOCAL);
if (application_services_handle == NULL || core_foundation_handle == NULL)
goto out;
*(void **)(&pCFStringCreateWithCString) =
dlsym(core_foundation_handle, "CFStringCreateWithCString");
*(void **)(&pCFBundleGetBundleWithIdentifier) =
dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
*(void **)(&pCFBundleGetDataPointerForName) =
dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
*(void **)(&pCFBundleGetFunctionPointerForName) =
dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");
if (pCFStringCreateWithCString == NULL ||
pCFBundleGetBundleWithIdentifier == NULL ||
pCFBundleGetDataPointerForName == NULL ||
pCFBundleGetFunctionPointerForName == NULL) {
goto out;
}
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
launch_services_bundle =
pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
if (launch_services_bundle == NULL)
goto out;
*(void **)(&pLSGetCurrentApplicationASN) =
pCFBundleGetFunctionPointerForName(launch_services_bundle,
S("_LSGetCurrentApplicationASN"));
if (pLSGetCurrentApplicationASN == NULL)
goto out;
*(void **)(&pLSSetApplicationInformationItem) =
pCFBundleGetFunctionPointerForName(launch_services_bundle,
S("_LSSetApplicationInformationItem"));
if (pLSSetApplicationInformationItem == NULL)
goto out;
display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle,
S("_kLSDisplayNameKey"));
if (display_name_key == NULL || *display_name_key == NULL)
goto out;
*(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle,
"CFBundleGetInfoDictionary");
*(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
"CFBundleGetMainBundle");
if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
goto out;
*(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
launch_services_bundle,
S("_LSApplicationCheckIn"));
if (pLSApplicationCheckIn == NULL)
goto out;
*(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
pCFBundleGetFunctionPointerForName(
launch_services_bundle,
S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
if (pLSSetApplicationLaunchServicesServerConnectionStatus == NULL)
goto out;
pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
/* Check into process manager?! */
pLSApplicationCheckIn(-2,
pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
asn = pLSGetCurrentApplicationASN();
err = UV_EBUSY;
if (asn == NULL)
goto out;
err = UV_EINVAL;
if (pLSSetApplicationInformationItem(-2, /* Magic value. */
asn,
*display_name_key,
S(title),
NULL) != noErr) {
goto out;
}
uv__pthread_setname_np(title); /* Don't care if it fails. */
err = 0;
out:
if (core_foundation_handle != NULL)
dlclose(core_foundation_handle);
if (application_services_handle != NULL)
dlclose(application_services_handle);
return err;
#endif /* !TARGET_OS_IPHONE */
}

113
deps/libuv/src/unix/darwin-stub.h vendored Normal file
View File

@ -0,0 +1,113 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_DARWIN_STUB_H_
#define UV_DARWIN_STUB_H_
#include <stdint.h>
struct CFArrayCallBacks;
struct CFRunLoopSourceContext;
struct FSEventStreamContext;
struct CFRange;
typedef double CFAbsoluteTime;
typedef double CFTimeInterval;
typedef int FSEventStreamEventFlags;
typedef int OSStatus;
typedef long CFIndex;
typedef struct CFArrayCallBacks CFArrayCallBacks;
typedef struct CFRunLoopSourceContext CFRunLoopSourceContext;
typedef struct FSEventStreamContext FSEventStreamContext;
typedef uint32_t FSEventStreamCreateFlags;
typedef uint64_t FSEventStreamEventId;
typedef unsigned CFStringEncoding;
typedef void* CFAllocatorRef;
typedef void* CFArrayRef;
typedef void* CFBundleRef;
typedef void* CFDataRef;
typedef void* CFDictionaryRef;
typedef void* CFMutableDictionaryRef;
typedef struct CFRange CFRange;
typedef void* CFRunLoopRef;
typedef void* CFRunLoopSourceRef;
typedef void* CFStringRef;
typedef void* CFTypeRef;
typedef void* FSEventStreamRef;
typedef uint32_t IOOptionBits;
typedef unsigned int io_iterator_t;
typedef unsigned int io_object_t;
typedef unsigned int io_service_t;
typedef unsigned int io_registry_entry_t;
typedef void (*FSEventStreamCallback)(const FSEventStreamRef,
void*,
size_t,
void*,
const FSEventStreamEventFlags*,
const FSEventStreamEventId*);
struct CFRunLoopSourceContext {
CFIndex version;
void* info;
void* pad[7];
void (*perform)(void*);
};
struct FSEventStreamContext {
CFIndex version;
void* info;
void* pad[3];
};
struct CFRange {
CFIndex location;
CFIndex length;
};
static const CFStringEncoding kCFStringEncodingUTF8 = 0x8000100;
static const OSStatus noErr = 0;
static const FSEventStreamEventId kFSEventStreamEventIdSinceNow = -1;
static const int kFSEventStreamCreateFlagNoDefer = 2;
static const int kFSEventStreamCreateFlagFileEvents = 16;
static const int kFSEventStreamEventFlagEventIdsWrapped = 8;
static const int kFSEventStreamEventFlagHistoryDone = 16;
static const int kFSEventStreamEventFlagItemChangeOwner = 0x4000;
static const int kFSEventStreamEventFlagItemCreated = 0x100;
static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x2000;
static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x400;
static const int kFSEventStreamEventFlagItemIsDir = 0x20000;
static const int kFSEventStreamEventFlagItemModified = 0x1000;
static const int kFSEventStreamEventFlagItemRemoved = 0x200;
static const int kFSEventStreamEventFlagItemRenamed = 0x800;
static const int kFSEventStreamEventFlagItemXattrMod = 0x8000;
static const int kFSEventStreamEventFlagKernelDropped = 4;
static const int kFSEventStreamEventFlagMount = 64;
static const int kFSEventStreamEventFlagRootChanged = 32;
static const int kFSEventStreamEventFlagUnmount = 128;
static const int kFSEventStreamEventFlagUserDropped = 2;
#endif /* UV_DARWIN_STUB_H_ */

371
deps/libuv/src/unix/darwin.c vendored Normal file
View File

@ -0,0 +1,371 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <stdint.h>
#include <errno.h>
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <unistd.h> /* sysconf */
#if !TARGET_OS_IPHONE
#include "darwin-stub.h"
#endif
static uv_once_t once = UV_ONCE_INIT;
static uint64_t (*time_func)(void);
static mach_timebase_info_data_t timebase;
typedef unsigned char UInt8;
int uv__platform_loop_init(uv_loop_t* loop) {
loop->cf_state = NULL;
if (uv__kqueue_init(loop))
return UV__ERR(errno);
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
uv__fsevents_loop_delete(loop);
}
static void uv__hrtime_init_once(void) {
if (KERN_SUCCESS != mach_timebase_info(&timebase))
abort();
time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time");
if (time_func == NULL)
time_func = mach_absolute_time;
}
uint64_t uv__hrtime(uv_clocktype_t type) {
uv_once(&once, uv__hrtime_init_once);
return time_func() * timebase.numer / timebase.denom;
}
int uv_exepath(char* buffer, size_t* size) {
/* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
char abspath[PATH_MAX * 2 + 1];
char exepath[PATH_MAX + 1];
uint32_t exepath_size;
size_t abspath_size;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
exepath_size = sizeof(exepath);
if (_NSGetExecutablePath(exepath, &exepath_size))
return UV_EIO;
if (realpath(exepath, abspath) != abspath)
return UV__ERR(errno);
abspath_size = strlen(abspath);
if (abspath_size == 0)
return UV_EIO;
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
return 0;
}
uint64_t uv_get_free_memory(void) {
vm_statistics_data_t info;
mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
if (host_statistics(mach_host_self(), HOST_VM_INFO,
(host_info_t)&info, &count) != KERN_SUCCESS) {
return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
}
return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
}
uint64_t uv_get_total_memory(void) {
uint64_t info;
int which[] = {CTL_HW, HW_MEMSIZE};
size_t size = sizeof(info);
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return (uint64_t) info;
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}
void uv_loadavg(double avg[3]) {
struct loadavg info;
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_LOADAVG};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
avg[0] = (double) info.ldavg[0] / info.fscale;
avg[1] = (double) info.ldavg[1] / info.fscale;
avg[2] = (double) info.ldavg[2] / info.fscale;
}
int uv_resident_set_memory(size_t* rss) {
mach_msg_type_number_t count;
task_basic_info_data_t info;
kern_return_t err;
count = TASK_BASIC_INFO_COUNT;
err = task_info(mach_task_self(),
TASK_BASIC_INFO,
(task_info_t) &info,
&count);
(void) &err;
/* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
* KERN_SUCCESS implies a libuv bug.
*/
assert(err == KERN_SUCCESS);
*rss = info.resident_size;
return 0;
}
int uv_uptime(double* uptime) {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
now = time(NULL);
*uptime = now - info.tv_sec;
return 0;
}
static int uv__get_cpu_speed(uint64_t* speed) {
/* IOKit */
void (*pIOObjectRelease)(io_object_t);
kern_return_t (*pIOMasterPort)(mach_port_t, mach_port_t*);
CFMutableDictionaryRef (*pIOServiceMatching)(const char*);
kern_return_t (*pIOServiceGetMatchingServices)(mach_port_t,
CFMutableDictionaryRef,
io_iterator_t*);
io_service_t (*pIOIteratorNext)(io_iterator_t);
CFTypeRef (*pIORegistryEntryCreateCFProperty)(io_registry_entry_t,
CFStringRef,
CFAllocatorRef,
IOOptionBits);
/* CoreFoundation */
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
const char*,
CFStringEncoding);
CFStringEncoding (*pCFStringGetSystemEncoding)(void);
UInt8 *(*pCFDataGetBytePtr)(CFDataRef);
CFIndex (*pCFDataGetLength)(CFDataRef);
void (*pCFDataGetBytes)(CFDataRef, CFRange, UInt8*);
void (*pCFRelease)(CFTypeRef);
void* core_foundation_handle;
void* iokit_handle;
int err;
kern_return_t kr;
mach_port_t mach_port;
io_iterator_t it;
io_object_t service;
mach_port = 0;
err = UV_ENOENT;
core_foundation_handle = dlopen("/System/Library/Frameworks/"
"CoreFoundation.framework/"
"Versions/A/CoreFoundation",
RTLD_LAZY | RTLD_LOCAL);
iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/"
"Versions/A/IOKit",
RTLD_LAZY | RTLD_LOCAL);
if (core_foundation_handle == NULL || iokit_handle == NULL)
goto out;
#define V(handle, symbol) \
do { \
*(void **)(&p ## symbol) = dlsym((handle), #symbol); \
if (p ## symbol == NULL) \
goto out; \
} \
while (0)
V(iokit_handle, IOMasterPort);
V(iokit_handle, IOServiceMatching);
V(iokit_handle, IOServiceGetMatchingServices);
V(iokit_handle, IOIteratorNext);
V(iokit_handle, IOObjectRelease);
V(iokit_handle, IORegistryEntryCreateCFProperty);
V(core_foundation_handle, CFStringCreateWithCString);
V(core_foundation_handle, CFStringGetSystemEncoding);
V(core_foundation_handle, CFDataGetBytePtr);
V(core_foundation_handle, CFDataGetLength);
V(core_foundation_handle, CFDataGetBytes);
V(core_foundation_handle, CFRelease);
#undef V
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
kr = pIOMasterPort(MACH_PORT_NULL, &mach_port);
assert(kr == KERN_SUCCESS);
CFMutableDictionaryRef classes_to_match
= pIOServiceMatching("IOPlatformDevice");
kr = pIOServiceGetMatchingServices(mach_port, classes_to_match, &it);
assert(kr == KERN_SUCCESS);
service = pIOIteratorNext(it);
CFStringRef device_type_str = S("device_type");
CFStringRef clock_frequency_str = S("clock-frequency");
while (service != 0) {
CFDataRef data;
data = pIORegistryEntryCreateCFProperty(service,
device_type_str,
NULL,
0);
if (data) {
const UInt8* raw = pCFDataGetBytePtr(data);
if (strncmp((char*)raw, "cpu", 3) == 0 ||
strncmp((char*)raw, "processor", 9) == 0) {
CFDataRef freq_ref;
freq_ref = pIORegistryEntryCreateCFProperty(service,
clock_frequency_str,
NULL,
0);
if (freq_ref) {
uint32_t freq;
CFIndex len = pCFDataGetLength(freq_ref);
CFRange range;
range.location = 0;
range.length = len;
pCFDataGetBytes(freq_ref, range, (UInt8*)&freq);
*speed = freq;
pCFRelease(freq_ref);
pCFRelease(data);
break;
}
}
pCFRelease(data);
}
service = pIOIteratorNext(it);
}
pIOObjectRelease(it);
err = 0;
out:
if (core_foundation_handle != NULL)
dlclose(core_foundation_handle);
if (iokit_handle != NULL)
dlclose(iokit_handle);
mach_port_deallocate(mach_task_self(), mach_port);
return err;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks);
char model[512];
size_t size;
unsigned int i;
natural_t numcpus;
mach_msg_type_number_t msg_type;
processor_cpu_load_info_data_t *info;
uv_cpu_info_t* cpu_info;
uint64_t cpuspeed;
int err;
size = sizeof(model);
if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
sysctlbyname("hw.model", &model, &size, NULL, 0)) {
return UV__ERR(errno);
}
err = uv__get_cpu_speed(&cpuspeed);
if (err < 0)
return err;
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
(processor_info_array_t*)&info,
&msg_type) != KERN_SUCCESS) {
return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
}
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
if (!(*cpu_infos)) {
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
return UV_ENOMEM;
}
*count = numcpus;
for (i = 0; i < numcpus; i++) {
cpu_info = &(*cpu_infos)[i];
cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier;
cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier;
cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier;
cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier;
cpu_info->cpu_times.irq = 0;
cpu_info->model = uv__strdup(model);
cpu_info->speed = cpuspeed/1000000;
}
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
return 0;
}

80
deps/libuv/src/unix/dl.c vendored Normal file
View File

@ -0,0 +1,80 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <dlfcn.h>
#include <errno.h>
#include <string.h>
#include <locale.h>
static int uv__dlerror(uv_lib_t* lib);
int uv_dlopen(const char* filename, uv_lib_t* lib) {
dlerror(); /* Reset error status. */
lib->errmsg = NULL;
lib->handle = dlopen(filename, RTLD_LAZY);
return lib->handle ? 0 : uv__dlerror(lib);
}
void uv_dlclose(uv_lib_t* lib) {
uv__free(lib->errmsg);
lib->errmsg = NULL;
if (lib->handle) {
/* Ignore errors. No good way to signal them without leaking memory. */
dlclose(lib->handle);
lib->handle = NULL;
}
}
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
dlerror(); /* Reset error status. */
*ptr = dlsym(lib->handle, name);
return uv__dlerror(lib);
}
const char* uv_dlerror(const uv_lib_t* lib) {
return lib->errmsg ? lib->errmsg : "no error";
}
static int uv__dlerror(uv_lib_t* lib) {
const char* errmsg;
uv__free(lib->errmsg);
errmsg = dlerror();
if (errmsg) {
lib->errmsg = uv__strdup(errmsg);
return -1;
}
else {
lib->errmsg = NULL;
return 0;
}
}

282
deps/libuv/src/unix/freebsd.c vendored Normal file
View File

@ -0,0 +1,282 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <paths.h>
#include <sys/user.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <vm/vm_param.h> /* VM_LOADAVG */
#include <time.h>
#include <stdlib.h>
#include <unistd.h> /* sysconf */
#include <fcntl.h>
#ifndef CPUSTATES
# define CPUSTATES 5U
#endif
#ifndef CP_USER
# define CP_USER 0
# define CP_NICE 1
# define CP_SYS 2
# define CP_IDLE 3
# define CP_INTR 4
#endif
int uv__platform_loop_init(uv_loop_t* loop) {
return uv__kqueue_init(loop);
}
void uv__platform_loop_delete(uv_loop_t* loop) {
}
int uv_exepath(char* buffer, size_t* size) {
char abspath[PATH_MAX * 2 + 1];
int mib[4];
size_t abspath_size;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
abspath_size = sizeof abspath;
if (sysctl(mib, ARRAY_SIZE(mib), abspath, &abspath_size, NULL, 0))
return UV__ERR(errno);
assert(abspath_size > 0);
abspath_size -= 1;
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
return 0;
}
uint64_t uv_get_free_memory(void) {
int freecount;
size_t size = sizeof(freecount);
if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
return UV__ERR(errno);
return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
}
uint64_t uv_get_total_memory(void) {
unsigned long info;
int which[] = {CTL_HW, HW_PHYSMEM};
size_t size = sizeof(info);
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return (uint64_t) info;
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}
void uv_loadavg(double avg[3]) {
struct loadavg info;
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_LOADAVG};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
avg[0] = (double) info.ldavg[0] / info.fscale;
avg[1] = (double) info.ldavg[1] / info.fscale;
avg[2] = (double) info.ldavg[2] / info.fscale;
}
int uv_resident_set_memory(size_t* rss) {
struct kinfo_proc kinfo;
size_t page_size;
size_t kinfo_size;
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
kinfo_size = sizeof(kinfo);
if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &kinfo_size, NULL, 0))
return UV__ERR(errno);
page_size = getpagesize();
#ifdef __DragonFly__
*rss = kinfo.kp_vm_rssize * page_size;
#else
*rss = kinfo.ki_rssize * page_size;
#endif
return 0;
}
int uv_uptime(double* uptime) {
int r;
struct timespec sp;
r = clock_gettime(CLOCK_MONOTONIC, &sp);
if (r)
return UV__ERR(errno);
*uptime = sp.tv_sec;
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
cur = 0;
uv_cpu_info_t* cpu_info;
const char* maxcpus_key;
const char* cptimes_key;
const char* model_key;
char model[512];
long* cp_times;
int numcpus;
size_t size;
int i;
#if defined(__DragonFly__)
/* This is not quite correct but DragonFlyBSD doesn't seem to have anything
* comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total,
* not per CPU). At least this stops uv_cpu_info() from failing completely.
*/
maxcpus_key = "hw.ncpu";
cptimes_key = "kern.cp_time";
#else
maxcpus_key = "kern.smp.maxcpus";
cptimes_key = "kern.cp_times";
#endif
#if defined(__arm__) || defined(__aarch64__)
/* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */
model_key = "hw.machine";
cpuspeed = 0;
#else
model_key = "hw.model";
size = sizeof(cpuspeed);
if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0))
return -errno;
#endif
size = sizeof(model);
if (sysctlbyname(model_key, &model, &size, NULL, 0))
return UV__ERR(errno);
size = sizeof(numcpus);
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
return UV__ERR(errno);
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
if (!(*cpu_infos))
return UV_ENOMEM;
*count = numcpus;
/* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
* ncpu.
*/
size = sizeof(maxcpus);
if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
uv__free(*cpu_infos);
return UV__ERR(errno);
}
size = maxcpus * CPUSTATES * sizeof(long);
cp_times = uv__malloc(size);
if (cp_times == NULL) {
uv__free(*cpu_infos);
return UV_ENOMEM;
}
if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
uv__free(cp_times);
uv__free(*cpu_infos);
return UV__ERR(errno);
}
for (i = 0; i < numcpus; i++) {
cpu_info = &(*cpu_infos)[i];
cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
cpu_info->model = uv__strdup(model);
cpu_info->speed = cpuspeed;
cur+=CPUSTATES;
}
uv__free(cp_times);
return 0;
}
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if __FreeBSD__ >= 11
return sendmmsg(fd, mmsg, vlen, /* flags */ 0);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if __FreeBSD__ >= 11
return recvmmsg(fd, mmsg, vlen, 0 /* flags */, NULL /* timeout */);
#else
return errno = ENOSYS, -1;
#endif
}

2134
deps/libuv/src/unix/fs.c vendored Normal file

File diff suppressed because it is too large Load Diff

923
deps/libuv/src/unix/fsevents.c vendored Normal file
View File

@ -0,0 +1,923 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MAX_ALLOWED < 1070
/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
/* macOS prior to 10.7 doesn't provide the full FSEvents API so use kqueue */
int uv__fsevents_init(uv_fs_event_t* handle) {
return 0;
}
int uv__fsevents_close(uv_fs_event_t* handle) {
return 0;
}
void uv__fsevents_loop_delete(uv_loop_t* loop) {
}
#else /* TARGET_OS_IPHONE */
#include "darwin-stub.h"
#include <dlfcn.h>
#include <assert.h>
#include <stdlib.h>
#include <pthread.h>
static const int kFSEventsModified =
kFSEventStreamEventFlagItemChangeOwner |
kFSEventStreamEventFlagItemFinderInfoMod |
kFSEventStreamEventFlagItemInodeMetaMod |
kFSEventStreamEventFlagItemModified |
kFSEventStreamEventFlagItemXattrMod;
static const int kFSEventsRenamed =
kFSEventStreamEventFlagItemCreated |
kFSEventStreamEventFlagItemRemoved |
kFSEventStreamEventFlagItemRenamed;
static const int kFSEventsSystem =
kFSEventStreamEventFlagUserDropped |
kFSEventStreamEventFlagKernelDropped |
kFSEventStreamEventFlagEventIdsWrapped |
kFSEventStreamEventFlagHistoryDone |
kFSEventStreamEventFlagMount |
kFSEventStreamEventFlagUnmount |
kFSEventStreamEventFlagRootChanged;
typedef struct uv__fsevents_event_s uv__fsevents_event_t;
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
enum uv__cf_loop_signal_type_e {
kUVCFLoopSignalRegular,
kUVCFLoopSignalClosing
};
typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
struct uv__cf_loop_signal_s {
QUEUE member;
uv_fs_event_t* handle;
uv__cf_loop_signal_type_t type;
};
struct uv__fsevents_event_s {
QUEUE member;
int events;
char path[1];
};
struct uv__cf_loop_state_s {
CFRunLoopRef loop;
CFRunLoopSourceRef signal_source;
int fsevent_need_reschedule;
FSEventStreamRef fsevent_stream;
uv_sem_t fsevent_sem;
uv_mutex_t fsevent_mutex;
void* fsevent_handles[2];
unsigned int fsevent_handle_count;
};
/* Forward declarations */
static void uv__cf_loop_cb(void* arg);
static void* uv__cf_loop_runner(void* arg);
static int uv__cf_loop_signal(uv_loop_t* loop,
uv_fs_event_t* handle,
uv__cf_loop_signal_type_t type);
/* Lazy-loaded by uv__fsevents_global_init(). */
static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
const void**,
CFIndex,
const CFArrayCallBacks*);
static void (*pCFRelease)(CFTypeRef);
static void (*pCFRunLoopAddSource)(CFRunLoopRef,
CFRunLoopSourceRef,
CFStringRef);
static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
CFRunLoopSourceRef,
CFStringRef);
static void (*pCFRunLoopRun)(void);
static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
CFIndex,
CFRunLoopSourceContext*);
static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
static void (*pCFRunLoopStop)(CFRunLoopRef);
static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
CFAllocatorRef,
const char*);
static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
static CFStringRef (*pkCFRunLoopDefaultMode);
static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
FSEventStreamCallback,
FSEventStreamContext*,
CFArrayRef,
FSEventStreamEventId,
CFTimeInterval,
FSEventStreamCreateFlags);
static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
static void (*pFSEventStreamRelease)(FSEventStreamRef);
static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
CFRunLoopRef,
CFStringRef);
static int (*pFSEventStreamStart)(FSEventStreamRef);
static void (*pFSEventStreamStop)(FSEventStreamRef);
#define UV__FSEVENTS_PROCESS(handle, block) \
do { \
QUEUE events; \
QUEUE* q; \
uv__fsevents_event_t* event; \
int err; \
uv_mutex_lock(&(handle)->cf_mutex); \
/* Split-off all events and empty original queue */ \
QUEUE_MOVE(&(handle)->cf_events, &events); \
/* Get error (if any) and zero original one */ \
err = (handle)->cf_error; \
(handle)->cf_error = 0; \
uv_mutex_unlock(&(handle)->cf_mutex); \
/* Loop through events, deallocating each after processing */ \
while (!QUEUE_EMPTY(&events)) { \
q = QUEUE_HEAD(&events); \
event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
QUEUE_REMOVE(q); \
/* NOTE: Checking uv__is_active() is required here, because handle \
* callback may close handle and invoking it after it will lead to \
* incorrect behaviour */ \
if (!uv__is_closing((handle)) && uv__is_active((handle))) \
block \
/* Free allocated data */ \
uv__free(event); \
} \
if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
(handle)->cb((handle), NULL, 0, err); \
} while (0)
/* Runs in UV loop's thread, when there're events to report to handle */
static void uv__fsevents_cb(uv_async_t* cb) {
uv_fs_event_t* handle;
handle = cb->data;
UV__FSEVENTS_PROCESS(handle, {
handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
});
}
/* Runs in CF thread, pushed event into handle's event list */
static void uv__fsevents_push_event(uv_fs_event_t* handle,
QUEUE* events,
int err) {
assert(events != NULL || err != 0);
uv_mutex_lock(&handle->cf_mutex);
/* Concatenate two queues */
if (events != NULL)
QUEUE_ADD(&handle->cf_events, events);
/* Propagate error */
if (err != 0)
handle->cf_error = err;
uv_mutex_unlock(&handle->cf_mutex);
uv_async_send(handle->cf_cb);
}
/* Runs in CF thread, when there're events in FSEventStream */
static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
void* info,
size_t numEvents,
void* eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[]) {
size_t i;
int len;
char** paths;
char* path;
char* pos;
uv_fs_event_t* handle;
QUEUE* q;
uv_loop_t* loop;
uv__cf_loop_state_t* state;
uv__fsevents_event_t* event;
FSEventStreamEventFlags flags;
QUEUE head;
loop = info;
state = loop->cf_state;
assert(state != NULL);
paths = eventPaths;
/* For each handle */
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_FOREACH(q, &state->fsevent_handles) {
handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
QUEUE_INIT(&head);
/* Process and filter out events */
for (i = 0; i < numEvents; i++) {
flags = eventFlags[i];
/* Ignore system events */
if (flags & kFSEventsSystem)
continue;
path = paths[i];
len = strlen(path);
if (handle->realpath_len == 0)
continue; /* This should be unreachable */
/* Filter out paths that are outside handle's request */
if (len < handle->realpath_len)
continue;
/* Make sure that realpath actually named a directory,
* (unless watching root, which alone keeps a trailing slash on the realpath)
* or that we matched the whole string */
if (handle->realpath_len != len &&
handle->realpath_len > 1 &&
path[handle->realpath_len] != '/')
continue;
if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
continue;
if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) {
/* Remove common prefix, unless the watched folder is "/" */
path += handle->realpath_len;
len -= handle->realpath_len;
/* Ignore events with path equal to directory itself */
if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir))
continue;
if (len == 0) {
/* Since we're using fsevents to watch the file itself,
* realpath == path, and we now need to get the basename of the file back
* (for commonality with other codepaths and platforms). */
while (len < handle->realpath_len && path[-1] != '/') {
path--;
len++;
}
/* Created and Removed seem to be always set, but don't make sense */
flags &= ~kFSEventsRenamed;
} else {
/* Skip forward slash */
path++;
len--;
}
}
/* Do not emit events from subdirectories (without option set) */
if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') {
pos = strchr(path + 1, '/');
if (pos != NULL)
continue;
}
event = uv__malloc(sizeof(*event) + len);
if (event == NULL)
break;
memset(event, 0, sizeof(*event));
memcpy(event->path, path, len + 1);
event->events = UV_RENAME;
if (0 == (flags & kFSEventsRenamed)) {
if (0 != (flags & kFSEventsModified) ||
0 == (flags & kFSEventStreamEventFlagItemIsDir))
event->events = UV_CHANGE;
}
QUEUE_INSERT_TAIL(&head, &event->member);
}
if (!QUEUE_EMPTY(&head))
uv__fsevents_push_event(handle, &head, 0);
}
uv_mutex_unlock(&state->fsevent_mutex);
}
/* Runs in CF thread */
static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
uv__cf_loop_state_t* state;
FSEventStreamContext ctx;
FSEventStreamRef ref;
CFAbsoluteTime latency;
FSEventStreamCreateFlags flags;
/* Initialize context */
memset(&ctx, 0, sizeof(ctx));
ctx.info = loop;
latency = 0.05;
/* Explanation of selected flags:
* 1. NoDefer - without this flag, events that are happening continuously
* (i.e. each event is happening after time interval less than `latency`,
* counted from previous event), will be deferred and passed to callback
* once they'll either fill whole OS buffer, or when this continuous stream
* will stop (i.e. there'll be delay between events, bigger than
* `latency`).
* Specifying this flag will invoke callback after `latency` time passed
* since event.
* 2. FileEvents - fire callback for file changes too (by default it is firing
* it only for directory changes).
*/
flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
/*
* NOTE: It might sound like a good idea to remember last seen StreamEventId,
* but in reality one dir might have last StreamEventId less than, the other,
* that is being watched now. Which will cause FSEventStream API to report
* changes to files from the past.
*/
ref = pFSEventStreamCreate(NULL,
&uv__fsevents_event_cb,
&ctx,
paths,
kFSEventStreamEventIdSinceNow,
latency,
flags);
assert(ref != NULL);
state = loop->cf_state;
pFSEventStreamScheduleWithRunLoop(ref,
state->loop,
*pkCFRunLoopDefaultMode);
if (!pFSEventStreamStart(ref)) {
pFSEventStreamInvalidate(ref);
pFSEventStreamRelease(ref);
return UV_EMFILE;
}
state->fsevent_stream = ref;
return 0;
}
/* Runs in CF thread */
static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
uv__cf_loop_state_t* state;
state = loop->cf_state;
if (state->fsevent_stream == NULL)
return;
/* Stop emitting events */
pFSEventStreamStop(state->fsevent_stream);
/* Release stream */
pFSEventStreamInvalidate(state->fsevent_stream);
pFSEventStreamRelease(state->fsevent_stream);
state->fsevent_stream = NULL;
}
/* Runs in CF thread, when there're new fsevent handles to add to stream */
static void uv__fsevents_reschedule(uv_fs_event_t* handle,
uv__cf_loop_signal_type_t type) {
uv__cf_loop_state_t* state;
QUEUE* q;
uv_fs_event_t* curr;
CFArrayRef cf_paths;
CFStringRef* paths;
unsigned int i;
int err;
unsigned int path_count;
state = handle->loop->cf_state;
paths = NULL;
cf_paths = NULL;
err = 0;
/* NOTE: `i` is used in deallocation loop below */
i = 0;
/* Optimization to prevent O(n^2) time spent when starting to watch
* many files simultaneously
*/
uv_mutex_lock(&state->fsevent_mutex);
if (state->fsevent_need_reschedule == 0) {
uv_mutex_unlock(&state->fsevent_mutex);
goto final;
}
state->fsevent_need_reschedule = 0;
uv_mutex_unlock(&state->fsevent_mutex);
/* Destroy previous FSEventStream */
uv__fsevents_destroy_stream(handle->loop);
/* Any failure below will be a memory failure */
err = UV_ENOMEM;
/* Create list of all watched paths */
uv_mutex_lock(&state->fsevent_mutex);
path_count = state->fsevent_handle_count;
if (path_count != 0) {
paths = uv__malloc(sizeof(*paths) * path_count);
if (paths == NULL) {
uv_mutex_unlock(&state->fsevent_mutex);
goto final;
}
q = &state->fsevent_handles;
for (; i < path_count; i++) {
q = QUEUE_NEXT(q);
assert(q != &state->fsevent_handles);
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
assert(curr->realpath != NULL);
paths[i] =
pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
if (paths[i] == NULL) {
uv_mutex_unlock(&state->fsevent_mutex);
goto final;
}
}
}
uv_mutex_unlock(&state->fsevent_mutex);
err = 0;
if (path_count != 0) {
/* Create new FSEventStream */
cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
if (cf_paths == NULL) {
err = UV_ENOMEM;
goto final;
}
err = uv__fsevents_create_stream(handle->loop, cf_paths);
}
final:
/* Deallocate all paths in case of failure */
if (err != 0) {
if (cf_paths == NULL) {
while (i != 0)
pCFRelease(paths[--i]);
uv__free(paths);
} else {
/* CFArray takes ownership of both strings and original C-array */
pCFRelease(cf_paths);
}
/* Broadcast error to all handles */
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_FOREACH(q, &state->fsevent_handles) {
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
uv__fsevents_push_event(curr, NULL, err);
}
uv_mutex_unlock(&state->fsevent_mutex);
}
/*
* Main thread will block until the removal of handle from the list,
* we must tell it when we're ready.
*
* NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
*/
if (type == kUVCFLoopSignalClosing)
uv_sem_post(&state->fsevent_sem);
}
static int uv__fsevents_global_init(void) {
static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
static void* core_foundation_handle;
static void* core_services_handle;
int err;
err = 0;
pthread_mutex_lock(&global_init_mutex);
if (core_foundation_handle != NULL)
goto out;
/* The libraries are never unloaded because we currently don't have a good
* mechanism for keeping a reference count. It's unlikely to be an issue
* but if it ever becomes one, we can turn the dynamic library handles into
* per-event loop properties and have the dynamic linker keep track for us.
*/
err = UV_ENOSYS;
core_foundation_handle = dlopen("/System/Library/Frameworks/"
"CoreFoundation.framework/"
"Versions/A/CoreFoundation",
RTLD_LAZY | RTLD_LOCAL);
if (core_foundation_handle == NULL)
goto out;
core_services_handle = dlopen("/System/Library/Frameworks/"
"CoreServices.framework/"
"Versions/A/CoreServices",
RTLD_LAZY | RTLD_LOCAL);
if (core_services_handle == NULL)
goto out;
err = UV_ENOENT;
#define V(handle, symbol) \
do { \
*(void **)(&p ## symbol) = dlsym((handle), #symbol); \
if (p ## symbol == NULL) \
goto out; \
} \
while (0)
V(core_foundation_handle, CFArrayCreate);
V(core_foundation_handle, CFRelease);
V(core_foundation_handle, CFRunLoopAddSource);
V(core_foundation_handle, CFRunLoopGetCurrent);
V(core_foundation_handle, CFRunLoopRemoveSource);
V(core_foundation_handle, CFRunLoopRun);
V(core_foundation_handle, CFRunLoopSourceCreate);
V(core_foundation_handle, CFRunLoopSourceSignal);
V(core_foundation_handle, CFRunLoopStop);
V(core_foundation_handle, CFRunLoopWakeUp);
V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
V(core_foundation_handle, CFStringGetSystemEncoding);
V(core_foundation_handle, kCFRunLoopDefaultMode);
V(core_services_handle, FSEventStreamCreate);
V(core_services_handle, FSEventStreamFlushSync);
V(core_services_handle, FSEventStreamInvalidate);
V(core_services_handle, FSEventStreamRelease);
V(core_services_handle, FSEventStreamScheduleWithRunLoop);
V(core_services_handle, FSEventStreamStart);
V(core_services_handle, FSEventStreamStop);
#undef V
err = 0;
out:
if (err && core_services_handle != NULL) {
dlclose(core_services_handle);
core_services_handle = NULL;
}
if (err && core_foundation_handle != NULL) {
dlclose(core_foundation_handle);
core_foundation_handle = NULL;
}
pthread_mutex_unlock(&global_init_mutex);
return err;
}
/* Runs in UV loop */
static int uv__fsevents_loop_init(uv_loop_t* loop) {
CFRunLoopSourceContext ctx;
uv__cf_loop_state_t* state;
pthread_attr_t attr_storage;
pthread_attr_t* attr;
int err;
if (loop->cf_state != NULL)
return 0;
err = uv__fsevents_global_init();
if (err)
return err;
state = uv__calloc(1, sizeof(*state));
if (state == NULL)
return UV_ENOMEM;
err = uv_mutex_init(&loop->cf_mutex);
if (err)
goto fail_mutex_init;
err = uv_sem_init(&loop->cf_sem, 0);
if (err)
goto fail_sem_init;
QUEUE_INIT(&loop->cf_signals);
err = uv_sem_init(&state->fsevent_sem, 0);
if (err)
goto fail_fsevent_sem_init;
err = uv_mutex_init(&state->fsevent_mutex);
if (err)
goto fail_fsevent_mutex_init;
QUEUE_INIT(&state->fsevent_handles);
state->fsevent_need_reschedule = 0;
state->fsevent_handle_count = 0;
memset(&ctx, 0, sizeof(ctx));
ctx.info = loop;
ctx.perform = uv__cf_loop_cb;
state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
if (state->signal_source == NULL) {
err = UV_ENOMEM;
goto fail_signal_source_create;
}
/* In the unlikely event that pthread_attr_init() fails, create the thread
* with the default stack size. We'll use a little more address space but
* that in itself is not a fatal error.
*/
attr = &attr_storage;
if (pthread_attr_init(attr))
attr = NULL;
if (attr != NULL)
if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
abort();
loop->cf_state = state;
/* uv_thread_t is an alias for pthread_t. */
err = UV__ERR(pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop));
if (attr != NULL)
pthread_attr_destroy(attr);
if (err)
goto fail_thread_create;
/* Synchronize threads */
uv_sem_wait(&loop->cf_sem);
return 0;
fail_thread_create:
loop->cf_state = NULL;
fail_signal_source_create:
uv_mutex_destroy(&state->fsevent_mutex);
fail_fsevent_mutex_init:
uv_sem_destroy(&state->fsevent_sem);
fail_fsevent_sem_init:
uv_sem_destroy(&loop->cf_sem);
fail_sem_init:
uv_mutex_destroy(&loop->cf_mutex);
fail_mutex_init:
uv__free(state);
return err;
}
/* Runs in UV loop */
void uv__fsevents_loop_delete(uv_loop_t* loop) {
uv__cf_loop_signal_t* s;
uv__cf_loop_state_t* state;
QUEUE* q;
if (loop->cf_state == NULL)
return;
if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
abort();
uv_thread_join(&loop->cf_thread);
uv_sem_destroy(&loop->cf_sem);
uv_mutex_destroy(&loop->cf_mutex);
/* Free any remaining data */
while (!QUEUE_EMPTY(&loop->cf_signals)) {
q = QUEUE_HEAD(&loop->cf_signals);
s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
QUEUE_REMOVE(q);
uv__free(s);
}
/* Destroy state */
state = loop->cf_state;
uv_sem_destroy(&state->fsevent_sem);
uv_mutex_destroy(&state->fsevent_mutex);
pCFRelease(state->signal_source);
uv__free(state);
loop->cf_state = NULL;
}
/* Runs in CF thread. This is the CF loop's body */
static void* uv__cf_loop_runner(void* arg) {
uv_loop_t* loop;
uv__cf_loop_state_t* state;
loop = arg;
state = loop->cf_state;
state->loop = pCFRunLoopGetCurrent();
pCFRunLoopAddSource(state->loop,
state->signal_source,
*pkCFRunLoopDefaultMode);
uv_sem_post(&loop->cf_sem);
pCFRunLoopRun();
pCFRunLoopRemoveSource(state->loop,
state->signal_source,
*pkCFRunLoopDefaultMode);
state->loop = NULL;
return NULL;
}
/* Runs in CF thread, executed after `uv__cf_loop_signal()` */
static void uv__cf_loop_cb(void* arg) {
uv_loop_t* loop;
uv__cf_loop_state_t* state;
QUEUE* item;
QUEUE split_head;
uv__cf_loop_signal_t* s;
loop = arg;
state = loop->cf_state;
uv_mutex_lock(&loop->cf_mutex);
QUEUE_MOVE(&loop->cf_signals, &split_head);
uv_mutex_unlock(&loop->cf_mutex);
while (!QUEUE_EMPTY(&split_head)) {
item = QUEUE_HEAD(&split_head);
QUEUE_REMOVE(item);
s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
/* This was a termination signal */
if (s->handle == NULL)
pCFRunLoopStop(state->loop);
else
uv__fsevents_reschedule(s->handle, s->type);
uv__free(s);
}
}
/* Runs in UV loop to notify CF thread */
int uv__cf_loop_signal(uv_loop_t* loop,
uv_fs_event_t* handle,
uv__cf_loop_signal_type_t type) {
uv__cf_loop_signal_t* item;
uv__cf_loop_state_t* state;
item = uv__malloc(sizeof(*item));
if (item == NULL)
return UV_ENOMEM;
item->handle = handle;
item->type = type;
uv_mutex_lock(&loop->cf_mutex);
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
state = loop->cf_state;
assert(state != NULL);
pCFRunLoopSourceSignal(state->signal_source);
pCFRunLoopWakeUp(state->loop);
uv_mutex_unlock(&loop->cf_mutex);
return 0;
}
/* Runs in UV loop to initialize handle */
int uv__fsevents_init(uv_fs_event_t* handle) {
int err;
uv__cf_loop_state_t* state;
err = uv__fsevents_loop_init(handle->loop);
if (err)
return err;
/* Get absolute path to file */
handle->realpath = realpath(handle->path, NULL);
if (handle->realpath == NULL)
return UV__ERR(errno);
handle->realpath_len = strlen(handle->realpath);
/* Initialize event queue */
QUEUE_INIT(&handle->cf_events);
handle->cf_error = 0;
/*
* Events will occur in other thread.
* Initialize callback for getting them back into event loop's thread
*/
handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb));
if (handle->cf_cb == NULL) {
err = UV_ENOMEM;
goto fail_cf_cb_malloc;
}
handle->cf_cb->data = handle;
uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
handle->cf_cb->flags |= UV_HANDLE_INTERNAL;
uv_unref((uv_handle_t*) handle->cf_cb);
err = uv_mutex_init(&handle->cf_mutex);
if (err)
goto fail_cf_mutex_init;
/* Insert handle into the list */
state = handle->loop->cf_state;
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
state->fsevent_handle_count++;
state->fsevent_need_reschedule = 1;
uv_mutex_unlock(&state->fsevent_mutex);
/* Reschedule FSEventStream */
assert(handle != NULL);
err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
if (err)
goto fail_loop_signal;
return 0;
fail_loop_signal:
uv_mutex_destroy(&handle->cf_mutex);
fail_cf_mutex_init:
uv__free(handle->cf_cb);
handle->cf_cb = NULL;
fail_cf_cb_malloc:
uv__free(handle->realpath);
handle->realpath = NULL;
handle->realpath_len = 0;
return err;
}
/* Runs in UV loop to de-initialize handle */
int uv__fsevents_close(uv_fs_event_t* handle) {
int err;
uv__cf_loop_state_t* state;
if (handle->cf_cb == NULL)
return UV_EINVAL;
/* Remove handle from the list */
state = handle->loop->cf_state;
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_REMOVE(&handle->cf_member);
state->fsevent_handle_count--;
state->fsevent_need_reschedule = 1;
uv_mutex_unlock(&state->fsevent_mutex);
/* Reschedule FSEventStream */
assert(handle != NULL);
err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
if (err)
return UV__ERR(err);
/* Wait for deinitialization */
uv_sem_wait(&state->fsevent_sem);
uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free);
handle->cf_cb = NULL;
/* Free data in queue */
UV__FSEVENTS_PROCESS(handle, {
/* NOP */
});
uv_mutex_destroy(&handle->cf_mutex);
uv__free(handle->realpath);
handle->realpath = NULL;
handle->realpath_len = 0;
return 0;
}
#endif /* TARGET_OS_IPHONE */

255
deps/libuv/src/unix/getaddrinfo.c vendored Normal file
View File

@ -0,0 +1,255 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
* include any headers.
*/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include "uv.h"
#include "internal.h"
#include "idna.h"
#include <errno.h>
#include <stddef.h> /* NULL */
#include <stdlib.h>
#include <string.h>
#include <net/if.h> /* if_indextoname() */
/* EAI_* constants. */
#include <netdb.h>
int uv__getaddrinfo_translate_error(int sys_err) {
switch (sys_err) {
case 0: return 0;
#if defined(EAI_ADDRFAMILY)
case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
#endif
#if defined(EAI_AGAIN)
case EAI_AGAIN: return UV_EAI_AGAIN;
#endif
#if defined(EAI_BADFLAGS)
case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
#endif
#if defined(EAI_BADHINTS)
case EAI_BADHINTS: return UV_EAI_BADHINTS;
#endif
#if defined(EAI_CANCELED)
case EAI_CANCELED: return UV_EAI_CANCELED;
#endif
#if defined(EAI_FAIL)
case EAI_FAIL: return UV_EAI_FAIL;
#endif
#if defined(EAI_FAMILY)
case EAI_FAMILY: return UV_EAI_FAMILY;
#endif
#if defined(EAI_MEMORY)
case EAI_MEMORY: return UV_EAI_MEMORY;
#endif
#if defined(EAI_NODATA)
case EAI_NODATA: return UV_EAI_NODATA;
#endif
#if defined(EAI_NONAME)
# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
case EAI_NONAME: return UV_EAI_NONAME;
# endif
#endif
#if defined(EAI_OVERFLOW)
case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
#endif
#if defined(EAI_PROTOCOL)
case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
#endif
#if defined(EAI_SERVICE)
case EAI_SERVICE: return UV_EAI_SERVICE;
#endif
#if defined(EAI_SOCKTYPE)
case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
#endif
#if defined(EAI_SYSTEM)
case EAI_SYSTEM: return UV__ERR(errno);
#endif
}
assert(!"unknown EAI_* error code");
abort();
#ifndef __SUNPRO_C
return 0; /* Pacify compiler. */
#endif
}
static void uv__getaddrinfo_work(struct uv__work* w) {
uv_getaddrinfo_t* req;
int err;
req = container_of(w, uv_getaddrinfo_t, work_req);
err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
req->retcode = uv__getaddrinfo_translate_error(err);
}
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
uv_getaddrinfo_t* req;
req = container_of(w, uv_getaddrinfo_t, work_req);
uv__req_unregister(req->loop, req);
/* See initialization in uv_getaddrinfo(). */
if (req->hints)
uv__free(req->hints);
else if (req->service)
uv__free(req->service);
else if (req->hostname)
uv__free(req->hostname);
else
assert(0);
req->hints = NULL;
req->service = NULL;
req->hostname = NULL;
if (status == UV_ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
}
if (req->cb)
req->cb(req, req->retcode, req->addrinfo);
}
int uv_getaddrinfo(uv_loop_t* loop,
uv_getaddrinfo_t* req,
uv_getaddrinfo_cb cb,
const char* hostname,
const char* service,
const struct addrinfo* hints) {
char hostname_ascii[256];
size_t hostname_len;
size_t service_len;
size_t hints_len;
size_t len;
char* buf;
long rc;
if (req == NULL || (hostname == NULL && service == NULL))
return UV_EINVAL;
/* FIXME(bnoordhuis) IDNA does not seem to work z/OS,
* probably because it uses EBCDIC rather than ASCII.
*/
#ifdef __MVS__
(void) &hostname_ascii;
#else
if (hostname != NULL) {
rc = uv__idna_toascii(hostname,
hostname + strlen(hostname),
hostname_ascii,
hostname_ascii + sizeof(hostname_ascii));
if (rc < 0)
return rc;
hostname = hostname_ascii;
}
#endif
hostname_len = hostname ? strlen(hostname) + 1 : 0;
service_len = service ? strlen(service) + 1 : 0;
hints_len = hints ? sizeof(*hints) : 0;
buf = uv__malloc(hostname_len + service_len + hints_len);
if (buf == NULL)
return UV_ENOMEM;
uv__req_init(loop, req, UV_GETADDRINFO);
req->loop = loop;
req->cb = cb;
req->addrinfo = NULL;
req->hints = NULL;
req->service = NULL;
req->hostname = NULL;
req->retcode = 0;
/* order matters, see uv_getaddrinfo_done() */
len = 0;
if (hints) {
req->hints = memcpy(buf + len, hints, sizeof(*hints));
len += sizeof(*hints);
}
if (service) {
req->service = memcpy(buf + len, service, service_len);
len += service_len;
}
if (hostname)
req->hostname = memcpy(buf + len, hostname, hostname_len);
if (cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getaddrinfo_work,
uv__getaddrinfo_done);
return 0;
} else {
uv__getaddrinfo_work(&req->work_req);
uv__getaddrinfo_done(&req->work_req, 0);
return req->retcode;
}
}
void uv_freeaddrinfo(struct addrinfo* ai) {
if (ai)
freeaddrinfo(ai);
}
int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
char ifname_buf[UV_IF_NAMESIZE];
size_t len;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
if (if_indextoname(ifindex, ifname_buf) == NULL)
return UV__ERR(errno);
len = strnlen(ifname_buf, sizeof(ifname_buf));
if (*size <= len) {
*size = len + 1;
return UV_ENOBUFS;
}
memcpy(buffer, ifname_buf, len);
buffer[len] = '\0';
*size = len;
return 0;
}
int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
return uv_if_indextoname(ifindex, buffer, size);
}

121
deps/libuv/src/unix/getnameinfo.c vendored Normal file
View File

@ -0,0 +1,121 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "uv.h"
#include "internal.h"
static void uv__getnameinfo_work(struct uv__work* w) {
uv_getnameinfo_t* req;
int err;
socklen_t salen;
req = container_of(w, uv_getnameinfo_t, work_req);
if (req->storage.ss_family == AF_INET)
salen = sizeof(struct sockaddr_in);
else if (req->storage.ss_family == AF_INET6)
salen = sizeof(struct sockaddr_in6);
else
abort();
err = getnameinfo((struct sockaddr*) &req->storage,
salen,
req->host,
sizeof(req->host),
req->service,
sizeof(req->service),
req->flags);
req->retcode = uv__getaddrinfo_translate_error(err);
}
static void uv__getnameinfo_done(struct uv__work* w, int status) {
uv_getnameinfo_t* req;
char* host;
char* service;
req = container_of(w, uv_getnameinfo_t, work_req);
uv__req_unregister(req->loop, req);
host = service = NULL;
if (status == UV_ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
} else if (req->retcode == 0) {
host = req->host;
service = req->service;
}
if (req->getnameinfo_cb)
req->getnameinfo_cb(req, req->retcode, host, service);
}
/*
* Entry point for getnameinfo
* return 0 if a callback will be made
* return error code if validation fails
*/
int uv_getnameinfo(uv_loop_t* loop,
uv_getnameinfo_t* req,
uv_getnameinfo_cb getnameinfo_cb,
const struct sockaddr* addr,
int flags) {
if (req == NULL || addr == NULL)
return UV_EINVAL;
if (addr->sa_family == AF_INET) {
memcpy(&req->storage,
addr,
sizeof(struct sockaddr_in));
} else if (addr->sa_family == AF_INET6) {
memcpy(&req->storage,
addr,
sizeof(struct sockaddr_in6));
} else {
return UV_EINVAL;
}
uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
req->getnameinfo_cb = getnameinfo_cb;
req->flags = flags;
req->type = UV_GETNAMEINFO;
req->loop = loop;
req->retcode = 0;
if (getnameinfo_cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getnameinfo_work,
uv__getnameinfo_done);
return 0;
} else {
uv__getnameinfo_work(&req->work_req);
uv__getnameinfo_done(&req->work_req, 0);
return req->retcode;
}
}

167
deps/libuv/src/unix/haiku.c vendored Normal file
View File

@ -0,0 +1,167 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <FindDirectory.h> /* find_path() */
#include <OS.h>
void uv_loadavg(double avg[3]) {
avg[0] = 0;
avg[1] = 0;
avg[2] = 0;
}
int uv_exepath(char* buffer, size_t* size) {
char abspath[B_PATH_NAME_LENGTH];
status_t status;
ssize_t abspath_len;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
status = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, abspath,
sizeof(abspath));
if (status != B_OK)
return UV__ERR(status);
abspath_len = uv__strscpy(buffer, abspath, *size);
*size -= 1;
if (abspath_len >= 0 && *size > (size_t)abspath_len)
*size = (size_t)abspath_len;
return 0;
}
uint64_t uv_get_free_memory(void) {
status_t status;
system_info sinfo;
status = get_system_info(&sinfo);
if (status != B_OK)
return 0;
return (sinfo.max_pages - sinfo.used_pages) * B_PAGE_SIZE;
}
uint64_t uv_get_total_memory(void) {
status_t status;
system_info sinfo;
status = get_system_info(&sinfo);
if (status != B_OK)
return 0;
return sinfo.max_pages * B_PAGE_SIZE;
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}
int uv_resident_set_memory(size_t* rss) {
area_info area;
ssize_t cookie;
status_t status;
thread_info thread;
status = get_thread_info(find_thread(NULL), &thread);
if (status != B_OK)
return UV__ERR(status);
cookie = 0;
*rss = 0;
while (get_next_area_info(thread.team, &cookie, &area) == B_OK)
*rss += area.ram_size;
return 0;
}
int uv_uptime(double* uptime) {
/* system_time() returns time since booting in microseconds */
*uptime = (double)system_time() / 1000000;
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cpu_topology_node_info* topology_infos;
int i;
status_t status;
system_info system;
uint32_t topology_count;
uint64_t cpuspeed;
uv_cpu_info_t* cpu_info;
if (cpu_infos == NULL || count == NULL)
return UV_EINVAL;
status = get_cpu_topology_info(NULL, &topology_count);
if (status != B_OK)
return UV__ERR(status);
topology_infos = uv__malloc(topology_count * sizeof(*topology_infos));
if (topology_infos == NULL)
return UV_ENOMEM;
status = get_cpu_topology_info(topology_infos, &topology_count);
if (status != B_OK) {
uv__free(topology_infos);
return UV__ERR(status);
}
cpuspeed = 0;
for (i = 0; i < (int)topology_count; i++) {
if (topology_infos[i].type == B_TOPOLOGY_CORE) {
cpuspeed = topology_infos[i].data.core.default_frequency;
break;
}
}
uv__free(topology_infos);
status = get_system_info(&system);
if (status != B_OK)
return UV__ERR(status);
*cpu_infos = uv__calloc(system.cpu_count, sizeof(**cpu_infos));
if (*cpu_infos == NULL)
return UV_ENOMEM;
/* CPU time and model are not exposed by Haiku. */
cpu_info = *cpu_infos;
for (i = 0; i < (int)system.cpu_count; i++) {
cpu_info->model = uv__strdup("unknown");
cpu_info->speed = (int)(cpuspeed / 1000000);
cpu_info++;
}
*count = system.cpu_count;
return 0;
}

501
deps/libuv/src/unix/ibmi.c vendored Normal file
View File

@ -0,0 +1,501 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <utmp.h>
#include <libgen.h>
#include <sys/protosw.h>
#include <procinfo.h>
#include <sys/proc.h>
#include <sys/procfs.h>
#include <ctype.h>
#include <sys/mntctl.h>
#include <sys/vmount.h>
#include <limits.h>
#include <strings.h>
#include <sys/vnode.h>
#include <as400_protos.h>
#include <as400_types.h>
char* original_exepath = NULL;
uv_mutex_t process_title_mutex;
uv_once_t process_title_mutex_once = UV_ONCE_INIT;
typedef struct {
int bytes_available;
int bytes_returned;
char current_date_and_time[8];
char system_name[8];
char elapsed_time[6];
char restricted_state_flag;
char reserved;
int percent_processing_unit_used;
int jobs_in_system;
int percent_permanent_addresses;
int percent_temporary_addresses;
int system_asp;
int percent_system_asp_used;
int total_auxiliary_storage;
int current_unprotected_storage_used;
int maximum_unprotected_storage_used;
int percent_db_capability;
int main_storage_size;
int number_of_partitions;
int partition_identifier;
int reserved1;
int current_processing_capacity;
char processor_sharing_attribute;
char reserved2[3];
int number_of_processors;
int active_jobs_in_system;
int active_threads_in_system;
int maximum_jobs_in_system;
int percent_temporary_256mb_segments_used;
int percent_temporary_4gb_segments_used;
int percent_permanent_256mb_segments_used;
int percent_permanent_4gb_segments_used;
int percent_current_interactive_performance;
int percent_uncapped_cpu_capacity_used;
int percent_shared_processor_pool_used;
long main_storage_size_long;
} SSTS0200;
typedef struct {
char header[208];
unsigned char loca_adapter_address[12];
} LIND0500;
typedef struct {
int bytes_provided;
int bytes_available;
char msgid[7];
} errcode_s;
static const unsigned char e2a[256] = {
0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
32, 160, 161, 162, 163, 164, 165, 166, 167, 168, 91, 46, 60, 40, 43, 33,
38, 169, 170, 171, 172, 173, 174, 175, 176, 177, 93, 36, 42, 41, 59, 94,
45, 47, 178, 179, 180, 181, 182, 183, 184, 185, 124, 44, 37, 95, 62, 63,
186, 187, 188, 189, 190, 191, 192, 193, 194, 96, 58, 35, 64, 39, 61, 34,
195, 97, 98, 99, 100, 101, 102, 103, 104, 105, 196, 197, 198, 199, 200, 201,
202, 106, 107, 108, 109, 110, 111, 112, 113, 114, 203, 204, 205, 206, 207, 208,
209, 126, 115, 116, 117, 118, 119, 120, 121, 122, 210, 211, 212, 213, 214, 215,
216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 232, 233, 234, 235, 236, 237,
125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 238, 239, 240, 241, 242, 243,
92, 159, 83, 84, 85, 86, 87, 88, 89, 90, 244, 245, 246, 247, 248, 249,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250, 251, 252, 253, 254, 255};
static const unsigned char a2e[256] = {
0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95, 109,
121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 106, 208, 161, 7,
32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 225,
65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
88, 89, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117,
118, 119, 120, 128, 138, 139, 140, 141, 142, 143, 144, 154, 155, 156, 157, 158,
159, 160, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191, 202, 203, 204, 205, 206, 207, 218, 219,
220, 221, 222, 223, 234, 235, 236, 237, 238, 239, 250, 251, 252, 253, 254, 255};
static void iconv_e2a(unsigned char src[], unsigned char dst[], size_t length) {
size_t i;
for (i = 0; i < length; i++)
dst[i] = e2a[src[i]];
}
static void iconv_a2e(const char* src, unsigned char dst[], size_t length) {
size_t srclen;
size_t i;
srclen = strlen(src);
if (srclen > length)
abort();
for (i = 0; i < srclen; i++)
dst[i] = a2e[src[i]];
/* padding the remaining part with spaces */
for (; i < length; i++)
dst[i] = a2e[' '];
}
void init_process_title_mutex_once(void) {
uv_mutex_init(&process_title_mutex);
}
static int get_ibmi_system_status(SSTS0200* rcvr) {
/* rcvrlen is input parameter 2 to QWCRSSTS */
unsigned int rcvrlen = sizeof(*rcvr);
unsigned char format[8], reset_status[10];
/* format is input parameter 3 to QWCRSSTS */
iconv_a2e("SSTS0200", format, sizeof(format));
/* reset_status is input parameter 4 */
iconv_a2e("*NO", reset_status, sizeof(reset_status));
/* errcode is input parameter 5 to QWCRSSTS */
errcode_s errcode;
/* qwcrssts_pointer is the 16-byte tagged system pointer to QWCRSSTS */
ILEpointer __attribute__((aligned(16))) qwcrssts_pointer;
/* qwcrssts_argv is the array of argument pointers to QWCRSSTS */
void* qwcrssts_argv[6];
/* Set the IBM i pointer to the QSYS/QWCRSSTS *PGM object */
int rc = _RSLOBJ2(&qwcrssts_pointer, RSLOBJ_TS_PGM, "QWCRSSTS", "QSYS");
if (rc != 0)
return rc;
/* initialize the QWCRSSTS returned info structure */
memset(rcvr, 0, sizeof(*rcvr));
/* initialize the QWCRSSTS error code structure */
memset(&errcode, 0, sizeof(errcode));
errcode.bytes_provided = sizeof(errcode);
/* initialize the array of argument pointers for the QWCRSSTS API */
qwcrssts_argv[0] = rcvr;
qwcrssts_argv[1] = &rcvrlen;
qwcrssts_argv[2] = &format;
qwcrssts_argv[3] = &reset_status;
qwcrssts_argv[4] = &errcode;
qwcrssts_argv[5] = NULL;
/* Call the IBM i QWCRSSTS API from PASE */
rc = _PGMCALL(&qwcrssts_pointer, qwcrssts_argv, 0);
return rc;
}
uint64_t uv_get_free_memory(void) {
SSTS0200 rcvr;
if (get_ibmi_system_status(&rcvr))
return 0;
return (uint64_t)rcvr.main_storage_size * 1024ULL;
}
uint64_t uv_get_total_memory(void) {
SSTS0200 rcvr;
if (get_ibmi_system_status(&rcvr))
return 0;
return (uint64_t)rcvr.main_storage_size * 1024ULL;
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}
void uv_loadavg(double avg[3]) {
SSTS0200 rcvr;
if (get_ibmi_system_status(&rcvr)) {
avg[0] = avg[1] = avg[2] = 0;
return;
}
/* The average (in tenths) of the elapsed time during which the processing
* units were in use. For example, a value of 411 in binary would be 41.1%.
* This percentage could be greater than 100% for an uncapped partition.
*/
double processing_unit_used_percent =
rcvr.percent_processing_unit_used / 1000.0;
avg[0] = avg[1] = avg[2] = processing_unit_used_percent;
}
int uv_resident_set_memory(size_t* rss) {
*rss = 0;
return 0;
}
int uv_uptime(double* uptime) {
return UV_ENOSYS;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int numcpus, idx = 0;
uv_cpu_info_t* cpu_info;
*cpu_infos = NULL;
*count = 0;
numcpus = sysconf(_SC_NPROCESSORS_ONLN);
*cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t));
if (!*cpu_infos) {
return UV_ENOMEM;
}
cpu_info = *cpu_infos;
for (idx = 0; idx < numcpus; idx++) {
cpu_info->speed = 0;
cpu_info->model = uv__strdup("unknown");
cpu_info->cpu_times.user = 0;
cpu_info->cpu_times.sys = 0;
cpu_info->cpu_times.idle = 0;
cpu_info->cpu_times.irq = 0;
cpu_info->cpu_times.nice = 0;
cpu_info++;
}
*count = numcpus;
return 0;
}
static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) {
LIND0500 rcvr;
/* rcvrlen is input parameter 2 to QDCRLIND */
unsigned int rcvrlen = sizeof(rcvr);
unsigned char format[8], line_name[10];
unsigned char mac_addr[sizeof(rcvr.loca_adapter_address)];
int c[6];
/* format is input parameter 3 to QDCRLIND */
iconv_a2e("LIND0500", format, sizeof(format));
/* line_name is input parameter 4 to QDCRLIND */
iconv_a2e(line, line_name, sizeof(line_name));
/* err is input parameter 5 to QDCRLIND */
errcode_s err;
/* qwcrssts_pointer is the 16-byte tagged system pointer to QDCRLIND */
ILEpointer __attribute__((aligned(16))) qdcrlind_pointer;
/* qwcrssts_argv is the array of argument pointers to QDCRLIND */
void* qdcrlind_argv[6];
/* Set the IBM i pointer to the QSYS/QDCRLIND *PGM object */
int rc = _RSLOBJ2(&qdcrlind_pointer, RSLOBJ_TS_PGM, "QDCRLIND", "QSYS");
if (rc != 0)
return rc;
/* initialize the QDCRLIND returned info structure */
memset(&rcvr, 0, sizeof(rcvr));
/* initialize the QDCRLIND error code structure */
memset(&err, 0, sizeof(err));
err.bytes_provided = sizeof(err);
/* initialize the array of argument pointers for the QDCRLIND API */
qdcrlind_argv[0] = &rcvr;
qdcrlind_argv[1] = &rcvrlen;
qdcrlind_argv[2] = &format;
qdcrlind_argv[3] = &line_name;
qdcrlind_argv[4] = &err;
qdcrlind_argv[5] = NULL;
/* Call the IBM i QDCRLIND API from PASE */
rc = _PGMCALL(&qdcrlind_pointer, qdcrlind_argv, 0);
if (rc != 0)
return rc;
/* convert ebcdic loca_adapter_address to ascii first */
iconv_e2a(rcvr.loca_adapter_address, mac_addr,
sizeof(rcvr.loca_adapter_address));
/* convert loca_adapter_address(char[12]) to phys_addr(char[6]) */
int r = sscanf(mac_addr, "%02x%02x%02x%02x%02x%02x",
&c[0], &c[1], &c[2], &c[3], &c[4], &c[5]);
if (r == ARRAY_SIZE(c)) {
(*phys_addr)[0] = c[0];
(*phys_addr)[1] = c[1];
(*phys_addr)[2] = c[2];
(*phys_addr)[3] = c[3];
(*phys_addr)[4] = c[4];
(*phys_addr)[5] = c[5];
} else {
memset(*phys_addr, 0, sizeof(*phys_addr));
rc = -1;
}
return rc;
}
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
struct ifaddrs_pase *ifap = NULL, *cur;
int inet6, r = 0;
*count = 0;
*addresses = NULL;
if (Qp2getifaddrs(&ifap))
return UV_ENOSYS;
/* The first loop to get the size of the array to be allocated */
for (cur = ifap; cur; cur = cur->ifa_next) {
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
cur->ifa_addr->sa_family == AF_INET))
continue;
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
continue;
(*count)++;
}
if (*count == 0) {
Qp2freeifaddrs(ifap);
return 0;
}
/* Alloc the return interface structs */
*addresses = uv__calloc(*count, sizeof(**addresses));
if (*addresses == NULL) {
Qp2freeifaddrs(ifap);
return UV_ENOMEM;
}
address = *addresses;
/* The second loop to fill in the array */
for (cur = ifap; cur; cur = cur->ifa_next) {
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
cur->ifa_addr->sa_family == AF_INET))
continue;
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
continue;
address->name = uv__strdup(cur->ifa_name);
inet6 = (cur->ifa_addr->sa_family == AF_INET6);
if (inet6) {
address->address.address6 = *((struct sockaddr_in6*)cur->ifa_addr);
address->netmask.netmask6 = *((struct sockaddr_in6*)cur->ifa_netmask);
address->netmask.netmask6.sin6_family = AF_INET6;
} else {
address->address.address4 = *((struct sockaddr_in*)cur->ifa_addr);
address->netmask.netmask4 = *((struct sockaddr_in*)cur->ifa_netmask);
address->netmask.netmask4.sin_family = AF_INET;
}
address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0;
if (!address->is_internal) {
int rc = get_ibmi_physical_address(address->name, &address->phys_addr);
if (rc != 0)
r = rc;
}
address++;
}
Qp2freeifaddrs(ifap);
return r;
}
void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
int i;
for (i = 0; i < count; ++i) {
uv__free(addresses[i].name);
}
uv__free(addresses);
}
char** uv_setup_args(int argc, char** argv) {
char exepath[UV__PATH_MAX];
char* s;
size_t size;
if (argc > 0) {
/* Use argv[0] to determine value for uv_exepath(). */
size = sizeof(exepath);
if (uv__search_path(argv[0], exepath, &size) == 0) {
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
original_exepath = uv__strdup(exepath);
uv_mutex_unlock(&process_title_mutex);
}
}
return argv;
}
int uv_set_process_title(const char* title) {
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return UV_EINVAL;
buffer[0] = '\0';
return 0;
}
void uv__process_title_cleanup(void) {
}

344
deps/libuv/src/unix/internal.h vendored Normal file
View File

@ -0,0 +1,344 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_UNIX_INTERNAL_H_
#define UV_UNIX_INTERNAL_H_
#include "uv-common.h"
#include <assert.h>
#include <limits.h> /* _POSIX_PATH_MAX, PATH_MAX */
#include <stdlib.h> /* abort */
#include <string.h> /* strrchr */
#include <fcntl.h> /* O_CLOEXEC and O_NONBLOCK, if supported. */
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#if defined(__STRICT_ANSI__)
# define inline __inline
#endif
#if defined(__linux__)
# include "linux-syscalls.h"
#endif /* __linux__ */
#if defined(__MVS__)
# include "os390-syscalls.h"
#endif /* __MVS__ */
#if defined(__sun)
# include <sys/port.h>
# include <port.h>
#endif /* __sun */
#if defined(_AIX)
# define reqevents events
# define rtnevents revents
# include <sys/poll.h>
#else
# include <poll.h>
#endif /* _AIX */
#if defined(__APPLE__) && !TARGET_OS_IPHONE
# include <AvailabilityMacros.h>
#endif
#if defined(PATH_MAX)
# define UV__PATH_MAX PATH_MAX
#else
# define UV__PATH_MAX 8192
#endif
#if defined(__ANDROID__)
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
# ifdef pthread_sigmask
# undef pthread_sigmask
# endif
# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
#endif
#define ACCESS_ONCE(type, var) \
(*(volatile type*) &(var))
#define ROUND_UP(a, b) \
((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a))
#define UNREACHABLE() \
do { \
assert(0 && "unreachable code"); \
abort(); \
} \
while (0)
#define SAVE_ERRNO(block) \
do { \
int _saved_errno = errno; \
do { block; } while (0); \
errno = _saved_errno; \
} \
while (0)
/* The __clang__ and __INTEL_COMPILER checks are superfluous because they
* define __GNUC__. They are here to convey to you, dear reader, that these
* macros are enabled when compiling with clang or icc.
*/
#if defined(__clang__) || \
defined(__GNUC__) || \
defined(__INTEL_COMPILER)
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
#else
# define UV_UNUSED(declaration) declaration
#endif
/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */
#ifdef POLLRDHUP
# define UV__POLLRDHUP POLLRDHUP
#else
# define UV__POLLRDHUP 0x2000
#endif
#ifdef POLLPRI
# define UV__POLLPRI POLLPRI
#else
# define UV__POLLPRI 0
#endif
#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
/*
* It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
* Try using fixed value const and give up, if it doesn't work
*/
# define O_CLOEXEC 0x00100000
#endif
typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
/* loop flags */
enum {
UV_LOOP_BLOCK_SIGPROF = 1
};
/* flags of excluding ifaddr */
enum {
UV__EXCLUDE_IFPHYS,
UV__EXCLUDE_IFADDR
};
typedef enum {
UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
} uv_clocktype_t;
struct uv__stream_queued_fds_s {
unsigned int size;
unsigned int offset;
int fds[1];
};
#if defined(_AIX) || \
defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__linux__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
#define uv__cloexec uv__cloexec_ioctl
#define uv__nonblock uv__nonblock_ioctl
#else
#define uv__cloexec uv__cloexec_fcntl
#define uv__nonblock uv__nonblock_fcntl
#endif
/* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute
* when O_NDELAY is not equal to O_NONBLOCK. Case in point: linux/sparc32
* and linux/sparc64, where O_NDELAY is O_NONBLOCK + another bit.
*
* Libuv uses uv__nonblock_fcntl() directly sometimes so ensure that it
* commutes with uv__nonblock().
*/
#if defined(__linux__) && O_NDELAY != O_NONBLOCK
#undef uv__nonblock
#define uv__nonblock uv__nonblock_fcntl
#endif
/* core */
int uv__cloexec_ioctl(int fd, int set);
int uv__cloexec_fcntl(int fd, int set);
int uv__nonblock_ioctl(int fd, int set);
int uv__nonblock_fcntl(int fd, int set);
int uv__close(int fd); /* preserves errno */
int uv__close_nocheckstdio(int fd);
int uv__close_nocancel(int fd);
int uv__socket(int domain, int type, int protocol);
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
void uv__make_close_pending(uv_handle_t* handle);
int uv__getiovmax(void);
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);
void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events);
void uv__io_close(uv_loop_t* loop, uv__io_t* w);
void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
int uv__io_active(const uv__io_t* w, unsigned int events);
int uv__io_check_fd(uv_loop_t* loop, int fd);
void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
int uv__io_fork(uv_loop_t* loop);
int uv__fd_exists(uv_loop_t* loop, int fd);
/* async */
void uv__async_stop(uv_loop_t* loop);
int uv__async_fork(uv_loop_t* loop);
/* loop */
void uv__run_idle(uv_loop_t* loop);
void uv__run_check(uv_loop_t* loop);
void uv__run_prepare(uv_loop_t* loop);
/* stream */
void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream,
uv_handle_type type);
int uv__stream_open(uv_stream_t*, int fd, int flags);
void uv__stream_destroy(uv_stream_t* stream);
#if defined(__APPLE__)
int uv__stream_try_select(uv_stream_t* stream, int* fd);
#endif /* defined(__APPLE__) */
void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
int uv__accept(int sockfd);
int uv__dup2_cloexec(int oldfd, int newfd);
int uv__open_cloexec(const char* path, int flags);
/* tcp */
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
int uv__tcp_nodelay(int fd, int on);
int uv__tcp_keepalive(int fd, int on, unsigned int delay);
/* pipe */
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
/* signal */
void uv__signal_close(uv_signal_t* handle);
void uv__signal_global_once_init(void);
void uv__signal_loop_cleanup(uv_loop_t* loop);
int uv__signal_loop_fork(uv_loop_t* loop);
/* platform specific */
uint64_t uv__hrtime(uv_clocktype_t type);
int uv__kqueue_init(uv_loop_t* loop);
int uv__platform_loop_init(uv_loop_t* loop);
void uv__platform_loop_delete(uv_loop_t* loop);
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
/* various */
void uv__async_close(uv_async_t* handle);
void uv__check_close(uv_check_t* handle);
void uv__fs_event_close(uv_fs_event_t* handle);
void uv__idle_close(uv_idle_t* handle);
void uv__pipe_close(uv_pipe_t* handle);
void uv__poll_close(uv_poll_t* handle);
void uv__prepare_close(uv_prepare_t* handle);
void uv__process_close(uv_process_t* handle);
void uv__stream_close(uv_stream_t* handle);
void uv__tcp_close(uv_tcp_t* handle);
void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle);
uv_handle_type uv__handle_type(int fd);
FILE* uv__open_file(const char* path);
int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__search_path(const char* prog, char* buf, size_t* buflen);
/* random */
int uv__random_devurandom(void* buf, size_t buflen);
int uv__random_getrandom(void* buf, size_t buflen);
int uv__random_getentropy(void* buf, size_t buflen);
int uv__random_readpath(const char* path, void* buf, size_t buflen);
int uv__random_sysctl(void* buf, size_t buflen);
#if defined(__APPLE__)
int uv___stream_fd(const uv_stream_t* handle);
#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle)))
#else
#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
#endif /* defined(__APPLE__) */
#ifdef O_NONBLOCK
# define UV__F_NONBLOCK O_NONBLOCK
#else
# define UV__F_NONBLOCK 1
#endif
int uv__make_pipe(int fds[2], int flags);
#if defined(__APPLE__)
int uv__fsevents_init(uv_fs_event_t* handle);
int uv__fsevents_close(uv_fs_event_t* handle);
void uv__fsevents_loop_delete(uv_loop_t* loop);
#endif /* defined(__APPLE__) */
UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
/* Use a fast time source if available. We only need millisecond precision.
*/
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
}
UV_UNUSED(static char* uv__basename_r(const char* path)) {
char* s;
s = strrchr(path, '/');
if (s == NULL)
return (char*) path;
return s + 1;
}
#if defined(__linux__)
int uv__inotify_fork(uv_loop_t* loop, void* old_watchers);
#endif
typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
int uv__getsockpeername(const uv_handle_t* handle,
uv__peersockfunc func,
struct sockaddr* name,
int* namelen);
#if defined(__linux__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__)
#define HAVE_MMSG 1
struct uv__mmsghdr {
struct msghdr msg_hdr;
unsigned int msg_len;
};
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen);
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen);
#else
#define HAVE_MMSG 0
#endif
#endif /* UV_UNIX_INTERNAL_H_ */

585
deps/libuv/src/unix/kqueue.c vendored Normal file
View File

@ -0,0 +1,585 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
/*
* Required on
* - Until at least FreeBSD 11.0
* - Older versions of Mac OS X
*
* http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp
*/
#ifndef EV_OOBAND
#define EV_OOBAND EV_FLAG1
#endif
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
int uv__kqueue_init(uv_loop_t* loop) {
loop->backend_fd = kqueue();
if (loop->backend_fd == -1)
return UV__ERR(errno);
uv__cloexec(loop->backend_fd, 1);
return 0;
}
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
static int uv__has_forked_with_cfrunloop;
#endif
int uv__io_fork(uv_loop_t* loop) {
int err;
loop->backend_fd = -1;
err = uv__kqueue_init(loop);
if (err)
return err;
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if (loop->cf_state != NULL) {
/* We cannot start another CFRunloop and/or thread in the child
process; CF aborts if you try or if you try to touch the thread
at all to kill it. So the best we can do is ignore it from now
on. This means we can't watch directories in the same way
anymore (like other BSDs). It also means we cannot properly
clean up the allocated resources; calling
uv__fsevents_loop_delete from uv_loop_close will crash the
process. So we sidestep the issue by pretending like we never
started it in the first place.
*/
uv__store_relaxed(&uv__has_forked_with_cfrunloop, 1);
uv__free(loop->cf_state);
loop->cf_state = NULL;
}
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
return err;
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct kevent ev;
int rc;
rc = 0;
EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
rc = UV__ERR(errno);
EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
if (rc == 0)
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
abort();
return rc;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
struct kevent events[1024];
struct kevent* ev;
struct timespec spec;
unsigned int nevents;
unsigned int revents;
QUEUE* q;
uv__io_t* w;
sigset_t* pset;
sigset_t set;
uint64_t base;
uint64_t diff;
int have_signals;
int filter;
int fflags;
int count;
int nfds;
int fd;
int op;
int i;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
nevents = 0;
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) {
filter = EVFILT_READ;
fflags = 0;
op = EV_ADD;
if (w->cb == uv__fs_event) {
filter = EVFILT_VNODE;
fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
| NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
}
EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
if (++nevents == ARRAY_SIZE(events)) {
if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
abort();
nevents = 0;
}
}
if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) {
EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
if (++nevents == ARRAY_SIZE(events)) {
if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
abort();
nevents = 0;
}
}
if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) {
EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0);
if (++nevents == ARRAY_SIZE(events)) {
if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
abort();
nevents = 0;
}
}
w->events = w->pevents;
}
pset = NULL;
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
pset = &set;
sigemptyset(pset);
sigaddset(pset, SIGPROF);
}
assert(timeout >= -1);
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (;; nevents = 0) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
if (timeout != -1) {
spec.tv_sec = timeout / 1000;
spec.tv_nsec = (timeout % 1000) * 1000000;
}
if (pset != NULL)
pthread_sigmask(SIG_BLOCK, pset, NULL);
nfds = kevent(loop->backend_fd,
events,
nevents,
events,
ARRAY_SIZE(events),
timeout == -1 ? NULL : &spec);
if (pset != NULL)
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
if (timeout == -1)
continue;
if (timeout > 0)
goto update_timeout;
}
assert(timeout != -1);
return;
}
if (nfds == -1) {
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
}
have_signals = 0;
nevents = 0;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
ev = events + i;
fd = ev->ident;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
w = loop->watchers[fd];
if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it.
* TODO: batch up. */
struct kevent events[1];
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
if (errno != EBADF && errno != ENOENT)
abort();
continue;
}
if (ev->filter == EVFILT_VNODE) {
assert(w->events == POLLIN);
assert(w->pevents == POLLIN);
uv__metrics_update_idle_time(loop);
w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
nevents++;
continue;
}
revents = 0;
if (ev->filter == EVFILT_READ) {
if (w->pevents & POLLIN) {
revents |= POLLIN;
w->rcount = ev->data;
} else {
/* TODO batch up */
struct kevent events[1];
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
if (errno != ENOENT)
abort();
}
}
if (ev->filter == EV_OOBAND) {
if (w->pevents & UV__POLLPRI) {
revents |= UV__POLLPRI;
w->rcount = ev->data;
} else {
/* TODO batch up */
struct kevent events[1];
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
if (errno != ENOENT)
abort();
}
}
if (ev->filter == EVFILT_WRITE) {
if (w->pevents & POLLOUT) {
revents |= POLLOUT;
w->wcount = ev->data;
} else {
/* TODO batch up */
struct kevent events[1];
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
if (errno != ENOENT)
abort();
}
}
if (ev->flags & EV_ERROR)
revents |= POLLERR;
if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
revents |= UV__POLLRDHUP;
if (revents == 0)
continue;
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher) {
have_signals = 1;
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, revents);
}
nevents++;
}
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
timeout = 0;
continue;
}
return;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
diff = loop->time - base;
if (diff >= (uint64_t) timeout)
return;
timeout -= diff;
}
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct kevent* events;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
assert(fd >= 0);
events = (struct kevent*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].ident == fd)
events[i].ident = -1;
}
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
uv_fs_event_t* handle;
struct kevent ev;
int events;
const char* path;
#if defined(F_GETPATH)
/* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
char pathbuf[MAXPATHLEN];
#endif
handle = container_of(w, uv_fs_event_t, event_watcher);
if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
events = UV_CHANGE;
else
events = UV_RENAME;
path = NULL;
#if defined(F_GETPATH)
/* Also works when the file has been unlinked from the file system. Passing
* in the path when the file has been deleted is arguably a little strange
* but it's consistent with what the inotify backend does.
*/
if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
path = uv__basename_r(pathbuf);
#endif
handle->cb(handle, path, events, 0);
if (handle->event_watcher.fd == -1)
return;
/* Watcher operates in one-shot mode, re-arm it. */
fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
| NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
abort();
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
const char* path,
unsigned int flags) {
int fd;
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
struct stat statbuf;
#endif
if (uv__is_active(handle))
return UV_EINVAL;
handle->cb = cb;
handle->path = uv__strdup(path);
if (handle->path == NULL)
return UV_ENOMEM;
/* TODO open asynchronously - but how do we report back errors? */
fd = open(handle->path, O_RDONLY);
if (fd == -1) {
uv__free(handle->path);
handle->path = NULL;
return UV__ERR(errno);
}
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
/* Nullify field to perform checks later */
handle->cf_cb = NULL;
handle->realpath = NULL;
handle->realpath_len = 0;
handle->cf_flags = flags;
if (fstat(fd, &statbuf))
goto fallback;
/* FSEvents works only with directories */
if (!(statbuf.st_mode & S_IFDIR))
goto fallback;
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) {
int r;
/* The fallback fd is no longer needed */
uv__close_nocheckstdio(fd);
handle->event_watcher.fd = -1;
r = uv__fsevents_init(handle);
if (r == 0) {
uv__handle_start(handle);
} else {
uv__free(handle->path);
handle->path = NULL;
}
return r;
}
fallback:
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
uv__handle_start(handle);
uv__io_init(&handle->event_watcher, uv__fs_event, fd);
uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
return 0;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
int r;
r = 0;
if (!uv__is_active(handle))
return 0;
uv__handle_stop(handle);
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop))
if (handle->cf_cb != NULL)
r = uv__fsevents_close(handle);
#endif
if (handle->event_watcher.fd != -1) {
uv__io_close(handle->loop, &handle->event_watcher);
uv__close(handle->event_watcher.fd);
handle->event_watcher.fd = -1;
}
uv__free(handle->path);
handle->path = NULL;
return r;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
}

1146
deps/libuv/src/unix/linux-core.c vendored Normal file

File diff suppressed because it is too large Load Diff

327
deps/libuv/src/unix/linux-inotify.c vendored Normal file
View File

@ -0,0 +1,327 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "uv/tree.h"
#include "internal.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include <unistd.h>
struct watcher_list {
RB_ENTRY(watcher_list) entry;
QUEUE watchers;
int iterating;
char* path;
int wd;
};
struct watcher_root {
struct watcher_list* rbh_root;
};
#define CAST(p) ((struct watcher_root*)(p))
static int compare_watchers(const struct watcher_list* a,
const struct watcher_list* b) {
if (a->wd < b->wd) return -1;
if (a->wd > b->wd) return 1;
return 0;
}
RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers)
static void uv__inotify_read(uv_loop_t* loop,
uv__io_t* w,
unsigned int revents);
static void maybe_free_watcher_list(struct watcher_list* w,
uv_loop_t* loop);
static int init_inotify(uv_loop_t* loop) {
int fd;
if (loop->inotify_fd != -1)
return 0;
fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (fd < 0)
return UV__ERR(errno);
loop->inotify_fd = fd;
uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
uv__io_start(loop, &loop->inotify_read_watcher, POLLIN);
return 0;
}
int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) {
/* Open the inotify_fd, and re-arm all the inotify watchers. */
int err;
struct watcher_list* tmp_watcher_list_iter;
struct watcher_list* watcher_list;
struct watcher_list tmp_watcher_list;
QUEUE queue;
QUEUE* q;
uv_fs_event_t* handle;
char* tmp_path;
if (old_watchers != NULL) {
/* We must restore the old watcher list to be able to close items
* out of it.
*/
loop->inotify_watchers = old_watchers;
QUEUE_INIT(&tmp_watcher_list.watchers);
/* Note that the queue we use is shared with the start and stop()
* functions, making QUEUE_FOREACH unsafe to use. So we use the
* QUEUE_MOVE trick to safely iterate. Also don't free the watcher
* list until we're done iterating. c.f. uv__inotify_read.
*/
RB_FOREACH_SAFE(watcher_list, watcher_root,
CAST(&old_watchers), tmp_watcher_list_iter) {
watcher_list->iterating = 1;
QUEUE_MOVE(&watcher_list->watchers, &queue);
while (!QUEUE_EMPTY(&queue)) {
q = QUEUE_HEAD(&queue);
handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
/* It's critical to keep a copy of path here, because it
* will be set to NULL by stop() and then deallocated by
* maybe_free_watcher_list
*/
tmp_path = uv__strdup(handle->path);
assert(tmp_path != NULL);
QUEUE_REMOVE(q);
QUEUE_INSERT_TAIL(&watcher_list->watchers, q);
uv_fs_event_stop(handle);
QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers);
handle->path = tmp_path;
}
watcher_list->iterating = 0;
maybe_free_watcher_list(watcher_list, loop);
}
QUEUE_MOVE(&tmp_watcher_list.watchers, &queue);
while (!QUEUE_EMPTY(&queue)) {
q = QUEUE_HEAD(&queue);
QUEUE_REMOVE(q);
handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
tmp_path = handle->path;
handle->path = NULL;
err = uv_fs_event_start(handle, handle->cb, tmp_path, 0);
uv__free(tmp_path);
if (err)
return err;
}
}
return 0;
}
static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) {
struct watcher_list w;
w.wd = wd;
return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w);
}
static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
/* if the watcher_list->watchers is being iterated over, we can't free it. */
if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
/* No watchers left for this path. Clean up. */
RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
inotify_rm_watch(loop->inotify_fd, w->wd);
uv__free(w);
}
}
static void uv__inotify_read(uv_loop_t* loop,
uv__io_t* dummy,
unsigned int events) {
const struct inotify_event* e;
struct watcher_list* w;
uv_fs_event_t* h;
QUEUE queue;
QUEUE* q;
const char* path;
ssize_t size;
const char *p;
/* needs to be large enough for sizeof(inotify_event) + strlen(path) */
char buf[4096];
while (1) {
do
size = read(loop->inotify_fd, buf, sizeof(buf));
while (size == -1 && errno == EINTR);
if (size == -1) {
assert(errno == EAGAIN || errno == EWOULDBLOCK);
break;
}
assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */
/* Now we have one or more inotify_event structs. */
for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
e = (const struct inotify_event*) p;
events = 0;
if (e->mask & (IN_ATTRIB|IN_MODIFY))
events |= UV_CHANGE;
if (e->mask & ~(IN_ATTRIB|IN_MODIFY))
events |= UV_RENAME;
w = find_watcher(loop, e->wd);
if (w == NULL)
continue; /* Stale event, no watchers left. */
/* inotify does not return the filename when monitoring a single file
* for modifications. Repurpose the filename for API compatibility.
* I'm not convinced this is a good thing, maybe it should go.
*/
path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path);
/* We're about to iterate over the queue and call user's callbacks.
* What can go wrong?
* A callback could call uv_fs_event_stop()
* and the queue can change under our feet.
* So, we use QUEUE_MOVE() trick to safely iterate over the queue.
* And we don't free the watcher_list until we're done iterating.
*
* First,
* tell uv_fs_event_stop() (that could be called from a user's callback)
* not to free watcher_list.
*/
w->iterating = 1;
QUEUE_MOVE(&w->watchers, &queue);
while (!QUEUE_EMPTY(&queue)) {
q = QUEUE_HEAD(&queue);
h = QUEUE_DATA(q, uv_fs_event_t, watchers);
QUEUE_REMOVE(q);
QUEUE_INSERT_TAIL(&w->watchers, q);
h->cb(h, path, events, 0);
}
/* done iterating, time to (maybe) free empty watcher_list */
w->iterating = 0;
maybe_free_watcher_list(w, loop);
}
}
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
const char* path,
unsigned int flags) {
struct watcher_list* w;
size_t len;
int events;
int err;
int wd;
if (uv__is_active(handle))
return UV_EINVAL;
err = init_inotify(handle->loop);
if (err)
return err;
events = IN_ATTRIB
| IN_CREATE
| IN_MODIFY
| IN_DELETE
| IN_DELETE_SELF
| IN_MOVE_SELF
| IN_MOVED_FROM
| IN_MOVED_TO;
wd = inotify_add_watch(handle->loop->inotify_fd, path, events);
if (wd == -1)
return UV__ERR(errno);
w = find_watcher(handle->loop, wd);
if (w)
goto no_insert;
len = strlen(path) + 1;
w = uv__malloc(sizeof(*w) + len);
if (w == NULL)
return UV_ENOMEM;
w->wd = wd;
w->path = memcpy(w + 1, path, len);
QUEUE_INIT(&w->watchers);
w->iterating = 0;
RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
no_insert:
uv__handle_start(handle);
QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers);
handle->path = w->path;
handle->cb = cb;
handle->wd = wd;
return 0;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
struct watcher_list* w;
if (!uv__is_active(handle))
return 0;
w = find_watcher(handle->loop, handle->wd);
assert(w != NULL);
handle->wd = -1;
handle->path = NULL;
uv__handle_stop(handle);
QUEUE_REMOVE(&handle->watchers);
maybe_free_watcher_list(w, handle->loop);
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
}

267
deps/libuv/src/unix/linux-syscalls.c vendored Normal file
View File

@ -0,0 +1,267 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "linux-syscalls.h"
#include <unistd.h>
#include <signal.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <errno.h>
#if defined(__arm__)
# if defined(__thumb__) || defined(__ARM_EABI__)
# define UV_SYSCALL_BASE 0
# else
# define UV_SYSCALL_BASE 0x900000
# endif
#endif /* __arm__ */
#ifndef __NR_recvmmsg
# if defined(__x86_64__)
# define __NR_recvmmsg 299
# elif defined(__arm__)
# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
# endif
#endif /* __NR_recvmsg */
#ifndef __NR_sendmmsg
# if defined(__x86_64__)
# define __NR_sendmmsg 307
# elif defined(__arm__)
# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
# endif
#endif /* __NR_sendmmsg */
#ifndef __NR_utimensat
# if defined(__x86_64__)
# define __NR_utimensat 280
# elif defined(__i386__)
# define __NR_utimensat 320
# elif defined(__arm__)
# define __NR_utimensat (UV_SYSCALL_BASE + 348)
# endif
#endif /* __NR_utimensat */
#ifndef __NR_preadv
# if defined(__x86_64__)
# define __NR_preadv 295
# elif defined(__i386__)
# define __NR_preadv 333
# elif defined(__arm__)
# define __NR_preadv (UV_SYSCALL_BASE + 361)
# endif
#endif /* __NR_preadv */
#ifndef __NR_pwritev
# if defined(__x86_64__)
# define __NR_pwritev 296
# elif defined(__i386__)
# define __NR_pwritev 334
# elif defined(__arm__)
# define __NR_pwritev (UV_SYSCALL_BASE + 362)
# endif
#endif /* __NR_pwritev */
#ifndef __NR_dup3
# if defined(__x86_64__)
# define __NR_dup3 292
# elif defined(__i386__)
# define __NR_dup3 330
# elif defined(__arm__)
# define __NR_dup3 (UV_SYSCALL_BASE + 358)
# endif
#endif /* __NR_pwritev */
#ifndef __NR_copy_file_range
# if defined(__x86_64__)
# define __NR_copy_file_range 326
# elif defined(__i386__)
# define __NR_copy_file_range 377
# elif defined(__s390__)
# define __NR_copy_file_range 375
# elif defined(__arm__)
# define __NR_copy_file_range (UV_SYSCALL_BASE + 391)
# elif defined(__aarch64__)
# define __NR_copy_file_range 285
# elif defined(__powerpc__)
# define __NR_copy_file_range 379
# elif defined(__arc__)
# define __NR_copy_file_range 285
# endif
#endif /* __NR_copy_file_range */
#ifndef __NR_statx
# if defined(__x86_64__)
# define __NR_statx 332
# elif defined(__i386__)
# define __NR_statx 383
# elif defined(__aarch64__)
# define __NR_statx 397
# elif defined(__arm__)
# define __NR_statx (UV_SYSCALL_BASE + 397)
# elif defined(__ppc__)
# define __NR_statx 383
# elif defined(__s390__)
# define __NR_statx 379
# endif
#endif /* __NR_statx */
#ifndef __NR_getrandom
# if defined(__x86_64__)
# define __NR_getrandom 318
# elif defined(__i386__)
# define __NR_getrandom 355
# elif defined(__aarch64__)
# define __NR_getrandom 384
# elif defined(__arm__)
# define __NR_getrandom (UV_SYSCALL_BASE + 384)
# elif defined(__ppc__)
# define __NR_getrandom 359
# elif defined(__s390__)
# define __NR_getrandom 349
# endif
#endif /* __NR_getrandom */
struct uv__mmsghdr;
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if defined(__i386__)
unsigned long args[4];
int rc;
args[0] = (unsigned long) fd;
args[1] = (unsigned long) mmsg;
args[2] = (unsigned long) vlen;
args[3] = /* flags */ 0;
/* socketcall() raises EINVAL when SYS_SENDMMSG is not supported. */
rc = syscall(/* __NR_socketcall */ 102, 20 /* SYS_SENDMMSG */, args);
if (rc == -1)
if (errno == EINVAL)
errno = ENOSYS;
return rc;
#elif defined(__NR_sendmmsg)
return syscall(__NR_sendmmsg, fd, mmsg, vlen, /* flags */ 0);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if defined(__i386__)
unsigned long args[5];
int rc;
args[0] = (unsigned long) fd;
args[1] = (unsigned long) mmsg;
args[2] = (unsigned long) vlen;
args[3] = /* flags */ 0;
args[4] = /* timeout */ 0;
/* socketcall() raises EINVAL when SYS_RECVMMSG is not supported. */
rc = syscall(/* __NR_socketcall */ 102, 19 /* SYS_RECVMMSG */, args);
if (rc == -1)
if (errno == EINVAL)
errno = ENOSYS;
return rc;
#elif defined(__NR_recvmmsg)
return syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0);
#else
return errno = ENOSYS, -1;
#endif
}
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
#if defined(__NR_preadv)
return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#else
return errno = ENOSYS, -1;
#endif
}
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
#if defined(__NR_pwritev)
return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#else
return errno = ENOSYS, -1;
#endif
}
int uv__dup3(int oldfd, int newfd, int flags) {
#if defined(__NR_dup3)
return syscall(__NR_dup3, oldfd, newfd, flags);
#else
return errno = ENOSYS, -1;
#endif
}
ssize_t
uv__fs_copy_file_range(int fd_in,
ssize_t* off_in,
int fd_out,
ssize_t* off_out,
size_t len,
unsigned int flags)
{
#ifdef __NR_copy_file_range
return syscall(__NR_copy_file_range,
fd_in,
off_in,
fd_out,
off_out,
len,
flags);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__statx(int dirfd,
const char* path,
int flags,
unsigned int mask,
struct uv__statx* statxbuf) {
/* __NR_statx make Android box killed by SIGSYS.
* That looks like a seccomp2 sandbox filter rejecting the system call.
*/
#if defined(__NR_statx) && !defined(__ANDROID__)
return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
#else
return errno = ENOSYS, -1;
#endif
}
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) {
#if defined(__NR_getrandom)
return syscall(__NR_getrandom, buf, buflen, flags);
#else
return errno = ENOSYS, -1;
#endif
}

81
deps/libuv/src/unix/linux-syscalls.h vendored Normal file
View File

@ -0,0 +1,81 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_LINUX_SYSCALL_H_
#define UV_LINUX_SYSCALL_H_
#undef _GNU_SOURCE
#define _GNU_SOURCE
#include <stdint.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
struct uv__statx_timestamp {
int64_t tv_sec;
uint32_t tv_nsec;
int32_t unused0;
};
struct uv__statx {
uint32_t stx_mask;
uint32_t stx_blksize;
uint64_t stx_attributes;
uint32_t stx_nlink;
uint32_t stx_uid;
uint32_t stx_gid;
uint16_t stx_mode;
uint16_t unused0;
uint64_t stx_ino;
uint64_t stx_size;
uint64_t stx_blocks;
uint64_t stx_attributes_mask;
struct uv__statx_timestamp stx_atime;
struct uv__statx_timestamp stx_btime;
struct uv__statx_timestamp stx_ctime;
struct uv__statx_timestamp stx_mtime;
uint32_t stx_rdev_major;
uint32_t stx_rdev_minor;
uint32_t stx_dev_major;
uint32_t stx_dev_minor;
uint64_t unused1[14];
};
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
int uv__dup3(int oldfd, int newfd, int flags);
ssize_t
uv__fs_copy_file_range(int fd_in,
ssize_t* off_in,
int fd_out,
ssize_t* off_out,
size_t len,
unsigned int flags);
int uv__statx(int dirfd,
const char* path,
int flags,
unsigned int mask,
struct uv__statx* statxbuf);
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags);
#endif /* UV_LINUX_SYSCALL_H_ */

68
deps/libuv/src/unix/loop-watcher.c vendored Normal file
View File

@ -0,0 +1,68 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#define UV_LOOP_WATCHER_DEFINE(name, type) \
int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \
handle->name##_cb = NULL; \
return 0; \
} \
\
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
if (uv__is_active(handle)) return 0; \
if (cb == NULL) return UV_EINVAL; \
QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
handle->name##_cb = cb; \
uv__handle_start(handle); \
return 0; \
} \
\
int uv_##name##_stop(uv_##name##_t* handle) { \
if (!uv__is_active(handle)) return 0; \
QUEUE_REMOVE(&handle->queue); \
uv__handle_stop(handle); \
return 0; \
} \
\
void uv__run_##name(uv_loop_t* loop) { \
uv_##name##_t* h; \
QUEUE queue; \
QUEUE* q; \
QUEUE_MOVE(&loop->name##_handles, &queue); \
while (!QUEUE_EMPTY(&queue)) { \
q = QUEUE_HEAD(&queue); \
h = QUEUE_DATA(q, uv_##name##_t, queue); \
QUEUE_REMOVE(q); \
QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
h->name##_cb(h); \
} \
} \
\
void uv__##name##_close(uv_##name##_t* handle) { \
uv_##name##_stop(handle); \
}
UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
UV_LOOP_WATCHER_DEFINE(check, CHECK)
UV_LOOP_WATCHER_DEFINE(idle, IDLE)

228
deps/libuv/src/unix/loop.c vendored Normal file
View File

@ -0,0 +1,228 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "uv/tree.h"
#include "internal.h"
#include "heap-inl.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int uv_loop_init(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
void* saved_data;
int err;
saved_data = loop->data;
memset(loop, 0, sizeof(*loop));
loop->data = saved_data;
lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
if (lfields == NULL)
return UV_ENOMEM;
loop->internal_fields = lfields;
err = uv_mutex_init(&lfields->loop_metrics.lock);
if (err)
goto fail_metrics_mutex_init;
heap_init((struct heap*) &loop->timer_heap);
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->idle_handles);
QUEUE_INIT(&loop->async_handles);
QUEUE_INIT(&loop->check_handles);
QUEUE_INIT(&loop->prepare_handles);
QUEUE_INIT(&loop->handle_queue);
loop->active_handles = 0;
loop->active_reqs.count = 0;
loop->nfds = 0;
loop->watchers = NULL;
loop->nwatchers = 0;
QUEUE_INIT(&loop->pending_queue);
QUEUE_INIT(&loop->watcher_queue);
loop->closing_handles = NULL;
uv__update_time(loop);
loop->async_io_watcher.fd = -1;
loop->async_wfd = -1;
loop->signal_pipefd[0] = -1;
loop->signal_pipefd[1] = -1;
loop->backend_fd = -1;
loop->emfile_fd = -1;
loop->timer_counter = 0;
loop->stop_flag = 0;
err = uv__platform_loop_init(loop);
if (err)
goto fail_platform_init;
uv__signal_global_once_init();
err = uv_signal_init(loop, &loop->child_watcher);
if (err)
goto fail_signal_init;
uv__handle_unref(&loop->child_watcher);
loop->child_watcher.flags |= UV_HANDLE_INTERNAL;
QUEUE_INIT(&loop->process_handles);
err = uv_rwlock_init(&loop->cloexec_lock);
if (err)
goto fail_rwlock_init;
err = uv_mutex_init(&loop->wq_mutex);
if (err)
goto fail_mutex_init;
err = uv_async_init(loop, &loop->wq_async, uv__work_done);
if (err)
goto fail_async_init;
uv__handle_unref(&loop->wq_async);
loop->wq_async.flags |= UV_HANDLE_INTERNAL;
return 0;
fail_async_init:
uv_mutex_destroy(&loop->wq_mutex);
fail_mutex_init:
uv_rwlock_destroy(&loop->cloexec_lock);
fail_rwlock_init:
uv__signal_loop_cleanup(loop);
fail_signal_init:
uv__platform_loop_delete(loop);
fail_platform_init:
uv_mutex_destroy(&lfields->loop_metrics.lock);
fail_metrics_mutex_init:
uv__free(lfields);
loop->internal_fields = NULL;
uv__free(loop->watchers);
loop->nwatchers = 0;
return err;
}
int uv_loop_fork(uv_loop_t* loop) {
int err;
unsigned int i;
uv__io_t* w;
err = uv__io_fork(loop);
if (err)
return err;
err = uv__async_fork(loop);
if (err)
return err;
err = uv__signal_loop_fork(loop);
if (err)
return err;
/* Rearm all the watchers that aren't re-queued by the above. */
for (i = 0; i < loop->nwatchers; i++) {
w = loop->watchers[i];
if (w == NULL)
continue;
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) {
w->events = 0; /* Force re-registration in uv__io_poll. */
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
}
}
return 0;
}
void uv__loop_close(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
uv__signal_loop_cleanup(loop);
uv__platform_loop_delete(loop);
uv__async_stop(loop);
if (loop->emfile_fd != -1) {
uv__close(loop->emfile_fd);
loop->emfile_fd = -1;
}
if (loop->backend_fd != -1) {
uv__close(loop->backend_fd);
loop->backend_fd = -1;
}
uv_mutex_lock(&loop->wq_mutex);
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
assert(!uv__has_active_reqs(loop));
uv_mutex_unlock(&loop->wq_mutex);
uv_mutex_destroy(&loop->wq_mutex);
/*
* Note that all thread pool stuff is finished at this point and
* it is safe to just destroy rw lock
*/
uv_rwlock_destroy(&loop->cloexec_lock);
#if 0
assert(QUEUE_EMPTY(&loop->pending_queue));
assert(QUEUE_EMPTY(&loop->watcher_queue));
assert(loop->nfds == 0);
#endif
uv__free(loop->watchers);
loop->watchers = NULL;
loop->nwatchers = 0;
lfields = uv__get_internal_fields(loop);
uv_mutex_destroy(&lfields->loop_metrics.lock);
uv__free(lfields);
loop->internal_fields = NULL;
}
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
uv__loop_internal_fields_t* lfields;
lfields = uv__get_internal_fields(loop);
if (option == UV_METRICS_IDLE_TIME) {
lfields->flags |= UV_METRICS_IDLE_TIME;
return 0;
}
if (option != UV_LOOP_BLOCK_SIGNAL)
return UV_ENOSYS;
if (va_arg(ap, int) != SIGPROF)
return UV_EINVAL;
loop->flags |= UV_LOOP_BLOCK_SIGPROF;
return 0;
}

259
deps/libuv/src/unix/netbsd.c vendored Normal file
View File

@ -0,0 +1,259 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <kvm.h>
#include <paths.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <uvm/uvm_extern.h>
#include <unistd.h>
#include <time.h>
int uv__platform_loop_init(uv_loop_t* loop) {
return uv__kqueue_init(loop);
}
void uv__platform_loop_delete(uv_loop_t* loop) {
}
void uv_loadavg(double avg[3]) {
struct loadavg info;
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_LOADAVG};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) == -1) return;
avg[0] = (double) info.ldavg[0] / info.fscale;
avg[1] = (double) info.ldavg[1] / info.fscale;
avg[2] = (double) info.ldavg[2] / info.fscale;
}
int uv_exepath(char* buffer, size_t* size) {
/* Intermediate buffer, retrieving partial path name does not work
* As of NetBSD-8(beta), vnode->path translator does not handle files
* with longer names than 31 characters.
*/
char int_buf[PATH_MAX];
size_t int_size;
int mib[4];
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = -1;
mib[3] = KERN_PROC_PATHNAME;
int_size = ARRAY_SIZE(int_buf);
if (sysctl(mib, 4, int_buf, &int_size, NULL, 0))
return UV__ERR(errno);
/* Copy string from the intermediate buffer to outer one with appropriate
* length.
*/
/* TODO(bnoordhuis) Check uv__strscpy() return value. */
uv__strscpy(buffer, int_buf, *size);
/* Set new size. */
*size = strlen(buffer);
return 0;
}
uint64_t uv_get_free_memory(void) {
struct uvmexp info;
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_UVMEXP};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
}
uint64_t uv_get_total_memory(void) {
#if defined(HW_PHYSMEM64)
uint64_t info;
int which[] = {CTL_HW, HW_PHYSMEM64};
#else
unsigned int info;
int which[] = {CTL_HW, HW_PHYSMEM};
#endif
size_t size = sizeof(info);
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return (uint64_t) info;
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}
int uv_resident_set_memory(size_t* rss) {
kvm_t *kd = NULL;
struct kinfo_proc2 *kinfo = NULL;
pid_t pid;
int nprocs;
int max_size = sizeof(struct kinfo_proc2);
int page_size;
page_size = getpagesize();
pid = getpid();
kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
if (kd == NULL) goto error;
kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
if (kinfo == NULL) goto error;
*rss = kinfo->p_vm_rssize * page_size;
kvm_close(kd);
return 0;
error:
if (kd) kvm_close(kd);
return UV_EPERM;
}
int uv_uptime(double* uptime) {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
now = time(NULL);
*uptime = (double)(now - info.tv_sec);
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
unsigned int multiplier = ((uint64_t)1000L / ticks);
unsigned int cur = 0;
uv_cpu_info_t* cpu_info;
u_int64_t* cp_times;
char model[512];
u_int64_t cpuspeed;
int numcpus;
size_t size;
int i;
size = sizeof(model);
if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
sysctlbyname("hw.model", &model, &size, NULL, 0)) {
return UV__ERR(errno);
}
size = sizeof(numcpus);
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
return UV__ERR(errno);
*count = numcpus;
/* Only i386 and amd64 have machdep.tsc_freq */
size = sizeof(cpuspeed);
if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
cpuspeed = 0;
size = numcpus * CPUSTATES * sizeof(*cp_times);
cp_times = uv__malloc(size);
if (cp_times == NULL)
return UV_ENOMEM;
if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
return UV__ERR(errno);
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
if (!(*cpu_infos)) {
uv__free(cp_times);
uv__free(*cpu_infos);
return UV_ENOMEM;
}
for (i = 0; i < numcpus; i++) {
cpu_info = &(*cpu_infos)[i];
cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
cpu_info->model = uv__strdup(model);
cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
cur += CPUSTATES;
}
uv__free(cp_times);
return 0;
}
int uv__random_sysctl(void* buf, size_t len) {
static int name[] = {CTL_KERN, KERN_ARND};
size_t count, req;
unsigned char* p;
p = buf;
while (len) {
req = len < 32 ? len : 32;
count = req;
if (sysctl(name, ARRAY_SIZE(name), p, &count, NULL, 0) == -1)
return UV__ERR(errno);
if (count != req)
return UV_EIO; /* Can't happen. */
p += count;
len -= count;
}
return 0;
}

42
deps/libuv/src/unix/no-fsevents.c vendored Normal file
View File

@ -0,0 +1,42 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <errno.h>
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
return UV_ENOSYS;
}
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
const char* filename, unsigned int flags) {
return UV_ENOSYS;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
return UV_ENOSYS;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
UNREACHABLE();
}

45
deps/libuv/src/unix/no-proctitle.c vendored Normal file
View File

@ -0,0 +1,45 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <errno.h>
#include <stddef.h>
char** uv_setup_args(int argc, char** argv) {
return argv;
}
void uv__process_title_cleanup(void) {
}
int uv_set_process_title(const char* title) {
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return UV_EINVAL;
buffer[0] = '\0';
return 0;
}

240
deps/libuv/src/unix/openbsd.c vendored Normal file
View File

@ -0,0 +1,240 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/sched.h>
#include <sys/time.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int uv__platform_loop_init(uv_loop_t* loop) {
return uv__kqueue_init(loop);
}
void uv__platform_loop_delete(uv_loop_t* loop) {
}
void uv_loadavg(double avg[3]) {
struct loadavg info;
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_LOADAVG};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
avg[0] = (double) info.ldavg[0] / info.fscale;
avg[1] = (double) info.ldavg[1] / info.fscale;
avg[2] = (double) info.ldavg[2] / info.fscale;
}
int uv_exepath(char* buffer, size_t* size) {
int mib[4];
char **argsbuf = NULL;
size_t argsbuf_size = 100U;
size_t exepath_size;
pid_t mypid;
int err;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
mypid = getpid();
for (;;) {
err = UV_ENOMEM;
argsbuf = uv__reallocf(argsbuf, argsbuf_size);
if (argsbuf == NULL)
goto out;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = mypid;
mib[3] = KERN_PROC_ARGV;
if (sysctl(mib, ARRAY_SIZE(mib), argsbuf, &argsbuf_size, NULL, 0) == 0) {
break;
}
if (errno != ENOMEM) {
err = UV__ERR(errno);
goto out;
}
argsbuf_size *= 2U;
}
if (argsbuf[0] == NULL) {
err = UV_EINVAL; /* FIXME(bnoordhuis) More appropriate error. */
goto out;
}
*size -= 1;
exepath_size = strlen(argsbuf[0]);
if (*size > exepath_size)
*size = exepath_size;
memcpy(buffer, argsbuf[0], *size);
buffer[*size] = '\0';
err = 0;
out:
uv__free(argsbuf);
return err;
}
uint64_t uv_get_free_memory(void) {
struct uvmexp info;
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_UVMEXP};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
}
uint64_t uv_get_total_memory(void) {
uint64_t info;
int which[] = {CTL_HW, HW_PHYSMEM64};
size_t size = sizeof(info);
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return (uint64_t) info;
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}
int uv_resident_set_memory(size_t* rss) {
struct kinfo_proc kinfo;
size_t page_size = getpagesize();
size_t size = sizeof(struct kinfo_proc);
int mib[6];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
mib[4] = sizeof(struct kinfo_proc);
mib[5] = 1;
if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &size, NULL, 0) < 0)
return UV__ERR(errno);
*rss = kinfo.p_vm_rssize * page_size;
return 0;
}
int uv_uptime(double* uptime) {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
now = time(NULL);
*uptime = (double)(now - info.tv_sec);
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed;
uint64_t info[CPUSTATES];
char model[512];
int numcpus = 1;
int which[] = {CTL_HW,HW_MODEL};
int percpu[] = {CTL_KERN,KERN_CPTIME2,0};
size_t size;
int i, j;
uv_cpu_info_t* cpu_info;
size = sizeof(model);
if (sysctl(which, ARRAY_SIZE(which), &model, &size, NULL, 0))
return UV__ERR(errno);
which[1] = HW_NCPUONLINE;
size = sizeof(numcpus);
if (sysctl(which, ARRAY_SIZE(which), &numcpus, &size, NULL, 0))
return UV__ERR(errno);
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
if (!(*cpu_infos))
return UV_ENOMEM;
i = 0;
*count = numcpus;
which[1] = HW_CPUSPEED;
size = sizeof(cpuspeed);
if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0))
goto error;
size = sizeof(info);
for (i = 0; i < numcpus; i++) {
percpu[2] = i;
if (sysctl(percpu, ARRAY_SIZE(percpu), &info, &size, NULL, 0))
goto error;
cpu_info = &(*cpu_infos)[i];
cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier;
cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier;
cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier;
cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier;
cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier;
cpu_info->model = uv__strdup(model);
cpu_info->speed = cpuspeed;
}
return 0;
error:
*count = 0;
for (j = 0; j < i; j++)
uv__free((*cpu_infos)[j].model);
uv__free(*cpu_infos);
*cpu_infos = NULL;
return UV__ERR(errno);
}

584
deps/libuv/src/unix/os390-syscalls.c vendored Normal file
View File

@ -0,0 +1,584 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "os390-syscalls.h"
#include <errno.h>
#include <stdlib.h>
#include <search.h>
#include <termios.h>
#include <sys/msg.h>
#define CW_INTRPT 1
#define CW_CONDVAR 32
#pragma linkage(BPX4CTW, OS)
#pragma linkage(BPX1CTW, OS)
static QUEUE global_epoll_queue;
static uv_mutex_t global_epoll_lock;
static uv_once_t once = UV_ONCE_INIT;
int scandir(const char* maindir, struct dirent*** namelist,
int (*filter)(const struct dirent*),
int (*compar)(const struct dirent**,
const struct dirent **)) {
struct dirent** nl;
struct dirent** nl_copy;
struct dirent* dirent;
unsigned count;
size_t allocated;
DIR* mdir;
nl = NULL;
count = 0;
allocated = 0;
mdir = opendir(maindir);
if (!mdir)
return -1;
while (1) {
dirent = readdir(mdir);
if (!dirent)
break;
if (!filter || filter(dirent)) {
struct dirent* copy;
copy = uv__malloc(sizeof(*copy));
if (!copy)
goto error;
memcpy(copy, dirent, sizeof(*copy));
nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1));
if (nl_copy == NULL) {
uv__free(copy);
goto error;
}
nl = nl_copy;
nl[count++] = copy;
}
}
qsort(nl, count, sizeof(struct dirent *),
(int (*)(const void *, const void *)) compar);
closedir(mdir);
*namelist = nl;
return count;
error:
while (count > 0) {
dirent = nl[--count];
uv__free(dirent);
}
uv__free(nl);
closedir(mdir);
errno = ENOMEM;
return -1;
}
static unsigned int next_power_of_two(unsigned int val) {
val -= 1;
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
val += 1;
return val;
}
static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
unsigned int newsize;
unsigned int i;
struct pollfd* newlst;
struct pollfd event;
if (len <= lst->size)
return;
if (lst->size == 0)
event.fd = -1;
else {
/* Extract the message queue at the end. */
event = lst->items[lst->size - 1];
lst->items[lst->size - 1].fd = -1;
}
newsize = next_power_of_two(len);
newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0]));
if (newlst == NULL)
abort();
for (i = lst->size; i < newsize; ++i)
newlst[i].fd = -1;
/* Restore the message queue at the end */
newlst[newsize - 1] = event;
lst->items = newlst;
lst->size = newsize;
}
static void init_message_queue(uv__os390_epoll* lst) {
struct {
long int header;
char body;
} msg;
/* initialize message queue */
lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT);
if (lst->msg_queue == -1)
abort();
/*
On z/OS, the message queue will be affiliated with the process only
when a send is performed on it. Once this is done, the system
can be queried for all message queues belonging to our process id.
*/
msg.header = 1;
if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0)
abort();
/* Clean up the dummy message sent above */
if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body))
abort();
}
static void before_fork(void) {
uv_mutex_lock(&global_epoll_lock);
}
static void after_fork(void) {
uv_mutex_unlock(&global_epoll_lock);
}
static void child_fork(void) {
QUEUE* q;
uv_once_t child_once = UV_ONCE_INIT;
/* reset once */
memcpy(&once, &child_once, sizeof(child_once));
/* reset epoll list */
while (!QUEUE_EMPTY(&global_epoll_queue)) {
uv__os390_epoll* lst;
q = QUEUE_HEAD(&global_epoll_queue);
QUEUE_REMOVE(q);
lst = QUEUE_DATA(q, uv__os390_epoll, member);
uv__free(lst->items);
lst->items = NULL;
lst->size = 0;
}
uv_mutex_unlock(&global_epoll_lock);
uv_mutex_destroy(&global_epoll_lock);
}
static void epoll_init(void) {
QUEUE_INIT(&global_epoll_queue);
if (uv_mutex_init(&global_epoll_lock))
abort();
if (pthread_atfork(&before_fork, &after_fork, &child_fork))
abort();
}
uv__os390_epoll* epoll_create1(int flags) {
uv__os390_epoll* lst;
lst = uv__malloc(sizeof(*lst));
if (lst != NULL) {
/* initialize list */
lst->size = 0;
lst->items = NULL;
init_message_queue(lst);
maybe_resize(lst, 1);
lst->items[lst->size - 1].fd = lst->msg_queue;
lst->items[lst->size - 1].events = POLLIN;
lst->items[lst->size - 1].revents = 0;
uv_once(&once, epoll_init);
uv_mutex_lock(&global_epoll_lock);
QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
uv_mutex_unlock(&global_epoll_lock);
}
return lst;
}
int epoll_ctl(uv__os390_epoll* lst,
int op,
int fd,
struct epoll_event *event) {
uv_mutex_lock(&global_epoll_lock);
if (op == EPOLL_CTL_DEL) {
if (fd >= lst->size || lst->items[fd].fd == -1) {
uv_mutex_unlock(&global_epoll_lock);
errno = ENOENT;
return -1;
}
lst->items[fd].fd = -1;
} else if (op == EPOLL_CTL_ADD) {
/* Resizing to 'fd + 1' would expand the list to contain at least
* 'fd'. But we need to guarantee that the last index on the list
* is reserved for the message queue. So specify 'fd + 2' instead.
*/
maybe_resize(lst, fd + 2);
if (lst->items[fd].fd != -1) {
uv_mutex_unlock(&global_epoll_lock);
errno = EEXIST;
return -1;
}
lst->items[fd].fd = fd;
lst->items[fd].events = event->events;
lst->items[fd].revents = 0;
} else if (op == EPOLL_CTL_MOD) {
if (fd >= lst->size - 1 || lst->items[fd].fd == -1) {
uv_mutex_unlock(&global_epoll_lock);
errno = ENOENT;
return -1;
}
lst->items[fd].events = event->events;
lst->items[fd].revents = 0;
} else
abort();
uv_mutex_unlock(&global_epoll_lock);
return 0;
}
#define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd))
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
int maxevents, int timeout) {
nmsgsfds_t size;
struct pollfd* pfds;
int pollret;
int reventcount;
int nevents;
struct pollfd msg_fd;
int i;
if (!lst || !lst->items || !events) {
errno = EFAULT;
return -1;
}
if (lst->size > EP_MAX_PFDS) {
errno = EINVAL;
return -1;
}
if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) {
errno = EINVAL;
return -1;
}
if (lst->size > 0)
_SET_FDS_MSGS(size, 1, lst->size - 1);
else
_SET_FDS_MSGS(size, 0, 0);
pfds = lst->items;
pollret = poll(pfds, size, timeout);
if (pollret <= 0)
return pollret;
assert(lst->size > 0);
pollret = _NFDS(pollret) + _NMSGS(pollret);
reventcount = 0;
nevents = 0;
msg_fd = pfds[lst->size - 1];
for (i = 0;
i < lst->size && i < maxevents && reventcount < pollret; ++i) {
struct epoll_event ev;
struct pollfd* pfd;
pfd = &pfds[i];
if (pfd->fd == -1 || pfd->revents == 0)
continue;
ev.fd = pfd->fd;
ev.events = pfd->revents;
ev.is_msg = 0;
if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
reventcount += 2;
else if (pfd->revents & (POLLIN | POLLOUT))
++reventcount;
pfd->revents = 0;
events[nevents++] = ev;
}
if (msg_fd.revents != 0 && msg_fd.fd != -1)
if (i == lst->size)
events[nevents - 1].is_msg = 1;
return nevents;
}
int epoll_file_close(int fd) {
QUEUE* q;
uv_once(&once, epoll_init);
uv_mutex_lock(&global_epoll_lock);
QUEUE_FOREACH(q, &global_epoll_queue) {
uv__os390_epoll* lst;
lst = QUEUE_DATA(q, uv__os390_epoll, member);
if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
lst->items[fd].fd = -1;
}
uv_mutex_unlock(&global_epoll_lock);
return 0;
}
void epoll_queue_close(uv__os390_epoll* lst) {
/* Remove epoll instance from global queue */
uv_mutex_lock(&global_epoll_lock);
QUEUE_REMOVE(&lst->member);
uv_mutex_unlock(&global_epoll_lock);
/* Free resources */
msgctl(lst->msg_queue, IPC_RMID, NULL);
lst->msg_queue = -1;
uv__free(lst->items);
lst->items = NULL;
}
int nanosleep(const struct timespec* req, struct timespec* rem) {
unsigned nano;
unsigned seconds;
unsigned events;
unsigned secrem;
unsigned nanorem;
int rv;
int err;
int rsn;
nano = (int)req->tv_nsec;
seconds = req->tv_sec;
events = CW_CONDVAR | CW_INTRPT;
secrem = 0;
nanorem = 0;
#if defined(_LP64)
BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
#else
BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
#endif
/* Don't clobber errno unless BPX1CTW/BPX4CTW errored.
* Don't leak EAGAIN, that just means the timeout expired.
*/
if (rv == -1)
if (err == EAGAIN)
rv = 0;
else
errno = err;
if (rem != NULL && (rv == 0 || err == EINTR)) {
rem->tv_nsec = nanorem;
rem->tv_sec = secrem;
}
return rv;
}
char* mkdtemp(char* path) {
static const char* tempchars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static const size_t num_chars = 62;
static const size_t num_x = 6;
char *ep, *cp;
unsigned int tries, i;
size_t len;
uint64_t v;
int fd;
int retval;
int saved_errno;
len = strlen(path);
ep = path + len;
if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {
errno = EINVAL;
return NULL;
}
fd = open("/dev/urandom", O_RDONLY);
if (fd == -1)
return NULL;
tries = TMP_MAX;
retval = -1;
do {
if (read(fd, &v, sizeof(v)) != sizeof(v))
break;
cp = ep - num_x;
for (i = 0; i < num_x; i++) {
*cp++ = tempchars[v % num_chars];
v /= num_chars;
}
if (mkdir(path, S_IRWXU) == 0) {
retval = 0;
break;
}
else if (errno != EEXIST)
break;
} while (--tries);
saved_errno = errno;
uv__close(fd);
if (tries == 0) {
errno = EEXIST;
return NULL;
}
if (retval == -1) {
errno = saved_errno;
return NULL;
}
return path;
}
ssize_t os390_readlink(const char* path, char* buf, size_t len) {
ssize_t rlen;
ssize_t vlen;
ssize_t plen;
char* delimiter;
char old_delim;
char* tmpbuf;
char realpathstr[PATH_MAX + 1];
tmpbuf = uv__malloc(len + 1);
if (tmpbuf == NULL) {
errno = ENOMEM;
return -1;
}
rlen = readlink(path, tmpbuf, len);
if (rlen < 0) {
uv__free(tmpbuf);
return rlen;
}
if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {
/* Straightforward readlink. */
memcpy(buf, tmpbuf, rlen);
uv__free(tmpbuf);
return rlen;
}
/*
* There is a parmlib variable at the beginning
* which needs interpretation.
*/
tmpbuf[rlen] = '\0';
delimiter = strchr(tmpbuf + 2, '/');
if (delimiter == NULL)
/* No slash at the end */
delimiter = strchr(tmpbuf + 2, '\0');
/* Read real path of the variable. */
old_delim = *delimiter;
*delimiter = '\0';
if (realpath(tmpbuf, realpathstr) == NULL) {
uv__free(tmpbuf);
return -1;
}
/* realpathstr is not guaranteed to end with null byte.*/
realpathstr[PATH_MAX] = '\0';
/* Reset the delimiter and fill up the buffer. */
*delimiter = old_delim;
plen = strlen(delimiter);
vlen = strlen(realpathstr);
rlen = plen + vlen;
if (rlen > len) {
uv__free(tmpbuf);
errno = ENAMETOOLONG;
return -1;
}
memcpy(buf, realpathstr, vlen);
memcpy(buf + vlen, delimiter, plen);
/* Done using temporary buffer. */
uv__free(tmpbuf);
return rlen;
}
size_t strnlen(const char* str, size_t maxlen) {
char* p = memchr(str, 0, maxlen);
if (p == NULL)
return maxlen;
else
return p - str;
}
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
UNREACHABLE();
}
int sem_destroy(UV_PLATFORM_SEM_T* semid) {
UNREACHABLE();
}
int sem_post(UV_PLATFORM_SEM_T* semid) {
UNREACHABLE();
}
int sem_trywait(UV_PLATFORM_SEM_T* semid) {
UNREACHABLE();
}
int sem_wait(UV_PLATFORM_SEM_T* semid) {
UNREACHABLE();
}

74
deps/libuv/src/unix/os390-syscalls.h vendored Normal file
View File

@ -0,0 +1,74 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_OS390_SYSCALL_H_
#define UV_OS390_SYSCALL_H_
#include "uv.h"
#include "internal.h"
#include <dirent.h>
#include <poll.h>
#include <pthread.h>
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
#define EPOLL_CTL_MOD 3
#define MAX_EPOLL_INSTANCES 256
#define MAX_ITEMS_PER_EPOLL 1024
#define UV__O_CLOEXEC 0x80000
struct epoll_event {
int events;
int fd;
int is_msg;
};
typedef struct {
QUEUE member;
struct pollfd* items;
unsigned long size;
int msg_queue;
} uv__os390_epoll;
/* epoll api */
uv__os390_epoll* epoll_create1(int flags);
int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event);
int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout);
int epoll_file_close(int fd);
/* utility functions */
int nanosleep(const struct timespec* req, struct timespec* rem);
int scandir(const char* maindir, struct dirent*** namelist,
int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **,
const struct dirent **));
char *mkdtemp(char* path);
ssize_t os390_readlink(const char* path, char* buf, size_t len);
size_t strnlen(const char* str, size_t maxlen);
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value);
int sem_destroy(UV_PLATFORM_SEM_T* semid);
int sem_post(UV_PLATFORM_SEM_T* semid);
int sem_trywait(UV_PLATFORM_SEM_T* semid);
int sem_wait(UV_PLATFORM_SEM_T* semid);
#endif /* UV_OS390_SYSCALL_H_ */

975
deps/libuv/src/unix/os390.c vendored Normal file
View File

@ -0,0 +1,975 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "internal.h"
#include <sys/ioctl.h>
#include <net/if.h>
#include <utmpx.h>
#include <unistd.h>
#include <sys/ps.h>
#include <builtins.h>
#include <termios.h>
#include <sys/msg.h>
#if defined(__clang__)
#include "csrsic.h"
#else
#include "//'SYS1.SAMPLIB(CSRSIC)'"
#endif
#define CVT_PTR 0x10
#define PSA_PTR 0x00
#define CSD_OFFSET 0x294
/*
Long-term average CPU service used by this logical partition,
in millions of service units per hour. If this value is above
the partition's defined capacity, the partition will be capped.
It is calculated using the physical CPU adjustment factor
(RCTPCPUA) so it may not match other measures of service which
are based on the logical CPU adjustment factor. It is available
if the hardware supports LPAR cluster.
*/
#define RCTLACS_OFFSET 0xC4
/* 32-bit count of alive CPUs. This includes both CPs and IFAs */
#define CSD_NUMBER_ONLINE_CPUS 0xD4
/* Address of system resources manager (SRM) control table */
#define CVTOPCTP_OFFSET 0x25C
/* Address of the RCT table */
#define RMCTRCT_OFFSET 0xE4
/* Address of the rsm control and enumeration area. */
#define CVTRCEP_OFFSET 0x490
/*
Number of frames currently available to system.
Excluded are frames backing perm storage, frames offline, and bad frames.
*/
#define RCEPOOL_OFFSET 0x004
/* Total number of frames currently on all available frame queues. */
#define RCEAFC_OFFSET 0x088
/* CPC model length from the CSRSI Service. */
#define CPCMODEL_LENGTH 16
/* Pointer to the home (current) ASCB. */
#define PSAAOLD 0x224
/* Pointer to rsm address space block extension. */
#define ASCBRSME 0x16C
/*
NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE.
It does not include 2G frames.
*/
#define RAXFMCT 0x2C
/* Thread Entry constants */
#define PGTH_CURRENT 1
#define PGTH_LEN 26
#define PGTHAPATH 0x20
#pragma linkage(BPX4GTH, OS)
#pragma linkage(BPX1GTH, OS)
/* TOD Clock resolution in nanoseconds */
#define TOD_RES 4.096
typedef unsigned data_area_ptr_assign_type;
typedef union {
struct {
#if defined(_LP64)
data_area_ptr_assign_type lower;
#endif
data_area_ptr_assign_type assign;
};
char* deref;
} data_area_ptr;
void uv_loadavg(double avg[3]) {
/* TODO: implement the following */
avg[0] = 0;
avg[1] = 0;
avg[2] = 0;
}
int uv__platform_loop_init(uv_loop_t* loop) {
uv__os390_epoll* ep;
ep = epoll_create1(0);
loop->ep = ep;
if (ep == NULL)
return UV__ERR(errno);
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->ep != NULL) {
epoll_queue_close(loop->ep);
loop->ep = NULL;
}
}
uint64_t uv__hrtime(uv_clocktype_t type) {
unsigned long long timestamp;
__stckf(&timestamp);
/* Convert to nanoseconds */
return timestamp / TOD_RES;
}
/*
Get the exe path using the thread entry information
in the address space.
*/
static int getexe(const int pid, char* buf, size_t len) {
struct {
int pid;
int thid[2];
char accesspid;
char accessthid;
char asid[2];
char loginname[8];
char flag;
char len;
} Input_data;
union {
struct {
char gthb[4];
int pid;
int thid[2];
char accesspid;
char accessthid[3];
int lenused;
int offsetProcess;
int offsetConTTY;
int offsetPath;
int offsetCommand;
int offsetFileData;
int offsetThread;
} Output_data;
char buf[2048];
} Output_buf;
struct Output_path_type {
char gthe[4];
short int len;
char path[1024];
};
int Input_length;
int Output_length;
void* Input_address;
void* Output_address;
struct Output_path_type* Output_path;
int rv;
int rc;
int rsn;
Input_length = PGTH_LEN;
Output_length = sizeof(Output_buf);
Output_address = &Output_buf;
Input_address = &Input_data;
memset(&Input_data, 0, sizeof Input_data);
Input_data.flag |= PGTHAPATH;
Input_data.pid = pid;
Input_data.accesspid = PGTH_CURRENT;
#ifdef _LP64
BPX4GTH(&Input_length,
&Input_address,
&Output_length,
&Output_address,
&rv,
&rc,
&rsn);
#else
BPX1GTH(&Input_length,
&Input_address,
&Output_length,
&Output_address,
&rv,
&rc,
&rsn);
#endif
if (rv == -1) {
errno = rc;
return -1;
}
/* Check highest byte to ensure data availability */
assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
/* Get the offset from the lowest 3 bytes */
Output_path = (struct Output_path_type*) ((char*) (&Output_buf) +
(Output_buf.Output_data.offsetPath & 0x00FFFFFF));
if (Output_path->len >= len) {
errno = ENOBUFS;
return -1;
}
uv__strscpy(buf, Output_path->path, len);
return 0;
}
/*
* We could use a static buffer for the path manipulations that we need outside
* of the function, but this function could be called by multiple consumers and
* we don't want to potentially create a race condition in the use of snprintf.
* There is no direct way of getting the exe path in zOS - either through /procfs
* or through some libc APIs. The below approach is to parse the argv[0]'s pattern
* and use it in conjunction with PATH environment variable to craft one.
*/
int uv_exepath(char* buffer, size_t* size) {
int res;
char args[PATH_MAX];
int pid;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
pid = getpid();
res = getexe(pid, args, sizeof(args));
if (res < 0)
return UV_EINVAL;
return uv__search_path(args, buffer, size);
}
uint64_t uv_get_free_memory(void) {
uint64_t freeram;
data_area_ptr cvt = {0};
data_area_ptr rcep = {0};
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4;
return freeram;
}
uint64_t uv_get_total_memory(void) {
uint64_t totalram;
data_area_ptr cvt = {0};
data_area_ptr rcep = {0};
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4;
return totalram;
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}
int uv_resident_set_memory(size_t* rss) {
char* ascb;
char* rax;
size_t nframes;
ascb = *(char* __ptr32 *)(PSA_PTR + PSAAOLD);
rax = *(char* __ptr32 *)(ascb + ASCBRSME);
nframes = *(unsigned int*)(rax + RAXFMCT);
*rss = nframes * sysconf(_SC_PAGESIZE);
return 0;
}
int uv_uptime(double* uptime) {
struct utmpx u ;
struct utmpx *v;
time64_t t;
u.ut_type = BOOT_TIME;
v = getutxid(&u);
if (v == NULL)
return -1;
*uptime = difftime64(time64(&t), v->ut_tv.tv_sec);
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
int idx;
siv1v2 info;
data_area_ptr cvt = {0};
data_area_ptr csd = {0};
data_area_ptr rmctrct = {0};
data_area_ptr cvtopctp = {0};
int cpu_usage_avg;
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET));
cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET));
rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET));
*count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS));
cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET));
*cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t));
if (!*cpu_infos)
return UV_ENOMEM;
cpu_info = *cpu_infos;
idx = 0;
while (idx < *count) {
cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability);
cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1);
memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1);
memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH);
cpu_info->cpu_times.user = cpu_usage_avg;
/* TODO: implement the following */
cpu_info->cpu_times.sys = 0;
cpu_info->cpu_times.idle = 0;
cpu_info->cpu_times.irq = 0;
cpu_info->cpu_times.nice = 0;
++cpu_info;
++idx;
}
return 0;
}
static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
int* count) {
uv_interface_address_t* address;
int sockfd;
int maxsize;
__net_ifconf6header_t ifc;
__net_ifconf6entry_t* ifr;
__net_ifconf6entry_t* p;
__net_ifconf6entry_t flg;
*count = 0;
/* Assume maximum buffer size allowable */
maxsize = 16384;
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
return UV__ERR(errno);
ifc.__nif6h_version = 1;
ifc.__nif6h_buflen = maxsize;
ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
uv__close(sockfd);
return UV__ERR(errno);
}
*count = 0;
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
p->__nif6e_addr.sin6_family == AF_INET))
continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
continue;
++(*count);
}
/* Alloc the return interface structs */
*addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
if (!(*addresses)) {
uv__close(sockfd);
return UV_ENOMEM;
}
address = *addresses;
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
p->__nif6e_addr.sin6_family == AF_INET))
continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
continue;
/* All conditions above must match count loop */
address->name = uv__strdup(p->__nif6e_name);
if (p->__nif6e_addr.sin6_family == AF_INET6)
address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
else
address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr);
/* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
memset(address->phys_addr, 0, sizeof(address->phys_addr));
address++;
}
uv__close(sockfd);
return 0;
}
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
int sockfd;
int maxsize;
struct ifconf ifc;
struct ifreq flg;
struct ifreq* ifr;
struct ifreq* p;
int count_v6;
*count = 0;
*addresses = NULL;
/* get the ipv6 addresses first */
uv_interface_address_t* addresses_v6;
uv__interface_addresses_v6(&addresses_v6, &count_v6);
/* now get the ipv4 addresses */
/* Assume maximum buffer size allowable */
maxsize = 16384;
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (0 > sockfd)
return UV__ERR(errno);
ifc.ifc_req = uv__calloc(1, maxsize);
ifc.ifc_len = maxsize;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
uv__close(sockfd);
return UV__ERR(errno);
}
#define MAX(a,b) (((a)>(b))?(a):(b))
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
/* Count all up and running ipv4/ipv6 addresses */
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv__close(sockfd);
return UV__ERR(errno);
}
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
(*count)++;
}
if (*count == 0) {
uv__close(sockfd);
return 0;
}
/* Alloc the return interface structs */
*addresses = uv__malloc((*count + count_v6) *
sizeof(uv_interface_address_t));
if (!(*addresses)) {
uv__close(sockfd);
return UV_ENOMEM;
}
address = *addresses;
/* copy over the ipv6 addresses */
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
address += count_v6;
*count += count_v6;
uv__free(addresses_v6);
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv__close(sockfd);
return UV_ENOSYS;
}
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
/* All conditions above must match count loop */
address->name = uv__strdup(p->ifr_name);
if (p->ifr_addr.sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
} else {
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
}
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
memset(address->phys_addr, 0, sizeof(address->phys_addr));
address++;
}
#undef ADDR_SIZE
#undef MAX
uv__close(sockfd);
return 0;
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; ++i)
uv__free(addresses[i].name);
uv__free(addresses);
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct epoll_event* events;
struct epoll_event dummy;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
assert(fd >= 0);
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events != NULL)
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].fd == fd)
events[i].fd = -1;
/* Remove the file descriptor from the epoll. */
if (loop->ep != NULL)
epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, &dummy);
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct pollfd p[1];
int rv;
p[0].fd = fd;
p[0].events = POLLIN;
do
rv = poll(p, 1, 0);
while (rv == -1 && errno == EINTR);
if (rv == -1)
abort();
if (p[0].revents & POLLNVAL)
return -1;
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
}
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
const char* filename, unsigned int flags) {
uv__os390_epoll* ep;
_RFIS reg_struct;
char* path;
int rc;
if (uv__is_active(handle))
return UV_EINVAL;
ep = handle->loop->ep;
assert(ep->msg_queue != -1);
reg_struct.__rfis_cmd = _RFIS_REG;
reg_struct.__rfis_qid = ep->msg_queue;
reg_struct.__rfis_type = 1;
memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
path = uv__strdup(filename);
if (path == NULL)
return UV_ENOMEM;
rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
if (rc != 0)
return UV__ERR(errno);
uv__handle_start(handle);
handle->path = path;
handle->cb = cb;
memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
sizeof(handle->rfis_rftok));
return 0;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
uv__os390_epoll* ep;
_RFIS reg_struct;
int rc;
if (!uv__is_active(handle))
return 0;
ep = handle->loop->ep;
assert(ep->msg_queue != -1);
reg_struct.__rfis_cmd = _RFIS_UNREG;
reg_struct.__rfis_qid = ep->msg_queue;
reg_struct.__rfis_type = 1;
memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
sizeof(handle->rfis_rftok));
/*
* This call will take "/" as the path argument in case we
* don't care to supply the correct path. The system will simply
* ignore it.
*/
rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
if (rc != 0 && errno != EALREADY && errno != ENOENT)
abort();
uv__handle_stop(handle);
return 0;
}
static int os390_message_queue_handler(uv__os390_epoll* ep) {
uv_fs_event_t* handle;
int msglen;
int events;
_RFIM msg;
if (ep->msg_queue == -1)
return 0;
msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT);
if (msglen == -1 && errno == ENOMSG)
return 0;
if (msglen == -1)
abort();
events = 0;
if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
events = UV_CHANGE;
else if (msg.__rfim_event == _RFIM_RENAME)
events = UV_RENAME;
else
/* Some event that we are not interested in. */
return 0;
handle = *(uv_fs_event_t**)(msg.__rfim_utok);
handle->cb(handle, uv__basename_r(handle->path), events, 0);
return 1;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
static const int max_safe_timeout = 1789569;
struct epoll_event events[1024];
struct epoll_event* pe;
struct epoll_event e;
uv__os390_epoll* ep;
int real_timeout;
QUEUE* q;
uv__io_t* w;
uint64_t base;
int count;
int nfds;
int fd;
int op;
int i;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
uv_stream_t* stream;
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
stream= container_of(w, uv_stream_t, io_watcher);
assert(w->fd < (int) loop->nwatchers);
e.events = w->pevents;
e.fd = w->fd;
if (w->events == 0)
op = EPOLL_CTL_ADD;
else
op = EPOLL_CTL_MOD;
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
* events, skip the syscall and squelch the events after epoll_wait().
*/
if (epoll_ctl(loop->ep, op, w->fd, &e)) {
if (errno != EEXIST)
abort();
assert(op == EPOLL_CTL_ADD);
/* We've reactivated a file descriptor that's been watched before. */
if (epoll_ctl(loop->ep, EPOLL_CTL_MOD, w->fd, &e))
abort();
}
w->events = w->pevents;
}
assert(timeout >= -1);
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
real_timeout = timeout;
int nevents = 0;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
nfds = 0;
for (;;) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
timeout = max_safe_timeout;
nfds = epoll_wait(loop->ep, events,
ARRAY_SIZE(events), timeout);
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
base = loop->time;
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
assert(timeout != -1);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* We may have been inside the system call for longer than |timeout|
* milliseconds so we need to update the timestamp to avoid drift.
*/
goto update_timeout;
}
if (nfds == -1) {
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
}
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->fd;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
ep = loop->ep;
if (pe->is_msg) {
os390_message_queue_handler(ep);
continue;
}
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
w = loop->watchers[fd];
if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it.
*
* Ignore all errors because we may be racing with another thread
* when the file descriptor is closed.
*/
epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, pe);
continue;
}
/* Give users only events they're interested in. Prevents spurious
* callbacks when previous callback invocation in this loop has stopped
* the current watcher. Also, filters out events that users has not
* requested us to watch.
*/
pe->events &= w->pevents | POLLERR | POLLHUP;
if (pe->events == POLLERR || pe->events == POLLHUP)
pe->events |= w->pevents & (POLLIN | POLLOUT);
if (pe->events != 0) {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->events);
nevents++;
}
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
timeout = 0;
continue;
}
return;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
real_timeout -= (loop->time - base);
if (real_timeout <= 0)
return;
timeout = real_timeout;
}
}
void uv__set_process_title(const char* title) {
/* do nothing */
}
int uv__io_fork(uv_loop_t* loop) {
/*
Nullify the msg queue but don't close it because
it is still being used by the parent.
*/
loop->ep = NULL;
uv__platform_loop_delete(loop);
return uv__platform_loop_init(loop);
}

381
deps/libuv/src/unix/pipe.c vendored Normal file
View File

@ -0,0 +1,381 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
handle->shutdown_req = NULL;
handle->connect_req = NULL;
handle->pipe_fname = NULL;
handle->ipc = ipc;
return 0;
}
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
struct sockaddr_un saddr;
const char* pipe_fname;
int sockfd;
int err;
pipe_fname = NULL;
/* Already bound? */
if (uv__stream_fd(handle) >= 0)
return UV_EINVAL;
/* Make a copy of the file name, it outlives this function's scope. */
pipe_fname = uv__strdup(name);
if (pipe_fname == NULL)
return UV_ENOMEM;
/* We've got a copy, don't touch the original any more. */
name = NULL;
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
if (err < 0)
goto err_socket;
sockfd = err;
memset(&saddr, 0, sizeof saddr);
uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
saddr.sun_family = AF_UNIX;
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
err = UV__ERR(errno);
/* Convert ENOENT to EACCES for compatibility with Windows. */
if (err == UV_ENOENT)
err = UV_EACCES;
uv__close(sockfd);
goto err_socket;
}
/* Success. */
handle->flags |= UV_HANDLE_BOUND;
handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
handle->io_watcher.fd = sockfd;
return 0;
err_socket:
uv__free((void*)pipe_fname);
return err;
}
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
if (uv__stream_fd(handle) == -1)
return UV_EINVAL;
if (handle->ipc)
return UV_EINVAL;
#if defined(__MVS__) || defined(__PASE__)
/* On zOS, backlog=0 has undefined behaviour */
/* On IBMi PASE, backlog=0 leads to "Connection refused" error */
if (backlog == 0)
backlog = 1;
else if (backlog < 0)
backlog = SOMAXCONN;
#endif
if (listen(uv__stream_fd(handle), backlog))
return UV__ERR(errno);
handle->connection_cb = cb;
handle->io_watcher.cb = uv__server_io;
uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
return 0;
}
void uv__pipe_close(uv_pipe_t* handle) {
if (handle->pipe_fname) {
/*
* Unlink the file system entity before closing the file descriptor.
* Doing it the other way around introduces a race where our process
* unlinks a socket with the same name that's just been created by
* another thread or process.
*/
unlink(handle->pipe_fname);
uv__free((void*)handle->pipe_fname);
handle->pipe_fname = NULL;
}
uv__stream_close((uv_stream_t*)handle);
}
int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
int flags;
int mode;
int err;
flags = 0;
if (uv__fd_exists(handle->loop, fd))
return UV_EEXIST;
do
mode = fcntl(fd, F_GETFL);
while (mode == -1 && errno == EINTR);
if (mode == -1)
return UV__ERR(errno); /* according to docs, must be EBADF */
err = uv__nonblock(fd, 1);
if (err)
return err;
#if defined(__APPLE__)
err = uv__stream_try_select((uv_stream_t*) handle, &fd);
if (err)
return err;
#endif /* defined(__APPLE__) */
mode &= O_ACCMODE;
if (mode != O_WRONLY)
flags |= UV_HANDLE_READABLE;
if (mode != O_RDONLY)
flags |= UV_HANDLE_WRITABLE;
return uv__stream_open((uv_stream_t*)handle, fd, flags);
}
void uv_pipe_connect(uv_connect_t* req,
uv_pipe_t* handle,
const char* name,
uv_connect_cb cb) {
struct sockaddr_un saddr;
int new_sock;
int err;
int r;
new_sock = (uv__stream_fd(handle) == -1);
if (new_sock) {
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
if (err < 0)
goto out;
handle->io_watcher.fd = err;
}
memset(&saddr, 0, sizeof saddr);
uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path));
saddr.sun_family = AF_UNIX;
do {
r = connect(uv__stream_fd(handle),
(struct sockaddr*)&saddr, sizeof saddr);
}
while (r == -1 && errno == EINTR);
if (r == -1 && errno != EINPROGRESS) {
err = UV__ERR(errno);
#if defined(__CYGWIN__) || defined(__MSYS__)
/* EBADF is supposed to mean that the socket fd is bad, but
Cygwin reports EBADF instead of ENOTSOCK when the file is
not a socket. We do not expect to see a bad fd here
(e.g. due to new_sock), so translate the error. */
if (err == UV_EBADF)
err = UV_ENOTSOCK;
#endif
goto out;
}
err = 0;
if (new_sock) {
err = uv__stream_open((uv_stream_t*)handle,
uv__stream_fd(handle),
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
}
if (err == 0)
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
out:
handle->delayed_error = err;
handle->connect_req = req;
uv__req_init(handle->loop, req, UV_CONNECT);
req->handle = (uv_stream_t*)handle;
req->cb = cb;
QUEUE_INIT(&req->queue);
/* Force callback to run on next tick in case of error. */
if (err)
uv__io_feed(handle->loop, &handle->io_watcher);
}
static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
uv__peersockfunc func,
char* buffer,
size_t* size) {
struct sockaddr_un sa;
socklen_t addrlen;
int err;
addrlen = sizeof(sa);
memset(&sa, 0, addrlen);
err = uv__getsockpeername((const uv_handle_t*) handle,
func,
(struct sockaddr*) &sa,
(int*) &addrlen);
if (err < 0) {
*size = 0;
return err;
}
#if defined(__linux__)
if (sa.sun_path[0] == 0)
/* Linux abstract namespace */
addrlen -= offsetof(struct sockaddr_un, sun_path);
else
#endif
addrlen = strlen(sa.sun_path);
if ((size_t)addrlen >= *size) {
*size = addrlen + 1;
return UV_ENOBUFS;
}
memcpy(buffer, sa.sun_path, addrlen);
*size = addrlen;
/* only null-terminate if it's not an abstract socket */
if (buffer[0] != '\0')
buffer[addrlen] = '\0';
return 0;
}
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
}
int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
}
void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
}
int uv_pipe_pending_count(uv_pipe_t* handle) {
uv__stream_queued_fds_t* queued_fds;
if (!handle->ipc)
return 0;
if (handle->accepted_fd == -1)
return 0;
if (handle->queued_fds == NULL)
return 1;
queued_fds = handle->queued_fds;
return queued_fds->offset + 1;
}
uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
if (!handle->ipc)
return UV_UNKNOWN_HANDLE;
if (handle->accepted_fd == -1)
return UV_UNKNOWN_HANDLE;
else
return uv__handle_type(handle->accepted_fd);
}
int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
unsigned desired_mode;
struct stat pipe_stat;
char* name_buffer;
size_t name_len;
int r;
if (handle == NULL || uv__stream_fd(handle) == -1)
return UV_EBADF;
if (mode != UV_READABLE &&
mode != UV_WRITABLE &&
mode != (UV_WRITABLE | UV_READABLE))
return UV_EINVAL;
/* Unfortunately fchmod does not work on all platforms, we will use chmod. */
name_len = 0;
r = uv_pipe_getsockname(handle, NULL, &name_len);
if (r != UV_ENOBUFS)
return r;
name_buffer = uv__malloc(name_len);
if (name_buffer == NULL)
return UV_ENOMEM;
r = uv_pipe_getsockname(handle, name_buffer, &name_len);
if (r != 0) {
uv__free(name_buffer);
return r;
}
/* stat must be used as fstat has a bug on Darwin */
if (stat(name_buffer, &pipe_stat) == -1) {
uv__free(name_buffer);
return -errno;
}
desired_mode = 0;
if (mode & UV_READABLE)
desired_mode |= S_IRUSR | S_IRGRP | S_IROTH;
if (mode & UV_WRITABLE)
desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
/* Exit early if pipe already has desired mode. */
if ((pipe_stat.st_mode & desired_mode) == desired_mode) {
uv__free(name_buffer);
return 0;
}
pipe_stat.st_mode |= desired_mode;
r = chmod(name_buffer, pipe_stat.st_mode);
uv__free(name_buffer);
return r != -1 ? 0 : UV__ERR(errno);
}

150
deps/libuv/src/unix/poll.c vendored Normal file
View File

@ -0,0 +1,150 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <unistd.h>
#include <assert.h>
#include <errno.h>
static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
uv_poll_t* handle;
int pevents;
handle = container_of(w, uv_poll_t, io_watcher);
/*
* As documented in the kernel source fs/kernfs/file.c #780
* poll will return POLLERR|POLLPRI in case of sysfs
* polling. This does not happen in case of out-of-band
* TCP messages.
*
* The above is the case on (at least) FreeBSD and Linux.
*
* So to properly determine a POLLPRI or a POLLERR we need
* to check for both.
*/
if ((events & POLLERR) && !(events & UV__POLLPRI)) {
uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
uv__handle_stop(handle);
handle->poll_cb(handle, UV_EBADF, 0);
return;
}
pevents = 0;
if (events & POLLIN)
pevents |= UV_READABLE;
if (events & UV__POLLPRI)
pevents |= UV_PRIORITIZED;
if (events & POLLOUT)
pevents |= UV_WRITABLE;
if (events & UV__POLLRDHUP)
pevents |= UV_DISCONNECT;
handle->poll_cb(handle, 0, pevents);
}
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
int err;
if (uv__fd_exists(loop, fd))
return UV_EEXIST;
err = uv__io_check_fd(loop, fd);
if (err)
return err;
/* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL).
* Workaround for e.g. kqueue fds not supporting ioctls.
*/
err = uv__nonblock(fd, 1);
if (err == UV_ENOTTY)
if (uv__nonblock == uv__nonblock_ioctl)
err = uv__nonblock_fcntl(fd, 1);
if (err)
return err;
uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
uv__io_init(&handle->io_watcher, uv__poll_io, fd);
handle->poll_cb = NULL;
return 0;
}
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
uv_os_sock_t socket) {
return uv_poll_init(loop, handle, socket);
}
static void uv__poll_stop(uv_poll_t* handle) {
uv__io_stop(handle->loop,
&handle->io_watcher,
POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
uv__handle_stop(handle);
uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd);
}
int uv_poll_stop(uv_poll_t* handle) {
assert(!uv__is_closing(handle));
uv__poll_stop(handle);
return 0;
}
int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
int events;
assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
UV_PRIORITIZED)) == 0);
assert(!uv__is_closing(handle));
uv__poll_stop(handle);
if (pevents == 0)
return 0;
events = 0;
if (pevents & UV_READABLE)
events |= POLLIN;
if (pevents & UV_PRIORITIZED)
events |= UV__POLLPRI;
if (pevents & UV_WRITABLE)
events |= POLLOUT;
if (pevents & UV_DISCONNECT)
events |= UV__POLLRDHUP;
uv__io_start(handle->loop, &handle->io_watcher, events);
uv__handle_start(handle);
handle->poll_cb = poll_cb;
return 0;
}
void uv__poll_close(uv_poll_t* handle) {
uv__poll_stop(handle);
}

35
deps/libuv/src/unix/posix-hrtime.c vendored Normal file
View File

@ -0,0 +1,35 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdint.h>
#include <time.h>
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
uint64_t uv__hrtime(uv_clocktype_t type) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}

374
deps/libuv/src/unix/posix-poll.c vendored Normal file
View File

@ -0,0 +1,374 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
/* POSIX defines poll() as a portable way to wait on file descriptors.
* Here we maintain a dynamically sized array of file descriptors and
* events to pass as the first argument to poll().
*/
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
int uv__platform_loop_init(uv_loop_t* loop) {
loop->poll_fds = NULL;
loop->poll_fds_used = 0;
loop->poll_fds_size = 0;
loop->poll_fds_iterating = 0;
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
uv__free(loop->poll_fds);
loop->poll_fds = NULL;
}
int uv__io_fork(uv_loop_t* loop) {
uv__platform_loop_delete(loop);
return uv__platform_loop_init(loop);
}
/* Allocate or dynamically resize our poll fds array. */
static void uv__pollfds_maybe_resize(uv_loop_t* loop) {
size_t i;
size_t n;
struct pollfd* p;
if (loop->poll_fds_used < loop->poll_fds_size)
return;
n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;
p = uv__reallocf(loop->poll_fds, n * sizeof(*loop->poll_fds));
if (p == NULL)
abort();
loop->poll_fds = p;
for (i = loop->poll_fds_size; i < n; i++) {
loop->poll_fds[i].fd = -1;
loop->poll_fds[i].events = 0;
loop->poll_fds[i].revents = 0;
}
loop->poll_fds_size = n;
}
/* Primitive swap operation on poll fds array elements. */
static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) {
struct pollfd pfd;
pfd = loop->poll_fds[l];
loop->poll_fds[l] = loop->poll_fds[r];
loop->poll_fds[r] = pfd;
}
/* Add a watcher's fd to our poll fds array with its pending events. */
static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) {
size_t i;
struct pollfd* pe;
/* If the fd is already in the set just update its events. */
assert(!loop->poll_fds_iterating);
for (i = 0; i < loop->poll_fds_used; ++i) {
if (loop->poll_fds[i].fd == w->fd) {
loop->poll_fds[i].events = w->pevents;
return;
}
}
/* Otherwise, allocate a new slot in the set for the fd. */
uv__pollfds_maybe_resize(loop);
pe = &loop->poll_fds[loop->poll_fds_used++];
pe->fd = w->fd;
pe->events = w->pevents;
}
/* Remove a watcher's fd from our poll fds array. */
static void uv__pollfds_del(uv_loop_t* loop, int fd) {
size_t i;
assert(!loop->poll_fds_iterating);
for (i = 0; i < loop->poll_fds_used;) {
if (loop->poll_fds[i].fd == fd) {
/* swap to last position and remove */
--loop->poll_fds_used;
uv__pollfds_swap(loop, i, loop->poll_fds_used);
loop->poll_fds[loop->poll_fds_used].fd = -1;
loop->poll_fds[loop->poll_fds_used].events = 0;
loop->poll_fds[loop->poll_fds_used].revents = 0;
/* This method is called with an fd of -1 to purge the invalidated fds,
* so we may possibly have multiples to remove.
*/
if (-1 != fd)
return;
} else {
/* We must only increment the loop counter when the fds do not match.
* Otherwise, when we are purging an invalidated fd, the value just
* swapped here from the previous end of the array will be skipped.
*/
++i;
}
}
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
sigset_t* pset;
sigset_t set;
uint64_t time_base;
uint64_t time_diff;
QUEUE* q;
uv__io_t* w;
size_t i;
unsigned int nevents;
int nfds;
int have_signals;
struct pollfd* pe;
int fd;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
/* Take queued watchers and add their fds to our poll fds array. */
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
uv__pollfds_add(loop, w);
w->events = w->pevents;
}
/* Prepare a set of signals to block around poll(), if any. */
pset = NULL;
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
pset = &set;
sigemptyset(pset);
sigaddset(pset, SIGPROF);
}
assert(timeout >= -1);
time_base = loop->time;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
/* Loop calls to poll() and processing of results. If we get some
* results from poll() but they turn out not to be interesting to
* our caller then we need to loop around and poll() again.
*/
for (;;) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
if (pset != NULL)
if (pthread_sigmask(SIG_BLOCK, pset, NULL))
abort();
nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout);
if (pset != NULL)
if (pthread_sigmask(SIG_UNBLOCK, pset, NULL))
abort();
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
if (timeout == -1)
continue;
if (timeout > 0)
goto update_timeout;
}
assert(timeout != -1);
return;
}
if (nfds == -1) {
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
}
/* Tell uv__platform_invalidate_fd not to manipulate our array
* while we are iterating over it.
*/
loop->poll_fds_iterating = 1;
/* Initialize a count of events that we care about. */
nevents = 0;
have_signals = 0;
/* Loop over the entire poll fds array looking for returned events. */
for (i = 0; i < loop->poll_fds_used; i++) {
pe = loop->poll_fds + i;
fd = pe->fd;
/* Skip invalidated events, see uv__platform_invalidate_fd. */
if (fd == -1)
continue;
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
w = loop->watchers[fd];
if (w == NULL) {
/* File descriptor that we've stopped watching, ignore. */
uv__platform_invalidate_fd(loop, fd);
continue;
}
/* Filter out events that user has not requested us to watch
* (e.g. POLLNVAL).
*/
pe->revents &= w->pevents | POLLERR | POLLHUP;
if (pe->revents != 0) {
/* Run signal watchers last. */
if (w == &loop->signal_io_watcher) {
have_signals = 1;
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->revents);
}
nevents++;
}
}
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->poll_fds_iterating = 0;
/* Purge invalidated fds from our poll fds array. */
uv__pollfds_del(loop, -1);
if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */
if (nevents != 0)
return;
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
time_diff = loop->time - time_base;
if (time_diff >= (uint64_t) timeout)
return;
timeout -= time_diff;
}
}
/* Remove the given fd from our poll fds array because no one
* is interested in its events anymore.
*/
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
size_t i;
assert(fd >= 0);
if (loop->poll_fds_iterating) {
/* uv__io_poll is currently iterating. Just invalidate fd. */
for (i = 0; i < loop->poll_fds_used; i++)
if (loop->poll_fds[i].fd == fd) {
loop->poll_fds[i].fd = -1;
loop->poll_fds[i].events = 0;
loop->poll_fds[i].revents = 0;
}
} else {
/* uv__io_poll is not iterating. Delete fd from the set. */
uv__pollfds_del(loop, fd);
}
}
/* Check whether the given fd is supported by poll(). */
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct pollfd p[1];
int rv;
p[0].fd = fd;
p[0].events = POLLIN;
do
rv = poll(p, 1, 0);
while (rv == -1 && (errno == EINTR || errno == EAGAIN));
if (rv == -1)
return UV__ERR(errno);
if (p[0].revents & POLLNVAL)
return UV_EINVAL;
return 0;
}

595
deps/libuv/src/unix/process.c vendored Normal file
View File

@ -0,0 +1,595 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#if defined(__APPLE__) && !TARGET_OS_IPHONE
# include <crt_externs.h>
# define environ (*_NSGetEnviron())
#else
extern char **environ;
#endif
#if defined(__linux__) || defined(__GLIBC__)
# include <grp.h>
#endif
static void uv__chld(uv_signal_t* handle, int signum) {
uv_process_t* process;
uv_loop_t* loop;
int exit_status;
int term_signal;
int status;
pid_t pid;
QUEUE pending;
QUEUE* q;
QUEUE* h;
assert(signum == SIGCHLD);
QUEUE_INIT(&pending);
loop = handle->loop;
h = &loop->process_handles;
q = QUEUE_HEAD(h);
while (q != h) {
process = QUEUE_DATA(q, uv_process_t, queue);
q = QUEUE_NEXT(q);
do
pid = waitpid(process->pid, &status, WNOHANG);
while (pid == -1 && errno == EINTR);
if (pid == 0)
continue;
if (pid == -1) {
if (errno != ECHILD)
abort();
continue;
}
process->status = status;
QUEUE_REMOVE(&process->queue);
QUEUE_INSERT_TAIL(&pending, &process->queue);
}
h = &pending;
q = QUEUE_HEAD(h);
while (q != h) {
process = QUEUE_DATA(q, uv_process_t, queue);
q = QUEUE_NEXT(q);
QUEUE_REMOVE(&process->queue);
QUEUE_INIT(&process->queue);
uv__handle_stop(process);
if (process->exit_cb == NULL)
continue;
exit_status = 0;
if (WIFEXITED(process->status))
exit_status = WEXITSTATUS(process->status);
term_signal = 0;
if (WIFSIGNALED(process->status))
term_signal = WTERMSIG(process->status);
process->exit_cb(process, exit_status, term_signal);
}
assert(QUEUE_EMPTY(&pending));
}
static int uv__make_socketpair(int fds[2]) {
#if defined(__FreeBSD__) || defined(__linux__)
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds))
return UV__ERR(errno);
return 0;
#else
int err;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
return UV__ERR(errno);
err = uv__cloexec(fds[0], 1);
if (err == 0)
err = uv__cloexec(fds[1], 1);
if (err != 0) {
uv__close(fds[0]);
uv__close(fds[1]);
return UV__ERR(errno);
}
return 0;
#endif
}
int uv__make_pipe(int fds[2], int flags) {
#if defined(__FreeBSD__) || defined(__linux__)
if (pipe2(fds, flags | O_CLOEXEC))
return UV__ERR(errno);
return 0;
#else
if (pipe(fds))
return UV__ERR(errno);
if (uv__cloexec(fds[0], 1))
goto fail;
if (uv__cloexec(fds[1], 1))
goto fail;
if (flags & UV__F_NONBLOCK) {
if (uv__nonblock(fds[0], 1))
goto fail;
if (uv__nonblock(fds[1], 1))
goto fail;
}
return 0;
fail:
uv__close(fds[0]);
uv__close(fds[1]);
return UV__ERR(errno);
#endif
}
/*
* Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success. See also the cleanup section in uv_spawn().
*/
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
int mask;
int fd;
mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
switch (container->flags & mask) {
case UV_IGNORE:
return 0;
case UV_CREATE_PIPE:
assert(container->data.stream != NULL);
if (container->data.stream->type != UV_NAMED_PIPE)
return UV_EINVAL;
else
return uv__make_socketpair(fds);
case UV_INHERIT_FD:
case UV_INHERIT_STREAM:
if (container->flags & UV_INHERIT_FD)
fd = container->data.fd;
else
fd = uv__stream_fd(container->data.stream);
if (fd == -1)
return UV_EINVAL;
fds[1] = fd;
return 0;
default:
assert(0 && "Unexpected flags");
return UV_EINVAL;
}
}
static int uv__process_open_stream(uv_stdio_container_t* container,
int pipefds[2]) {
int flags;
int err;
if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
return 0;
err = uv__close(pipefds[1]);
if (err != 0)
abort();
pipefds[1] = -1;
uv__nonblock(pipefds[0], 1);
flags = 0;
if (container->flags & UV_WRITABLE_PIPE)
flags |= UV_HANDLE_READABLE;
if (container->flags & UV_READABLE_PIPE)
flags |= UV_HANDLE_WRITABLE;
return uv__stream_open(container->data.stream, pipefds[0], flags);
}
static void uv__process_close_stream(uv_stdio_container_t* container) {
if (!(container->flags & UV_CREATE_PIPE)) return;
uv__stream_close(container->data.stream);
}
static void uv__write_int(int fd, int val) {
ssize_t n;
do
n = write(fd, &val, sizeof(val));
while (n == -1 && errno == EINTR);
if (n == -1 && errno == EPIPE)
return; /* parent process has quit */
assert(n == sizeof(val));
}
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
* avoided. Since this isn't called on those targets, the function
* doesn't even need to be defined for them.
*/
static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd) {
sigset_t set;
int close_fd;
int use_fd;
int err;
int fd;
int n;
if (options->flags & UV_PROCESS_DETACHED)
setsid();
/* First duplicate low numbered fds, since it's not safe to duplicate them,
* they could get replaced. Example: swapping stdout and stderr; without
* this fd 2 (stderr) would be duplicated into fd 1, thus making both
* stdout and stderr go to the same fd, which was not the intention. */
for (fd = 0; fd < stdio_count; fd++) {
use_fd = pipes[fd][1];
if (use_fd < 0 || use_fd >= fd)
continue;
pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
if (pipes[fd][1] == -1) {
uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
}
}
for (fd = 0; fd < stdio_count; fd++) {
close_fd = pipes[fd][0];
use_fd = pipes[fd][1];
if (use_fd < 0) {
if (fd >= 3)
continue;
else {
/* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
* set
*/
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
close_fd = use_fd;
if (use_fd < 0) {
uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
}
}
}
if (fd == use_fd)
uv__cloexec_fcntl(use_fd, 0);
else
fd = dup2(use_fd, fd);
if (fd == -1) {
uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
}
if (fd <= 2)
uv__nonblock_fcntl(fd, 0);
if (close_fd >= stdio_count)
uv__close(close_fd);
}
for (fd = 0; fd < stdio_count; fd++) {
use_fd = pipes[fd][1];
if (use_fd >= stdio_count)
uv__close(use_fd);
}
if (options->cwd != NULL && chdir(options->cwd)) {
uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
}
if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
/* When dropping privileges from root, the `setgroups` call will
* remove any extraneous groups. If we don't call this, then
* even though our uid has dropped, we may still have groups
* that enable us to do super-user things. This will fail if we
* aren't root, so don't bother checking the return value, this
* is just done as an optimistic privilege dropping function.
*/
SAVE_ERRNO(setgroups(0, NULL));
}
if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
}
if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
}
if (options->env != NULL) {
environ = options->env;
}
/* Reset signal disposition. Use a hard-coded limit because NSIG
* is not fixed on Linux: it's either 32, 34 or 64, depending on
* whether RT signals are enabled. We are not allowed to touch
* RT signal handlers, glibc uses them internally.
*/
for (n = 1; n < 32; n += 1) {
if (n == SIGKILL || n == SIGSTOP)
continue; /* Can't be changed. */
#if defined(__HAIKU__)
if (n == SIGKILLTHR)
continue; /* Can't be changed. */
#endif
if (SIG_ERR != signal(n, SIG_DFL))
continue;
uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
}
/* Reset signal mask. */
sigemptyset(&set);
err = pthread_sigmask(SIG_SETMASK, &set, NULL);
if (err != 0) {
uv__write_int(error_fd, UV__ERR(err));
_exit(127);
}
execvp(options->file, options->args);
uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
}
#endif
int uv_spawn(uv_loop_t* loop,
uv_process_t* process,
const uv_process_options_t* options) {
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
/* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
return UV_ENOSYS;
#else
int signal_pipe[2] = { -1, -1 };
int pipes_storage[8][2];
int (*pipes)[2];
int stdio_count;
ssize_t r;
pid_t pid;
int err;
int exec_errorno;
int i;
int status;
assert(options->file != NULL);
assert(!(options->flags & ~(UV_PROCESS_DETACHED |
UV_PROCESS_SETGID |
UV_PROCESS_SETUID |
UV_PROCESS_WINDOWS_HIDE |
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
UV_PROCESS_WINDOWS_HIDE_GUI |
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
QUEUE_INIT(&process->queue);
stdio_count = options->stdio_count;
if (stdio_count < 3)
stdio_count = 3;
err = UV_ENOMEM;
pipes = pipes_storage;
if (stdio_count > (int) ARRAY_SIZE(pipes_storage))
pipes = uv__malloc(stdio_count * sizeof(*pipes));
if (pipes == NULL)
goto error;
for (i = 0; i < stdio_count; i++) {
pipes[i][0] = -1;
pipes[i][1] = -1;
}
for (i = 0; i < options->stdio_count; i++) {
err = uv__process_init_stdio(options->stdio + i, pipes[i]);
if (err)
goto error;
}
/* This pipe is used by the parent to wait until
* the child has called `execve()`. We need this
* to avoid the following race condition:
*
* if ((pid = fork()) > 0) {
* kill(pid, SIGTERM);
* }
* else if (pid == 0) {
* execve("/bin/cat", argp, envp);
* }
*
* The parent sends a signal immediately after forking.
* Since the child may not have called `execve()` yet,
* there is no telling what process receives the signal,
* our fork or /bin/cat.
*
* To avoid ambiguity, we create a pipe with both ends
* marked close-on-exec. Then, after the call to `fork()`,
* the parent polls the read end until it EOFs or errors with EPIPE.
*/
err = uv__make_pipe(signal_pipe, 0);
if (err)
goto error;
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
/* Acquire write lock to prevent opening new fds in worker threads */
uv_rwlock_wrlock(&loop->cloexec_lock);
pid = fork();
if (pid == -1) {
err = UV__ERR(errno);
uv_rwlock_wrunlock(&loop->cloexec_lock);
uv__close(signal_pipe[0]);
uv__close(signal_pipe[1]);
goto error;
}
if (pid == 0) {
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
abort();
}
/* Release lock in parent process */
uv_rwlock_wrunlock(&loop->cloexec_lock);
uv__close(signal_pipe[1]);
process->status = 0;
exec_errorno = 0;
do
r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
while (r == -1 && errno == EINTR);
if (r == 0)
; /* okay, EOF */
else if (r == sizeof(exec_errorno)) {
do
err = waitpid(pid, &status, 0); /* okay, read errorno */
while (err == -1 && errno == EINTR);
assert(err == pid);
} else if (r == -1 && errno == EPIPE) {
do
err = waitpid(pid, &status, 0); /* okay, got EPIPE */
while (err == -1 && errno == EINTR);
assert(err == pid);
} else
abort();
uv__close_nocheckstdio(signal_pipe[0]);
for (i = 0; i < options->stdio_count; i++) {
err = uv__process_open_stream(options->stdio + i, pipes[i]);
if (err == 0)
continue;
while (i--)
uv__process_close_stream(options->stdio + i);
goto error;
}
/* Only activate this handle if exec() happened successfully */
if (exec_errorno == 0) {
QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
uv__handle_start(process);
}
process->pid = pid;
process->exit_cb = options->exit_cb;
if (pipes != pipes_storage)
uv__free(pipes);
return exec_errorno;
error:
if (pipes != NULL) {
for (i = 0; i < stdio_count; i++) {
if (i < options->stdio_count)
if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
continue;
if (pipes[i][0] != -1)
uv__close_nocheckstdio(pipes[i][0]);
if (pipes[i][1] != -1)
uv__close_nocheckstdio(pipes[i][1]);
}
if (pipes != pipes_storage)
uv__free(pipes);
}
return err;
#endif
}
int uv_process_kill(uv_process_t* process, int signum) {
return uv_kill(process->pid, signum);
}
int uv_kill(int pid, int signum) {
if (kill(pid, signum))
return UV__ERR(errno);
else
return 0;
}
void uv__process_close(uv_process_t* handle) {
QUEUE_REMOVE(&handle->queue);
uv__handle_stop(handle);
if (QUEUE_EMPTY(&handle->loop->process_handles))
uv_signal_stop(&handle->loop->child_watcher);
}

45
deps/libuv/src/unix/procfs-exepath.c vendored Normal file
View File

@ -0,0 +1,45 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stddef.h>
#include <unistd.h>
int uv_exepath(char* buffer, size_t* size) {
ssize_t n;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
n = *size - 1;
if (n > 0)
n = readlink("/proc/self/exe", buffer, n);
if (n == -1)
return UV__ERR(errno);
buffer[n] = '\0';
*size = n;
return 0;
}

159
deps/libuv/src/unix/proctitle.c vendored Normal file
View File

@ -0,0 +1,159 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdlib.h>
#include <string.h>
struct uv__process_title {
char* str;
size_t len; /* Length of the current process title. */
size_t cap; /* Maximum capacity. Computed once in uv_setup_args(). */
};
extern void uv__set_process_title(const char* title);
static uv_mutex_t process_title_mutex;
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static struct uv__process_title process_title;
static void* args_mem;
static void init_process_title_mutex_once(void) {
uv_mutex_init(&process_title_mutex);
}
char** uv_setup_args(int argc, char** argv) {
struct uv__process_title pt;
char** new_argv;
size_t size;
char* s;
int i;
if (argc <= 0)
return argv;
pt.str = argv[0];
pt.len = strlen(argv[0]);
pt.cap = pt.len + 1;
/* Calculate how much memory we need for the argv strings. */
size = pt.cap;
for (i = 1; i < argc; i++)
size += strlen(argv[i]) + 1;
/* Add space for the argv pointers. */
size += (argc + 1) * sizeof(char*);
new_argv = uv__malloc(size);
if (new_argv == NULL)
return argv;
/* Copy over the strings and set up the pointer table. */
i = 0;
s = (char*) &new_argv[argc + 1];
size = pt.cap;
goto loop;
for (/* empty */; i < argc; i++) {
size = strlen(argv[i]) + 1;
loop:
memcpy(s, argv[i], size);
new_argv[i] = s;
s += size;
}
new_argv[i] = NULL;
/* argv is not adjacent on z/os, we use just argv[0] on that platform. */
#ifndef __MVS__
pt.cap = argv[i - 1] + size - argv[0];
#endif
args_mem = new_argv;
process_title = pt;
return new_argv;
}
int uv_set_process_title(const char* title) {
struct uv__process_title* pt;
size_t len;
/* If uv_setup_args wasn't called or failed, we can't continue. */
if (args_mem == NULL)
return UV_ENOBUFS;
pt = &process_title;
len = strlen(title);
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
if (len >= pt->cap) {
len = 0;
if (pt->cap > 0)
len = pt->cap - 1;
}
memcpy(pt->str, title, len);
memset(pt->str + len, '\0', pt->cap - len);
pt->len = len;
uv_mutex_unlock(&process_title_mutex);
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return UV_EINVAL;
/* If uv_setup_args wasn't called or failed, we can't continue. */
if (args_mem == NULL)
return UV_ENOBUFS;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
if (size <= process_title.len) {
uv_mutex_unlock(&process_title_mutex);
return UV_ENOBUFS;
}
if (process_title.len != 0)
memcpy(buffer, process_title.str, process_title.len + 1);
buffer[process_title.len] = '\0';
uv_mutex_unlock(&process_title_mutex);
return 0;
}
void uv__process_title_cleanup(void) {
uv__free(args_mem); /* Keep valgrind happy. */
args_mem = NULL;
}

58
deps/libuv/src/unix/pthread-fixes.c vendored Normal file
View File

@ -0,0 +1,58 @@
/* Copyright (c) 2013, Sony Mobile Communications AB
* Copyright (c) 2012, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Android versions < 4.1 have a broken pthread_sigmask. */
#include "uv-common.h"
#include <errno.h>
#include <pthread.h>
#include <signal.h>
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
static int workaround;
int err;
if (uv__load_relaxed(&workaround)) {
return sigprocmask(how, set, oset);
} else {
err = pthread_sigmask(how, set, oset);
if (err) {
if (err == EINVAL && sigprocmask(how, set, oset) == 0) {
uv__store_relaxed(&workaround, 1);
return 0;
} else {
return -1;
}
}
}
return 0;
}

137
deps/libuv/src/unix/qnx.c vendored Normal file
View File

@ -0,0 +1,137 @@
/* Copyright libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <string.h>
#include <sys/process.h>
#include <sys/neutrino.h>
#include <sys/memmsg.h>
#include <sys/syspage.h>
#include <sys/procfs.h>
static void
get_mem_info(uint64_t* totalmem, uint64_t* freemem) {
mem_info_t msg;
memset(&msg, 0, sizeof(msg));
msg.i.type = _MEM_INFO;
msg.i.fd = -1;
if (MsgSend(MEMMGR_COID, &msg.i, sizeof(msg.i), &msg.o, sizeof(msg.o))
!= -1) {
*totalmem = msg.o.info.__posix_tmi_total;
*freemem = msg.o.info.posix_tmi_length;
} else {
*totalmem = 0;
*freemem = 0;
}
}
void uv_loadavg(double avg[3]) {
avg[0] = 0.0;
avg[1] = 0.0;
avg[2] = 0.0;
}
int uv_exepath(char* buffer, size_t* size) {
char path[PATH_MAX];
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
realpath(_cmdname(NULL), path);
strlcpy(buffer, path, *size);
*size = strlen(buffer);
return 0;
}
uint64_t uv_get_free_memory(void) {
uint64_t totalmem;
uint64_t freemem;
get_mem_info(&totalmem, &freemem);
return freemem;
}
uint64_t uv_get_total_memory(void) {
uint64_t totalmem;
uint64_t freemem;
get_mem_info(&totalmem, &freemem);
return totalmem;
}
uint64_t uv_get_constrained_memory(void) {
return 0;
}
int uv_resident_set_memory(size_t* rss) {
int fd;
procfs_asinfo asinfo;
fd = uv__open_cloexec("/proc/self/ctl", O_RDONLY);
if (fd == -1)
return UV__ERR(errno);
if (devctl(fd, DCMD_PROC_ASINFO, &asinfo, sizeof(asinfo), 0) == -1) {
uv__close(fd);
return UV__ERR(errno);
}
uv__close(fd);
*rss = asinfo.rss;
return 0;
}
int uv_uptime(double* uptime) {
struct qtime_entry* qtime = _SYSPAGE_ENTRY(_syspage_ptr, qtime);
*uptime = (qtime->nsec / 1000000000.0);
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
struct cpuinfo_entry* cpuinfo =
(struct cpuinfo_entry*)_SYSPAGE_ENTRY(_syspage_ptr, new_cpuinfo);
size_t cpuinfo_size = _SYSPAGE_ELEMENT_SIZE(_syspage_ptr, cpuinfo);
struct strings_entry* strings = _SYSPAGE_ENTRY(_syspage_ptr, strings);
int num_cpus = _syspage_ptr->num_cpu;
int i;
*count = num_cpus;
*cpu_infos = uv__malloc(num_cpus * sizeof(**cpu_infos));
if (*cpu_infos == NULL)
return UV_ENOMEM;
for (i = 0; i < num_cpus; i++) {
(*cpu_infos)[i].model = strdup(&strings->data[cpuinfo->name]);
(*cpu_infos)[i].speed = cpuinfo->speed;
SYSPAGE_ARRAY_ADJ_OFFSET(cpuinfo, cpuinfo, cpuinfo_size);
}
return 0;
}

93
deps/libuv/src/unix/random-devurandom.c vendored Normal file
View File

@ -0,0 +1,93 @@
/* Copyright libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <sys/stat.h>
#include <unistd.h>
static uv_once_t once = UV_ONCE_INIT;
static int status;
int uv__random_readpath(const char* path, void* buf, size_t buflen) {
struct stat s;
size_t pos;
ssize_t n;
int fd;
fd = uv__open_cloexec(path, O_RDONLY);
if (fd < 0)
return fd;
if (fstat(fd, &s)) {
uv__close(fd);
return UV__ERR(errno);
}
if (!S_ISCHR(s.st_mode)) {
uv__close(fd);
return UV_EIO;
}
for (pos = 0; pos != buflen; pos += n) {
do
n = read(fd, (char*) buf + pos, buflen - pos);
while (n == -1 && errno == EINTR);
if (n == -1) {
uv__close(fd);
return UV__ERR(errno);
}
if (n == 0) {
uv__close(fd);
return UV_EIO;
}
}
uv__close(fd);
return 0;
}
static void uv__random_devurandom_init(void) {
char c;
/* Linux's random(4) man page suggests applications should read at least
* once from /dev/random before switching to /dev/urandom in order to seed
* the system RNG. Reads from /dev/random can of course block indefinitely
* until entropy is available but that's the point.
*/
status = uv__random_readpath("/dev/random", &c, 1);
}
int uv__random_devurandom(void* buf, size_t buflen) {
uv_once(&once, uv__random_devurandom_init);
if (status != 0)
return status;
return uv__random_readpath("/dev/urandom", buf, buflen);
}

57
deps/libuv/src/unix/random-getentropy.c vendored Normal file
View File

@ -0,0 +1,57 @@
/* Copyright libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stddef.h>
#include <dlfcn.h>
typedef int (*uv__getentropy_cb)(void *, size_t);
static uv__getentropy_cb uv__getentropy;
static uv_once_t once = UV_ONCE_INIT;
static void uv__random_getentropy_init(void) {
uv__getentropy = (uv__getentropy_cb) dlsym(RTLD_DEFAULT, "getentropy");
}
int uv__random_getentropy(void* buf, size_t buflen) {
size_t pos;
size_t stride;
uv_once(&once, uv__random_getentropy_init);
if (uv__getentropy == NULL)
return UV_ENOSYS;
/* getentropy() returns an error for requests > 256 bytes. */
for (pos = 0, stride = 256; pos + stride < buflen; pos += stride)
if (uv__getentropy((char *) buf + pos, stride))
return UV__ERR(errno);
if (uv__getentropy((char *) buf + pos, buflen - pos))
return UV__ERR(errno);
return 0;
}

88
deps/libuv/src/unix/random-getrandom.c vendored Normal file
View File

@ -0,0 +1,88 @@
/* Copyright libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#ifdef __linux__
#include "linux-syscalls.h"
#define uv__random_getrandom_init() 0
#else /* !__linux__ */
#include <stddef.h>
#include <dlfcn.h>
typedef ssize_t (*uv__getrandom_cb)(void *, size_t, unsigned);
static uv__getrandom_cb uv__getrandom;
static uv_once_t once = UV_ONCE_INIT;
static void uv__random_getrandom_init_once(void) {
uv__getrandom = (uv__getrandom_cb) dlsym(RTLD_DEFAULT, "getrandom");
}
static int uv__random_getrandom_init(void) {
uv_once(&once, uv__random_getrandom_init_once);
if (uv__getrandom == NULL)
return UV_ENOSYS;
return 0;
}
#endif /* !__linux__ */
int uv__random_getrandom(void* buf, size_t buflen) {
ssize_t n;
size_t pos;
int rc;
rc = uv__random_getrandom_init();
if (rc != 0)
return rc;
for (pos = 0; pos != buflen; pos += n) {
do {
n = buflen - pos;
/* Most getrandom() implementations promise that reads <= 256 bytes
* will always succeed and won't be interrupted by signals.
* It's therefore useful to split it up in smaller reads because
* one big read may, in theory, continuously fail with EINTR.
*/
if (n > 256)
n = 256;
n = uv__getrandom((char *) buf + pos, n, 0);
} while (n == -1 && errno == EINTR);
if (n == -1)
return UV__ERR(errno);
if (n == 0)
return UV_EIO;
}
return 0;
}

View File

@ -0,0 +1,99 @@
/* Copyright libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <errno.h>
#include <string.h>
#include <syscall.h>
#include <unistd.h>
struct uv__sysctl_args {
int* name;
int nlen;
void* oldval;
size_t* oldlenp;
void* newval;
size_t newlen;
unsigned long unused[4];
};
int uv__random_sysctl(void* buf, size_t buflen) {
static int name[] = {1 /*CTL_KERN*/, 40 /*KERN_RANDOM*/, 6 /*RANDOM_UUID*/};
struct uv__sysctl_args args;
char uuid[16];
char* p;
char* pe;
size_t n;
p = buf;
pe = p + buflen;
while (p < pe) {
memset(&args, 0, sizeof(args));
args.name = name;
args.nlen = ARRAY_SIZE(name);
args.oldval = uuid;
args.oldlenp = &n;
n = sizeof(uuid);
/* Emits a deprecation warning with some kernels but that seems like
* an okay trade-off for the fallback of the fallback: this function is
* only called when neither getrandom(2) nor /dev/urandom are available.
* Fails with ENOSYS on kernels configured without CONFIG_SYSCTL_SYSCALL.
* At least arm64 never had a _sysctl system call and therefore doesn't
* have a SYS__sysctl define either.
*/
#ifdef SYS__sysctl
if (syscall(SYS__sysctl, &args) == -1)
return UV__ERR(errno);
#else
{
(void) &args;
return UV_ENOSYS;
}
#endif
if (n != sizeof(uuid))
return UV_EIO; /* Can't happen. */
/* uuid[] is now a type 4 UUID. Bytes 6 and 8 (counting from zero) contain
* 4 and 5 bits of entropy, respectively. For ease of use, we skip those
* and only use 14 of the 16 bytes.
*/
uuid[6] = uuid[14];
uuid[8] = uuid[15];
n = pe - p;
if (n > 14)
n = 14;
memcpy(p, uuid, n);
p += n;
}
return 0;
}

558
deps/libuv/src/unix/signal.c vendored Normal file
View File

@ -0,0 +1,558 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef SA_RESTART
# define SA_RESTART 0
#endif
typedef struct {
uv_signal_t* handle;
int signum;
} uv__signal_msg_t;
RB_HEAD(uv__signal_tree_s, uv_signal_s);
static int uv__signal_unlock(void);
static int uv__signal_start(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum,
int oneshot);
static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events);
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
static void uv__signal_stop(uv_signal_t* handle);
static void uv__signal_unregister_handler(int signum);
static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
static struct uv__signal_tree_s uv__signal_tree =
RB_INITIALIZER(uv__signal_tree);
static int uv__signal_lock_pipefd[2] = { -1, -1 };
RB_GENERATE_STATIC(uv__signal_tree_s,
uv_signal_s, tree_entry,
uv__signal_compare)
static void uv__signal_global_reinit(void);
static void uv__signal_global_init(void) {
if (uv__signal_lock_pipefd[0] == -1)
/* pthread_atfork can register before and after handlers, one
* for each child. This only registers one for the child. That
* state is both persistent and cumulative, so if we keep doing
* it the handler functions will be called multiple times. Thus
* we only want to do it once.
*/
if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit))
abort();
uv__signal_global_reinit();
}
void uv__signal_cleanup(void) {
/* We can only use signal-safe functions here.
* That includes read/write and close, fortunately.
* We do all of this directly here instead of resetting
* uv__signal_global_init_guard because
* uv__signal_global_once_init is only called from uv_loop_init
* and this needs to function in existing loops.
*/
if (uv__signal_lock_pipefd[0] != -1) {
uv__close(uv__signal_lock_pipefd[0]);
uv__signal_lock_pipefd[0] = -1;
}
if (uv__signal_lock_pipefd[1] != -1) {
uv__close(uv__signal_lock_pipefd[1]);
uv__signal_lock_pipefd[1] = -1;
}
}
static void uv__signal_global_reinit(void) {
uv__signal_cleanup();
if (uv__make_pipe(uv__signal_lock_pipefd, 0))
abort();
if (uv__signal_unlock())
abort();
}
void uv__signal_global_once_init(void) {
uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
}
static int uv__signal_lock(void) {
int r;
char data;
do {
r = read(uv__signal_lock_pipefd[0], &data, sizeof data);
} while (r < 0 && errno == EINTR);
return (r < 0) ? -1 : 0;
}
static int uv__signal_unlock(void) {
int r;
char data = 42;
do {
r = write(uv__signal_lock_pipefd[1], &data, sizeof data);
} while (r < 0 && errno == EINTR);
return (r < 0) ? -1 : 0;
}
static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
sigset_t new_mask;
if (sigfillset(&new_mask))
abort();
/* to shut up valgrind */
sigemptyset(saved_sigmask);
if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
abort();
if (uv__signal_lock())
abort();
}
static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
if (uv__signal_unlock())
abort();
if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL))
abort();
}
static uv_signal_t* uv__signal_first_handle(int signum) {
/* This function must be called with the signal lock held. */
uv_signal_t lookup;
uv_signal_t* handle;
lookup.signum = signum;
lookup.flags = 0;
lookup.loop = NULL;
handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup);
if (handle != NULL && handle->signum == signum)
return handle;
return NULL;
}
static void uv__signal_handler(int signum) {
uv__signal_msg_t msg;
uv_signal_t* handle;
int saved_errno;
saved_errno = errno;
memset(&msg, 0, sizeof msg);
if (uv__signal_lock()) {
errno = saved_errno;
return;
}
for (handle = uv__signal_first_handle(signum);
handle != NULL && handle->signum == signum;
handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
int r;
msg.signum = signum;
msg.handle = handle;
/* write() should be atomic for small data chunks, so the entire message
* should be written at once. In theory the pipe could become full, in
* which case the user is out of luck.
*/
do {
r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg);
} while (r == -1 && errno == EINTR);
assert(r == sizeof msg ||
(r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));
if (r != -1)
handle->caught_signals++;
}
uv__signal_unlock();
errno = saved_errno;
}
static int uv__signal_register_handler(int signum, int oneshot) {
/* When this function is called, the signal lock must be held. */
struct sigaction sa;
/* XXX use a separate signal stack? */
memset(&sa, 0, sizeof(sa));
if (sigfillset(&sa.sa_mask))
abort();
sa.sa_handler = uv__signal_handler;
sa.sa_flags = SA_RESTART;
if (oneshot)
sa.sa_flags |= SA_RESETHAND;
/* XXX save old action so we can restore it later on? */
if (sigaction(signum, &sa, NULL))
return UV__ERR(errno);
return 0;
}
static void uv__signal_unregister_handler(int signum) {
/* When this function is called, the signal lock must be held. */
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
/* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a
* signal implies that it was successfully registered earlier, so EINVAL
* should never happen.
*/
if (sigaction(signum, &sa, NULL))
abort();
}
static int uv__signal_loop_once_init(uv_loop_t* loop) {
int err;
/* Return if already initialized. */
if (loop->signal_pipefd[0] != -1)
return 0;
err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
if (err)
return err;
uv__io_init(&loop->signal_io_watcher,
uv__signal_event,
loop->signal_pipefd[0]);
uv__io_start(loop, &loop->signal_io_watcher, POLLIN);
return 0;
}
int uv__signal_loop_fork(uv_loop_t* loop) {
uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
uv__close(loop->signal_pipefd[0]);
uv__close(loop->signal_pipefd[1]);
loop->signal_pipefd[0] = -1;
loop->signal_pipefd[1] = -1;
return uv__signal_loop_once_init(loop);
}
void uv__signal_loop_cleanup(uv_loop_t* loop) {
QUEUE* q;
/* Stop all the signal watchers that are still attached to this loop. This
* ensures that the (shared) signal tree doesn't contain any invalid entries
* entries, and that signal handlers are removed when appropriate.
* It's safe to use QUEUE_FOREACH here because the handles and the handle
* queue are not modified by uv__signal_stop().
*/
QUEUE_FOREACH(q, &loop->handle_queue) {
uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
if (handle->type == UV_SIGNAL)
uv__signal_stop((uv_signal_t*) handle);
}
if (loop->signal_pipefd[0] != -1) {
uv__close(loop->signal_pipefd[0]);
loop->signal_pipefd[0] = -1;
}
if (loop->signal_pipefd[1] != -1) {
uv__close(loop->signal_pipefd[1]);
loop->signal_pipefd[1] = -1;
}
}
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
int err;
err = uv__signal_loop_once_init(loop);
if (err)
return err;
uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
handle->signum = 0;
handle->caught_signals = 0;
handle->dispatched_signals = 0;
return 0;
}
void uv__signal_close(uv_signal_t* handle) {
uv__signal_stop(handle);
}
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
return uv__signal_start(handle, signal_cb, signum, 0);
}
int uv_signal_start_oneshot(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum) {
return uv__signal_start(handle, signal_cb, signum, 1);
}
static int uv__signal_start(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum,
int oneshot) {
sigset_t saved_sigmask;
int err;
uv_signal_t* first_handle;
assert(!uv__is_closing(handle));
/* If the user supplies signum == 0, then return an error already. If the
* signum is otherwise invalid then uv__signal_register will find out
* eventually.
*/
if (signum == 0)
return UV_EINVAL;
/* Short circuit: if the signal watcher is already watching {signum} don't
* go through the process of deregistering and registering the handler.
* Additionally, this avoids pending signals getting lost in the small
* time frame that handle->signum == 0.
*/
if (signum == handle->signum) {
handle->signal_cb = signal_cb;
return 0;
}
/* If the signal handler was already active, stop it first. */
if (handle->signum != 0) {
uv__signal_stop(handle);
}
uv__signal_block_and_lock(&saved_sigmask);
/* If at this point there are no active signal watchers for this signum (in
* any of the loops), it's time to try and register a handler for it here.
* Also in case there's only one-shot handlers and a regular handler comes in.
*/
first_handle = uv__signal_first_handle(signum);
if (first_handle == NULL ||
(!oneshot && (first_handle->flags & UV_SIGNAL_ONE_SHOT))) {
err = uv__signal_register_handler(signum, oneshot);
if (err) {
/* Registering the signal handler failed. Must be an invalid signal. */
uv__signal_unlock_and_unblock(&saved_sigmask);
return err;
}
}
handle->signum = signum;
if (oneshot)
handle->flags |= UV_SIGNAL_ONE_SHOT;
RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
uv__signal_unlock_and_unblock(&saved_sigmask);
handle->signal_cb = signal_cb;
uv__handle_start(handle);
return 0;
}
static void uv__signal_event(uv_loop_t* loop,
uv__io_t* w,
unsigned int events) {
uv__signal_msg_t* msg;
uv_signal_t* handle;
char buf[sizeof(uv__signal_msg_t) * 32];
size_t bytes, end, i;
int r;
bytes = 0;
end = 0;
do {
r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);
if (r == -1 && errno == EINTR)
continue;
if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
/* If there are bytes in the buffer already (which really is extremely
* unlikely if possible at all) we can't exit the function here. We'll
* spin until more bytes are read instead.
*/
if (bytes > 0)
continue;
/* Otherwise, there was nothing there. */
return;
}
/* Other errors really should never happen. */
if (r == -1)
abort();
bytes += r;
/* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */
end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t);
for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) {
msg = (uv__signal_msg_t*) (buf + i);
handle = msg->handle;
if (msg->signum == handle->signum) {
assert(!(handle->flags & UV_HANDLE_CLOSING));
handle->signal_cb(handle, handle->signum);
}
handle->dispatched_signals++;
if (handle->flags & UV_SIGNAL_ONE_SHOT)
uv__signal_stop(handle);
}
bytes -= end;
/* If there are any "partial" messages left, move them to the start of the
* the buffer, and spin. This should not happen.
*/
if (bytes) {
memmove(buf, buf + end, bytes);
continue;
}
} while (end == sizeof buf);
}
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
int f1;
int f2;
/* Compare signums first so all watchers with the same signnum end up
* adjacent.
*/
if (w1->signum < w2->signum) return -1;
if (w1->signum > w2->signum) return 1;
/* Handlers without UV_SIGNAL_ONE_SHOT set will come first, so if the first
* handler returned is a one-shot handler, the rest will be too.
*/
f1 = w1->flags & UV_SIGNAL_ONE_SHOT;
f2 = w2->flags & UV_SIGNAL_ONE_SHOT;
if (f1 < f2) return -1;
if (f1 > f2) return 1;
/* Sort by loop pointer, so we can easily look up the first item after
* { .signum = x, .loop = NULL }.
*/
if (w1->loop < w2->loop) return -1;
if (w1->loop > w2->loop) return 1;
if (w1 < w2) return -1;
if (w1 > w2) return 1;
return 0;
}
int uv_signal_stop(uv_signal_t* handle) {
assert(!uv__is_closing(handle));
uv__signal_stop(handle);
return 0;
}
static void uv__signal_stop(uv_signal_t* handle) {
uv_signal_t* removed_handle;
sigset_t saved_sigmask;
uv_signal_t* first_handle;
int rem_oneshot;
int first_oneshot;
int ret;
/* If the watcher wasn't started, this is a no-op. */
if (handle->signum == 0)
return;
uv__signal_block_and_lock(&saved_sigmask);
removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle);
assert(removed_handle == handle);
(void) removed_handle;
/* Check if there are other active signal watchers observing this signal. If
* not, unregister the signal handler.
*/
first_handle = uv__signal_first_handle(handle->signum);
if (first_handle == NULL) {
uv__signal_unregister_handler(handle->signum);
} else {
rem_oneshot = handle->flags & UV_SIGNAL_ONE_SHOT;
first_oneshot = first_handle->flags & UV_SIGNAL_ONE_SHOT;
if (first_oneshot && !rem_oneshot) {
ret = uv__signal_register_handler(handle->signum, 1);
assert(ret == 0);
(void)ret;
}
}
uv__signal_unlock_and_unblock(&saved_sigmask);
handle->signum = 0;
uv__handle_stop(handle);
}

53
deps/libuv/src/unix/spinlock.h vendored Normal file
View File

@ -0,0 +1,53 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef UV_SPINLOCK_H_
#define UV_SPINLOCK_H_
#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */
#include "atomic-ops.h"
#define UV_SPINLOCK_INITIALIZER { 0 }
typedef struct {
int lock;
} uv_spinlock_t;
UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock));
UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock));
UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock));
UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock));
UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) {
ACCESS_ONCE(int, spinlock->lock) = 0;
}
UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) {
while (!uv_spinlock_trylock(spinlock)) cpu_relax();
}
UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) {
ACCESS_ONCE(int, spinlock->lock) = 0;
}
UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) {
/* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing.
* Not really critical until we have locks that are (frequently) contended
* for by several threads.
*/
return 0 == cmpxchgi(&spinlock->lock, 0, 1);
}
#endif /* UV_SPINLOCK_H_ */

1693
deps/libuv/src/unix/stream.c vendored Normal file

File diff suppressed because it is too large Load Diff

867
deps/libuv/src/unix/sunos.c vendored Normal file
View File

@ -0,0 +1,867 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#ifndef SUNOS_NO_IFADDRS
# include <ifaddrs.h>
#endif
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_arp.h>
#include <sys/sockio.h>
#include <sys/loadavg.h>
#include <sys/time.h>
#include <unistd.h>
#include <kstat.h>
#include <fcntl.h>
#include <sys/port.h>
#include <port.h>
#define PORT_FIRED 0x69
#define PORT_UNUSED 0x0
#define PORT_LOADED 0x99
#define PORT_DELETED -1
#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
#define PROCFS_FILE_OFFSET_BITS_HACK 1
#undef _FILE_OFFSET_BITS
#else
#define PROCFS_FILE_OFFSET_BITS_HACK 0
#endif
#include <procfs.h>
#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
#define _FILE_OFFSET_BITS 64
#endif
int uv__platform_loop_init(uv_loop_t* loop) {
int err;
int fd;
loop->fs_fd = -1;
loop->backend_fd = -1;
fd = port_create();
if (fd == -1)
return UV__ERR(errno);
err = uv__cloexec(fd, 1);
if (err) {
uv__close(fd);
return err;
}
loop->backend_fd = fd;
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->fs_fd != -1) {
uv__close(loop->fs_fd);
loop->fs_fd = -1;
}
if (loop->backend_fd != -1) {
uv__close(loop->backend_fd);
loop->backend_fd = -1;
}
}
int uv__io_fork(uv_loop_t* loop) {
#if defined(PORT_SOURCE_FILE)
if (loop->fs_fd != -1) {
/* stop the watcher before we blow away its fileno */
uv__io_stop(loop, &loop->fs_event_watcher, POLLIN);
}
#endif
uv__platform_loop_delete(loop);
return uv__platform_loop_init(loop);
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct port_event* events;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
assert(fd >= 0);
events = (struct port_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].portev_object == fd)
events[i].portev_object = -1;
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0))
return UV__ERR(errno);
if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) {
perror("(libuv) port_dissociate()");
abort();
}
return 0;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
struct port_event events[1024];
struct port_event* pe;
struct timespec spec;
QUEUE* q;
uv__io_t* w;
sigset_t* pset;
sigset_t set;
uint64_t base;
uint64_t diff;
uint64_t idle_poll;
unsigned int nfds;
unsigned int i;
int saved_errno;
int have_signals;
int nevents;
int count;
int err;
int fd;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
if (port_associate(loop->backend_fd,
PORT_SOURCE_FD,
w->fd,
w->pevents,
0)) {
perror("(libuv) port_associate()");
abort();
}
w->events = w->pevents;
}
pset = NULL;
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
pset = &set;
sigemptyset(pset);
sigaddset(pset, SIGPROF);
}
assert(timeout >= -1);
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (;;) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
if (timeout != -1) {
spec.tv_sec = timeout / 1000;
spec.tv_nsec = (timeout % 1000) * 1000000;
}
/* Work around a kernel bug where nfds is not updated. */
events[0].portev_source = 0;
nfds = 1;
saved_errno = 0;
if (pset != NULL)
pthread_sigmask(SIG_BLOCK, pset, NULL);
err = port_getn(loop->backend_fd,
events,
ARRAY_SIZE(events),
&nfds,
timeout == -1 ? NULL : &spec);
if (pset != NULL)
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
if (err) {
/* Work around another kernel bug: port_getn() may return events even
* on error.
*/
if (errno == EINTR || errno == ETIME) {
saved_errno = errno;
} else {
perror("(libuv) port_getn()");
abort();
}
}
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
SAVE_ERRNO(uv__update_time(loop));
if (events[0].portev_source == 0) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
goto update_timeout;
}
if (nfds == 0) {
assert(timeout != -1);
return;
}
have_signals = 0;
nevents = 0;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->portev_object;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
w = loop->watchers[fd];
/* File descriptor that we've stopped watching, ignore. */
if (w == NULL)
continue;
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher) {
have_signals = 1;
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->portev_events);
}
nevents++;
if (w != loop->watchers[fd])
continue; /* Disabled by callback. */
/* Events Ports operates in oneshot mode, rearm timer on next run. */
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
}
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
timeout = 0;
continue;
}
return;
}
if (saved_errno == ETIME) {
assert(timeout != -1);
return;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
diff = loop->time - base;
if (diff >= (uint64_t) timeout)
return;
timeout -= diff;
}
}
uint64_t uv__hrtime(uv_clocktype_t type) {
return gethrtime();
}
/*
* We could use a static buffer for the path manipulations that we need outside
* of the function, but this function could be called by multiple consumers and
* we don't want to potentially create a race condition in the use of snprintf.
*/
int uv_exepath(char* buffer, size_t* size) {
ssize_t res;
char buf[128];
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
res = *size - 1;
if (res > 0)
res = readlink(buf, buffer, res);
if (res == -1)
return UV__ERR(errno);
buffer[res] = '\0';
*size = res;
return 0;
}
uint64_t uv_get_free_memory(void) {
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
}
uint64_t uv_get_total_memory(void) {
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}
void uv_loadavg(double avg[3]) {
(void) getloadavg(avg, 3);
}
#if defined(PORT_SOURCE_FILE)
static int uv__fs_event_rearm(uv_fs_event_t *handle) {
if (handle->fd == -1)
return UV_EBADF;
if (port_associate(handle->loop->fs_fd,
PORT_SOURCE_FILE,
(uintptr_t) &handle->fo,
FILE_ATTRIB | FILE_MODIFIED,
handle) == -1) {
return UV__ERR(errno);
}
handle->fd = PORT_LOADED;
return 0;
}
static void uv__fs_event_read(uv_loop_t* loop,
uv__io_t* w,
unsigned int revents) {
uv_fs_event_t *handle = NULL;
timespec_t timeout;
port_event_t pe;
int events;
int r;
(void) w;
(void) revents;
do {
uint_t n = 1;
/*
* Note that our use of port_getn() here (and not port_get()) is deliberate:
* there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
* causes port_get() to return success instead of ETIME when there aren't
* actually any events (!); by using port_getn() in lieu of port_get(),
* we can at least workaround the bug by checking for zero returned events
* and treating it as we would ETIME.
*/
do {
memset(&timeout, 0, sizeof timeout);
r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
}
while (r == -1 && errno == EINTR);
if ((r == -1 && errno == ETIME) || n == 0)
break;
handle = (uv_fs_event_t*) pe.portev_user;
assert((r == 0) && "unexpected port_get() error");
events = 0;
if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
events |= UV_CHANGE;
if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
events |= UV_RENAME;
assert(events != 0);
handle->fd = PORT_FIRED;
handle->cb(handle, NULL, events, 0);
if (handle->fd != PORT_DELETED) {
r = uv__fs_event_rearm(handle);
if (r != 0)
handle->cb(handle, NULL, 0, r);
}
}
while (handle->fd != PORT_DELETED);
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0;
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
const char* path,
unsigned int flags) {
int portfd;
int first_run;
int err;
if (uv__is_active(handle))
return UV_EINVAL;
first_run = 0;
if (handle->loop->fs_fd == -1) {
portfd = port_create();
if (portfd == -1)
return UV__ERR(errno);
handle->loop->fs_fd = portfd;
first_run = 1;
}
uv__handle_start(handle);
handle->path = uv__strdup(path);
handle->fd = PORT_UNUSED;
handle->cb = cb;
memset(&handle->fo, 0, sizeof handle->fo);
handle->fo.fo_name = handle->path;
err = uv__fs_event_rearm(handle);
if (err != 0) {
uv_fs_event_stop(handle);
return err;
}
if (first_run) {
uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN);
}
return 0;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
return 0;
if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
port_dissociate(handle->loop->fs_fd,
PORT_SOURCE_FILE,
(uintptr_t) &handle->fo);
}
handle->fd = PORT_DELETED;
uv__free(handle->path);
handle->path = NULL;
handle->fo.fo_name = NULL;
uv__handle_stop(handle);
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
}
#else /* !defined(PORT_SOURCE_FILE) */
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
return UV_ENOSYS;
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
const char* filename,
unsigned int flags) {
return UV_ENOSYS;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
return UV_ENOSYS;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
UNREACHABLE();
}
#endif /* defined(PORT_SOURCE_FILE) */
int uv_resident_set_memory(size_t* rss) {
psinfo_t psinfo;
int err;
int fd;
fd = open("/proc/self/psinfo", O_RDONLY);
if (fd == -1)
return UV__ERR(errno);
/* FIXME(bnoordhuis) Handle EINTR. */
err = UV_EINVAL;
if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
*rss = (size_t)psinfo.pr_rssize * 1024;
err = 0;
}
uv__close(fd);
return err;
}
int uv_uptime(double* uptime) {
kstat_ctl_t *kc;
kstat_t *ksp;
kstat_named_t *knp;
long hz = sysconf(_SC_CLK_TCK);
kc = kstat_open();
if (kc == NULL)
return UV_EPERM;
ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
if (kstat_read(kc, ksp, NULL) == -1) {
*uptime = -1;
} else {
knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr");
*uptime = knp->value.ul / hz;
}
kstat_close(kc);
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int lookup_instance;
kstat_ctl_t *kc;
kstat_t *ksp;
kstat_named_t *knp;
uv_cpu_info_t* cpu_info;
kc = kstat_open();
if (kc == NULL)
return UV_EPERM;
/* Get count of cpus */
lookup_instance = 0;
while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
lookup_instance++;
}
*cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos));
if (!(*cpu_infos)) {
kstat_close(kc);
return UV_ENOMEM;
}
*count = lookup_instance;
cpu_info = *cpu_infos;
lookup_instance = 0;
while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
if (kstat_read(kc, ksp, NULL) == -1) {
cpu_info->speed = 0;
cpu_info->model = NULL;
} else {
knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
assert(knp->data_type == KSTAT_DATA_INT32 ||
knp->data_type == KSTAT_DATA_INT64);
cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
: knp->value.i64;
knp = kstat_data_lookup(ksp, (char*) "brand");
assert(knp->data_type == KSTAT_DATA_STRING);
cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp));
}
lookup_instance++;
cpu_info++;
}
cpu_info = *cpu_infos;
lookup_instance = 0;
for (;;) {
ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
if (ksp == NULL)
break;
if (kstat_read(kc, ksp, NULL) == -1) {
cpu_info->cpu_times.user = 0;
cpu_info->cpu_times.nice = 0;
cpu_info->cpu_times.sys = 0;
cpu_info->cpu_times.idle = 0;
cpu_info->cpu_times.irq = 0;
} else {
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
assert(knp->data_type == KSTAT_DATA_UINT64);
cpu_info->cpu_times.user = knp->value.ui64;
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
assert(knp->data_type == KSTAT_DATA_UINT64);
cpu_info->cpu_times.sys = knp->value.ui64;
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
assert(knp->data_type == KSTAT_DATA_UINT64);
cpu_info->cpu_times.idle = knp->value.ui64;
knp = kstat_data_lookup(ksp, (char*) "intr");
assert(knp->data_type == KSTAT_DATA_UINT64);
cpu_info->cpu_times.irq = knp->value.ui64;
cpu_info->cpu_times.nice = 0;
}
lookup_instance++;
cpu_info++;
}
kstat_close(kc);
return 0;
}
#ifdef SUNOS_NO_IFADDRS
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
*count = 0;
*addresses = NULL;
return UV_ENOSYS;
}
#else /* SUNOS_NO_IFADDRS */
/*
* Inspired By:
* https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
* http://www.pauliesworld.org/project/getmac.c
*/
static int uv__set_phys_addr(uv_interface_address_t* address,
struct ifaddrs* ent) {
struct sockaddr_dl* sa_addr;
int sockfd;
size_t i;
struct arpreq arpreq;
/* This appears to only work as root */
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
for (i = 0; i < sizeof(address->phys_addr); i++) {
/* Check that all bytes of phys_addr are zero. */
if (address->phys_addr[i] != 0)
return 0;
}
memset(&arpreq, 0, sizeof(arpreq));
if (address->address.address4.sin_family == AF_INET) {
struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa);
sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr;
} else if (address->address.address4.sin_family == AF_INET6) {
struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa);
memcpy(sin->sin6_addr.s6_addr,
address->address.address6.sin6_addr.s6_addr,
sizeof(address->address.address6.sin6_addr.s6_addr));
} else {
return 0;
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
return UV__ERR(errno);
if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) {
uv__close(sockfd);
return UV__ERR(errno);
}
memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr));
uv__close(sockfd);
return 0;
}
static int uv__ifaddr_exclude(struct ifaddrs *ent) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
return 1;
if (ent->ifa_addr == NULL)
return 1;
if (ent->ifa_addr->sa_family != AF_INET &&
ent->ifa_addr->sa_family != AF_INET6)
return 1;
return 0;
}
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
struct ifaddrs* addrs;
struct ifaddrs* ent;
*count = 0;
*addresses = NULL;
if (getifaddrs(&addrs))
return UV__ERR(errno);
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent))
continue;
(*count)++;
}
if (*count == 0) {
freeifaddrs(addrs);
return 0;
}
*addresses = uv__malloc(*count * sizeof(**addresses));
if (!(*addresses)) {
freeifaddrs(addrs);
return UV_ENOMEM;
}
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent))
continue;
address->name = uv__strdup(ent->ifa_name);
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
} else {
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
}
address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
(ent->ifa_flags & IFF_LOOPBACK));
uv__set_phys_addr(address, ent);
address++;
}
freeifaddrs(addrs);
return 0;
}
#endif /* SUNOS_NO_IFADDRS */
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; i++) {
uv__free(addresses[i].name);
}
uv__free(addresses);
}

36
deps/libuv/src/unix/sysinfo-loadavg.c vendored Normal file
View File

@ -0,0 +1,36 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdint.h>
#include <sys/sysinfo.h>
void uv_loadavg(double avg[3]) {
struct sysinfo info;
if (sysinfo(&info) < 0) return;
avg[0] = (double) info.loads[0] / 65536.0;
avg[1] = (double) info.loads[1] / 65536.0;
avg[2] = (double) info.loads[2] / 65536.0;
}

42
deps/libuv/src/unix/sysinfo-memory.c vendored Normal file
View File

@ -0,0 +1,42 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdint.h>
#include <sys/sysinfo.h>
uint64_t uv_get_free_memory(void) {
struct sysinfo info;
if (sysinfo(&info) == 0)
return (uint64_t) info.freeram * info.mem_unit;
return 0;
}
uint64_t uv_get_total_memory(void) {
struct sysinfo info;
if (sysinfo(&info) == 0)
return (uint64_t) info.totalram * info.mem_unit;
return 0;
}

461
deps/libuv/src/unix/tcp.c vendored Normal file
View File

@ -0,0 +1,461 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
struct sockaddr_storage saddr;
socklen_t slen;
int sockfd;
int err;
err = uv__socket(domain, SOCK_STREAM, 0);
if (err < 0)
return err;
sockfd = err;
err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
if (err) {
uv__close(sockfd);
return err;
}
if (flags & UV_HANDLE_BOUND) {
/* Bind this new socket to an arbitrary port */
slen = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) {
uv__close(sockfd);
return UV__ERR(errno);
}
if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) {
uv__close(sockfd);
return UV__ERR(errno);
}
}
return 0;
}
static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
struct sockaddr_storage saddr;
socklen_t slen;
if (domain == AF_UNSPEC) {
handle->flags |= flags;
return 0;
}
if (uv__stream_fd(handle) != -1) {
if (flags & UV_HANDLE_BOUND) {
if (handle->flags & UV_HANDLE_BOUND) {
/* It is already bound to a port. */
handle->flags |= flags;
return 0;
}
/* Query to see if tcp socket is bound. */
slen = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
return UV__ERR(errno);
if ((saddr.ss_family == AF_INET6 &&
((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
(saddr.ss_family == AF_INET &&
((struct sockaddr_in*) &saddr)->sin_port != 0)) {
/* Handle is already bound to a port. */
handle->flags |= flags;
return 0;
}
/* Bind to arbitrary port */
if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
return UV__ERR(errno);
}
handle->flags |= flags;
return 0;
}
return new_socket(handle, domain, flags);
}
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
int domain;
/* Use the lower 8 bits for the domain */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return UV_EINVAL;
if (flags & ~0xFF)
return UV_EINVAL;
uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
/* If anything fails beyond this point we need to remove the handle from
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
*/
if (domain != AF_UNSPEC) {
int err = maybe_new_socket(tcp, domain, 0);
if (err) {
QUEUE_REMOVE(&tcp->handle_queue);
return err;
}
}
return 0;
}
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
}
int uv__tcp_bind(uv_tcp_t* tcp,
const struct sockaddr* addr,
unsigned int addrlen,
unsigned int flags) {
int err;
int on;
/* Cannot set IPv6-only mode on non-IPv6 socket. */
if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
return UV_EINVAL;
err = maybe_new_socket(tcp, addr->sa_family, 0);
if (err)
return err;
on = 1;
if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
return UV__ERR(errno);
#ifndef __OpenBSD__
#ifdef IPV6_V6ONLY
if (addr->sa_family == AF_INET6) {
on = (flags & UV_TCP_IPV6ONLY) != 0;
if (setsockopt(tcp->io_watcher.fd,
IPPROTO_IPV6,
IPV6_V6ONLY,
&on,
sizeof on) == -1) {
#if defined(__MVS__)
if (errno == EOPNOTSUPP)
return UV_EINVAL;
#endif
return UV__ERR(errno);
}
}
#endif
#endif
errno = 0;
if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
if (errno == EAFNOSUPPORT)
/* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
* socket created with AF_INET to an AF_INET6 address or vice versa. */
return UV_EINVAL;
return UV__ERR(errno);
}
tcp->delayed_error = UV__ERR(errno);
tcp->flags |= UV_HANDLE_BOUND;
if (addr->sa_family == AF_INET6)
tcp->flags |= UV_HANDLE_IPV6;
return 0;
}
int uv__tcp_connect(uv_connect_t* req,
uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen,
uv_connect_cb cb) {
int err;
int r;
assert(handle->type == UV_TCP);
if (handle->connect_req != NULL)
return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
err = maybe_new_socket(handle,
addr->sa_family,
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
if (err)
return err;
handle->delayed_error = 0;
do {
errno = 0;
r = connect(uv__stream_fd(handle), addr, addrlen);
} while (r == -1 && errno == EINTR);
/* We not only check the return value, but also check the errno != 0.
* Because in rare cases connect() will return -1 but the errno
* is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
* and actually the tcp three-way handshake is completed.
*/
if (r == -1 && errno != 0) {
if (errno == EINPROGRESS)
; /* not an error */
else if (errno == ECONNREFUSED
#if defined(__OpenBSD__)
|| errno == EINVAL
#endif
)
/* If we get ECONNREFUSED (Solaris) or EINVAL (OpenBSD) wait until the
* next tick to report the error. Solaris and OpenBSD wants to report
* immediately -- other unixes want to wait.
*/
handle->delayed_error = UV__ERR(ECONNREFUSED);
else
return UV__ERR(errno);
}
uv__req_init(handle->loop, req, UV_CONNECT);
req->cb = cb;
req->handle = (uv_stream_t*) handle;
QUEUE_INIT(&req->queue);
handle->connect_req = req;
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
if (handle->delayed_error)
uv__io_feed(handle->loop, &handle->io_watcher);
return 0;
}
int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
int err;
if (uv__fd_exists(handle->loop, sock))
return UV_EEXIST;
err = uv__nonblock(sock, 1);
if (err)
return err;
return uv__stream_open((uv_stream_t*)handle,
sock,
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
}
int uv_tcp_getsockname(const uv_tcp_t* handle,
struct sockaddr* name,
int* namelen) {
if (handle->delayed_error)
return handle->delayed_error;
return uv__getsockpeername((const uv_handle_t*) handle,
getsockname,
name,
namelen);
}
int uv_tcp_getpeername(const uv_tcp_t* handle,
struct sockaddr* name,
int* namelen) {
if (handle->delayed_error)
return handle->delayed_error;
return uv__getsockpeername((const uv_handle_t*) handle,
getpeername,
name,
namelen);
}
int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
int fd;
struct linger l = { 1, 0 };
/* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
if (handle->flags & UV_HANDLE_SHUTTING)
return UV_EINVAL;
fd = uv__stream_fd(handle);
if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)))
return UV__ERR(errno);
uv_close((uv_handle_t*) handle, close_cb);
return 0;
}
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
static int single_accept_cached = -1;
unsigned long flags;
int single_accept;
int err;
if (tcp->delayed_error)
return tcp->delayed_error;
single_accept = uv__load_relaxed(&single_accept_cached);
if (single_accept == -1) {
const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
uv__store_relaxed(&single_accept_cached, single_accept);
}
if (single_accept)
tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
flags = 0;
#if defined(__MVS__)
/* on zOS the listen call does not bind automatically
if the socket is unbound. Hence the manual binding to
an arbitrary port is required to be done manually
*/
flags |= UV_HANDLE_BOUND;
#endif
err = maybe_new_socket(tcp, AF_INET, flags);
if (err)
return err;
if (listen(tcp->io_watcher.fd, backlog))
return UV__ERR(errno);
tcp->connection_cb = cb;
tcp->flags |= UV_HANDLE_BOUND;
/* Start listening for connections. */
tcp->io_watcher.cb = uv__server_io;
uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);
return 0;
}
int uv__tcp_nodelay(int fd, int on) {
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
return UV__ERR(errno);
return 0;
}
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
return UV__ERR(errno);
#ifdef TCP_KEEPIDLE
if (on) {
int intvl = 1; /* 1 second; same as default on Win32 */
int cnt = 10; /* 10 retries; same as hardcoded on Win32 */
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
return UV__ERR(errno);
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
return UV__ERR(errno);
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
return UV__ERR(errno);
}
#endif
/* Solaris/SmartOS, if you don't support keep-alive,
* then don't advertise it in your system headers...
*/
/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
#if defined(TCP_KEEPALIVE) && !defined(__sun)
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
return UV__ERR(errno);
#endif
return 0;
}
int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
int err;
if (uv__stream_fd(handle) != -1) {
err = uv__tcp_nodelay(uv__stream_fd(handle), on);
if (err)
return err;
}
if (on)
handle->flags |= UV_HANDLE_TCP_NODELAY;
else
handle->flags &= ~UV_HANDLE_TCP_NODELAY;
return 0;
}
int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
int err;
if (uv__stream_fd(handle) != -1) {
err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
if (err)
return err;
}
if (on)
handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
else
handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
/* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
* uv_tcp_t with an int that's almost never used...
*/
return 0;
}
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
if (enable)
handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
else
handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
return 0;
}
void uv__tcp_close(uv_tcp_t* handle) {
uv__stream_close((uv_stream_t*)handle);
}

842
deps/libuv/src/unix/thread.c vendored Normal file
View File

@ -0,0 +1,842 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <pthread.h>
#include <assert.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h> /* getrlimit() */
#include <unistd.h> /* getpagesize() */
#include <limits.h>
#ifdef __MVS__
#include <sys/ipc.h>
#include <sys/sem.h>
#endif
#if defined(__GLIBC__) && !defined(__UCLIBC__)
#include <gnu/libc-version.h> /* gnu_get_libc_version() */
#endif
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
#if defined(PTHREAD_BARRIER_SERIAL_THREAD)
STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
#endif
/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */
#if defined(_AIX) || \
defined(__OpenBSD__) || \
!defined(PTHREAD_BARRIER_SERIAL_THREAD)
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
struct _uv_barrier* b;
int rc;
if (barrier == NULL || count == 0)
return UV_EINVAL;
b = uv__malloc(sizeof(*b));
if (b == NULL)
return UV_ENOMEM;
b->in = 0;
b->out = 0;
b->threshold = count;
rc = uv_mutex_init(&b->mutex);
if (rc != 0)
goto error2;
rc = uv_cond_init(&b->cond);
if (rc != 0)
goto error;
barrier->b = b;
return 0;
error:
uv_mutex_destroy(&b->mutex);
error2:
uv__free(b);
return rc;
}
int uv_barrier_wait(uv_barrier_t* barrier) {
struct _uv_barrier* b;
int last;
if (barrier == NULL || barrier->b == NULL)
return UV_EINVAL;
b = barrier->b;
uv_mutex_lock(&b->mutex);
if (++b->in == b->threshold) {
b->in = 0;
b->out = b->threshold;
uv_cond_signal(&b->cond);
} else {
do
uv_cond_wait(&b->cond, &b->mutex);
while (b->in != 0);
}
last = (--b->out == 0);
if (!last)
uv_cond_signal(&b->cond); /* Not needed for last thread. */
uv_mutex_unlock(&b->mutex);
return last;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
struct _uv_barrier* b;
b = barrier->b;
uv_mutex_lock(&b->mutex);
assert(b->in == 0);
assert(b->out == 0);
if (b->in != 0 || b->out != 0)
abort();
uv_mutex_unlock(&b->mutex);
uv_mutex_destroy(&b->mutex);
uv_cond_destroy(&b->cond);
uv__free(barrier->b);
barrier->b = NULL;
}
#else
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
}
int uv_barrier_wait(uv_barrier_t* barrier) {
int rc;
rc = pthread_barrier_wait(barrier);
if (rc != 0)
if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
abort();
return rc == PTHREAD_BARRIER_SERIAL_THREAD;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
if (pthread_barrier_destroy(barrier))
abort();
}
#endif
/* On MacOS, threads other than the main thread are created with a reduced
* stack size by default. Adjust to RLIMIT_STACK aligned to the page size.
*
* On Linux, threads created by musl have a much smaller stack than threads
* created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
*/
static size_t thread_stack_size(void) {
#if defined(__APPLE__) || defined(__linux__)
struct rlimit lim;
/* getrlimit() can fail on some aarch64 systems due to a glibc bug where
* the system call wrapper invokes the wrong system call. Don't treat
* that as fatal, just use the default stack size instead.
*/
if (0 == getrlimit(RLIMIT_STACK, &lim) && lim.rlim_cur != RLIM_INFINITY) {
/* pthread_attr_setstacksize() expects page-aligned values. */
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
* too small to safely receive signals on.
*
* Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has
* the largest MINSIGSTKSZ of the architectures that musl supports) so
* let's use that as a lower bound.
*
* We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ
* is between 28 and 133 KB when compiling against glibc, depending
* on the architecture.
*/
if (lim.rlim_cur >= 8192)
if (lim.rlim_cur >= PTHREAD_STACK_MIN)
return lim.rlim_cur;
}
#endif
#if !defined(__linux__)
return 0;
#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
return 4 << 20; /* glibc default. */
#else
return 2 << 20; /* glibc default. */
#endif
}
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
uv_thread_options_t params;
params.flags = UV_THREAD_NO_FLAGS;
return uv_thread_create_ex(tid, &params, entry, arg);
}
int uv_thread_create_ex(uv_thread_t* tid,
const uv_thread_options_t* params,
void (*entry)(void *arg),
void *arg) {
int err;
pthread_attr_t* attr;
pthread_attr_t attr_storage;
size_t pagesize;
size_t stack_size;
/* Used to squelch a -Wcast-function-type warning. */
union {
void (*in)(void*);
void* (*out)(void*);
} f;
stack_size =
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
attr = NULL;
if (stack_size == 0) {
stack_size = thread_stack_size();
} else {
pagesize = (size_t)getpagesize();
/* Round up to the nearest page boundary. */
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
#ifdef PTHREAD_STACK_MIN
if (stack_size < PTHREAD_STACK_MIN)
stack_size = PTHREAD_STACK_MIN;
#endif
}
if (stack_size > 0) {
attr = &attr_storage;
if (pthread_attr_init(attr))
abort();
if (pthread_attr_setstacksize(attr, stack_size))
abort();
}
f.in = entry;
err = pthread_create(tid, attr, f.out, arg);
if (attr != NULL)
pthread_attr_destroy(attr);
return UV__ERR(err);
}
uv_thread_t uv_thread_self(void) {
return pthread_self();
}
int uv_thread_join(uv_thread_t *tid) {
return UV__ERR(pthread_join(*tid, NULL));
}
int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
return pthread_equal(*t1, *t2);
}
int uv_mutex_init(uv_mutex_t* mutex) {
#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
return UV__ERR(pthread_mutex_init(mutex, NULL));
#else
pthread_mutexattr_t attr;
int err;
if (pthread_mutexattr_init(&attr))
abort();
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
abort();
err = pthread_mutex_init(mutex, &attr);
if (pthread_mutexattr_destroy(&attr))
abort();
return UV__ERR(err);
#endif
}
int uv_mutex_init_recursive(uv_mutex_t* mutex) {
pthread_mutexattr_t attr;
int err;
if (pthread_mutexattr_init(&attr))
abort();
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
abort();
err = pthread_mutex_init(mutex, &attr);
if (pthread_mutexattr_destroy(&attr))
abort();
return UV__ERR(err);
}
void uv_mutex_destroy(uv_mutex_t* mutex) {
if (pthread_mutex_destroy(mutex))
abort();
}
void uv_mutex_lock(uv_mutex_t* mutex) {
if (pthread_mutex_lock(mutex))
abort();
}
int uv_mutex_trylock(uv_mutex_t* mutex) {
int err;
err = pthread_mutex_trylock(mutex);
if (err) {
if (err != EBUSY && err != EAGAIN)
abort();
return UV_EBUSY;
}
return 0;
}
void uv_mutex_unlock(uv_mutex_t* mutex) {
if (pthread_mutex_unlock(mutex))
abort();
}
int uv_rwlock_init(uv_rwlock_t* rwlock) {
return UV__ERR(pthread_rwlock_init(rwlock, NULL));
}
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
if (pthread_rwlock_destroy(rwlock))
abort();
}
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
if (pthread_rwlock_rdlock(rwlock))
abort();
}
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
int err;
err = pthread_rwlock_tryrdlock(rwlock);
if (err) {
if (err != EBUSY && err != EAGAIN)
abort();
return UV_EBUSY;
}
return 0;
}
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
if (pthread_rwlock_unlock(rwlock))
abort();
}
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
if (pthread_rwlock_wrlock(rwlock))
abort();
}
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
int err;
err = pthread_rwlock_trywrlock(rwlock);
if (err) {
if (err != EBUSY && err != EAGAIN)
abort();
return UV_EBUSY;
}
return 0;
}
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
if (pthread_rwlock_unlock(rwlock))
abort();
}
void uv_once(uv_once_t* guard, void (*callback)(void)) {
if (pthread_once(guard, callback))
abort();
}
#if defined(__APPLE__) && defined(__MACH__)
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
kern_return_t err;
err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
if (err == KERN_SUCCESS)
return 0;
if (err == KERN_INVALID_ARGUMENT)
return UV_EINVAL;
if (err == KERN_RESOURCE_SHORTAGE)
return UV_ENOMEM;
abort();
return UV_EINVAL; /* Satisfy the compiler. */
}
void uv_sem_destroy(uv_sem_t* sem) {
if (semaphore_destroy(mach_task_self(), *sem))
abort();
}
void uv_sem_post(uv_sem_t* sem) {
if (semaphore_signal(*sem))
abort();
}
void uv_sem_wait(uv_sem_t* sem) {
int r;
do
r = semaphore_wait(*sem);
while (r == KERN_ABORTED);
if (r != KERN_SUCCESS)
abort();
}
int uv_sem_trywait(uv_sem_t* sem) {
mach_timespec_t interval;
kern_return_t err;
interval.tv_sec = 0;
interval.tv_nsec = 0;
err = semaphore_timedwait(*sem, interval);
if (err == KERN_SUCCESS)
return 0;
if (err == KERN_OPERATION_TIMED_OUT)
return UV_EAGAIN;
abort();
return UV_EINVAL; /* Satisfy the compiler. */
}
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
#if defined(__GLIBC__) && !defined(__UCLIBC__)
/* Hack around https://sourceware.org/bugzilla/show_bug.cgi?id=12674
* by providing a custom implementation for glibc < 2.21 in terms of other
* concurrency primitives.
* Refs: https://github.com/nodejs/node/issues/19903 */
/* To preserve ABI compatibility, we treat the uv_sem_t as storage for
* a pointer to the actual struct we're using underneath. */
static uv_once_t glibc_version_check_once = UV_ONCE_INIT;
static int platform_needs_custom_semaphore = 0;
static void glibc_version_check(void) {
const char* version = gnu_get_libc_version();
platform_needs_custom_semaphore =
version[0] == '2' && version[1] == '.' &&
atoi(version + 2) < 21;
}
#elif defined(__MVS__)
#define platform_needs_custom_semaphore 1
#else /* !defined(__GLIBC__) && !defined(__MVS__) */
#define platform_needs_custom_semaphore 0
#endif
typedef struct uv_semaphore_s {
uv_mutex_t mutex;
uv_cond_t cond;
unsigned int value;
} uv_semaphore_t;
#if (defined(__GLIBC__) && !defined(__UCLIBC__)) || \
platform_needs_custom_semaphore
STATIC_ASSERT(sizeof(uv_sem_t) >= sizeof(uv_semaphore_t*));
#endif
static int uv__custom_sem_init(uv_sem_t* sem_, unsigned int value) {
int err;
uv_semaphore_t* sem;
sem = uv__malloc(sizeof(*sem));
if (sem == NULL)
return UV_ENOMEM;
if ((err = uv_mutex_init(&sem->mutex)) != 0) {
uv__free(sem);
return err;
}
if ((err = uv_cond_init(&sem->cond)) != 0) {
uv_mutex_destroy(&sem->mutex);
uv__free(sem);
return err;
}
sem->value = value;
*(uv_semaphore_t**)sem_ = sem;
return 0;
}
static void uv__custom_sem_destroy(uv_sem_t* sem_) {
uv_semaphore_t* sem;
sem = *(uv_semaphore_t**)sem_;
uv_cond_destroy(&sem->cond);
uv_mutex_destroy(&sem->mutex);
uv__free(sem);
}
static void uv__custom_sem_post(uv_sem_t* sem_) {
uv_semaphore_t* sem;
sem = *(uv_semaphore_t**)sem_;
uv_mutex_lock(&sem->mutex);
sem->value++;
if (sem->value == 1)
uv_cond_signal(&sem->cond);
uv_mutex_unlock(&sem->mutex);
}
static void uv__custom_sem_wait(uv_sem_t* sem_) {
uv_semaphore_t* sem;
sem = *(uv_semaphore_t**)sem_;
uv_mutex_lock(&sem->mutex);
while (sem->value == 0)
uv_cond_wait(&sem->cond, &sem->mutex);
sem->value--;
uv_mutex_unlock(&sem->mutex);
}
static int uv__custom_sem_trywait(uv_sem_t* sem_) {
uv_semaphore_t* sem;
sem = *(uv_semaphore_t**)sem_;
if (uv_mutex_trylock(&sem->mutex) != 0)
return UV_EAGAIN;
if (sem->value == 0) {
uv_mutex_unlock(&sem->mutex);
return UV_EAGAIN;
}
sem->value--;
uv_mutex_unlock(&sem->mutex);
return 0;
}
static int uv__sem_init(uv_sem_t* sem, unsigned int value) {
if (sem_init(sem, 0, value))
return UV__ERR(errno);
return 0;
}
static void uv__sem_destroy(uv_sem_t* sem) {
if (sem_destroy(sem))
abort();
}
static void uv__sem_post(uv_sem_t* sem) {
if (sem_post(sem))
abort();
}
static void uv__sem_wait(uv_sem_t* sem) {
int r;
do
r = sem_wait(sem);
while (r == -1 && errno == EINTR);
if (r)
abort();
}
static int uv__sem_trywait(uv_sem_t* sem) {
int r;
do
r = sem_trywait(sem);
while (r == -1 && errno == EINTR);
if (r) {
if (errno == EAGAIN)
return UV_EAGAIN;
abort();
}
return 0;
}
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
#if defined(__GLIBC__) && !defined(__UCLIBC__)
uv_once(&glibc_version_check_once, glibc_version_check);
#endif
if (platform_needs_custom_semaphore)
return uv__custom_sem_init(sem, value);
else
return uv__sem_init(sem, value);
}
void uv_sem_destroy(uv_sem_t* sem) {
if (platform_needs_custom_semaphore)
uv__custom_sem_destroy(sem);
else
uv__sem_destroy(sem);
}
void uv_sem_post(uv_sem_t* sem) {
if (platform_needs_custom_semaphore)
uv__custom_sem_post(sem);
else
uv__sem_post(sem);
}
void uv_sem_wait(uv_sem_t* sem) {
if (platform_needs_custom_semaphore)
uv__custom_sem_wait(sem);
else
uv__sem_wait(sem);
}
int uv_sem_trywait(uv_sem_t* sem) {
if (platform_needs_custom_semaphore)
return uv__custom_sem_trywait(sem);
else
return uv__sem_trywait(sem);
}
#endif /* defined(__APPLE__) && defined(__MACH__) */
#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__)
int uv_cond_init(uv_cond_t* cond) {
return UV__ERR(pthread_cond_init(cond, NULL));
}
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
int uv_cond_init(uv_cond_t* cond) {
pthread_condattr_t attr;
int err;
err = pthread_condattr_init(&attr);
if (err)
return UV__ERR(err);
err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
if (err)
goto error2;
err = pthread_cond_init(cond, &attr);
if (err)
goto error2;
err = pthread_condattr_destroy(&attr);
if (err)
goto error;
return 0;
error:
pthread_cond_destroy(cond);
error2:
pthread_condattr_destroy(&attr);
return UV__ERR(err);
}
#endif /* defined(__APPLE__) && defined(__MACH__) */
void uv_cond_destroy(uv_cond_t* cond) {
#if defined(__APPLE__) && defined(__MACH__)
/* It has been reported that destroying condition variables that have been
* signalled but not waited on can sometimes result in application crashes.
* See https://codereview.chromium.org/1323293005.
*/
pthread_mutex_t mutex;
struct timespec ts;
int err;
if (pthread_mutex_init(&mutex, NULL))
abort();
if (pthread_mutex_lock(&mutex))
abort();
ts.tv_sec = 0;
ts.tv_nsec = 1;
err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts);
if (err != 0 && err != ETIMEDOUT)
abort();
if (pthread_mutex_unlock(&mutex))
abort();
if (pthread_mutex_destroy(&mutex))
abort();
#endif /* defined(__APPLE__) && defined(__MACH__) */
if (pthread_cond_destroy(cond))
abort();
}
void uv_cond_signal(uv_cond_t* cond) {
if (pthread_cond_signal(cond))
abort();
}
void uv_cond_broadcast(uv_cond_t* cond) {
if (pthread_cond_broadcast(cond))
abort();
}
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
if (pthread_cond_wait(cond, mutex))
abort();
}
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
int r;
struct timespec ts;
#if defined(__MVS__)
struct timeval tv;
#endif
#if defined(__APPLE__) && defined(__MACH__)
ts.tv_sec = timeout / NANOSEC;
ts.tv_nsec = timeout % NANOSEC;
r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
#else
#if defined(__MVS__)
if (gettimeofday(&tv, NULL))
abort();
timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3;
#else
timeout += uv__hrtime(UV_CLOCK_PRECISE);
#endif
ts.tv_sec = timeout / NANOSEC;
ts.tv_nsec = timeout % NANOSEC;
r = pthread_cond_timedwait(cond, mutex, &ts);
#endif
if (r == 0)
return 0;
if (r == ETIMEDOUT)
return UV_ETIMEDOUT;
abort();
#ifndef __SUNPRO_C
return UV_EINVAL; /* Satisfy the compiler. */
#endif
}
int uv_key_create(uv_key_t* key) {
return UV__ERR(pthread_key_create(key, NULL));
}
void uv_key_delete(uv_key_t* key) {
if (pthread_key_delete(*key))
abort();
}
void* uv_key_get(uv_key_t* key) {
return pthread_getspecific(*key);
}
void uv_key_set(uv_key_t* key, void* value) {
if (pthread_setspecific(*key, value))
abort();
}

402
deps/libuv/src/unix/tty.c vendored Normal file
View File

@ -0,0 +1,402 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include "spinlock.h"
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#if defined(__MVS__) && !defined(IMAXBEL)
#define IMAXBEL 0
#endif
#if defined(__PASE__)
/* On IBM i PASE, for better compatibility with running interactive programs in
* a 5250 environment, isatty() will return true for the stdin/stdout/stderr
* streams created by QSH/QP2TERM.
*
* For more, see docs on PASE_STDIO_ISATTY in
* https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/apis/pase_environ.htm
*
* This behavior causes problems for Node as it expects that if isatty() returns
* true that TTY ioctls will be supported by that fd (which is not an
* unreasonable expectation) and when they don't it crashes with assertion
* errors.
*
* Here, we create our own version of isatty() that uses ioctl() to identify
* whether the fd is *really* a TTY or not.
*/
static int isreallyatty(int file) {
int rc;
rc = !ioctl(file, TXISATTY + 0x81, NULL);
if (!rc && errno != EBADF)
errno = ENOTTY;
return rc;
}
#define isatty(fd) isreallyatty(fd)
#endif
static int orig_termios_fd = -1;
static struct termios orig_termios;
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
static int uv__tty_is_slave(const int fd) {
int result;
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
int dummy;
result = ioctl(fd, TIOCGPTN, &dummy) != 0;
#elif defined(__APPLE__)
char dummy[256];
result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
#elif defined(__NetBSD__)
/*
* NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave
* device name for both descriptors, the master one and slave one.
*
* Implement function to compare major device number with pts devices.
*
* The major numbers are machine-dependent, on NetBSD/amd64 they are
* respectively:
* - master tty: ptc - major 6
* - slave tty: pts - major 5
*/
struct stat sb;
/* Lookup device's major for the pts driver and cache it. */
static devmajor_t pts = NODEVMAJOR;
if (pts == NODEVMAJOR) {
pts = getdevmajor("pts", S_IFCHR);
if (pts == NODEVMAJOR)
abort();
}
/* Lookup stat structure behind the file descriptor. */
if (fstat(fd, &sb) != 0)
abort();
/* Assert character device. */
if (!S_ISCHR(sb.st_mode))
abort();
/* Assert valid major. */
if (major(sb.st_rdev) == NODEVMAJOR)
abort();
result = (pts == major(sb.st_rdev));
#else
/* Fallback to ptsname
*/
result = ptsname(fd) == NULL;
#endif
return result;
}
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
uv_handle_type type;
int flags;
int newfd;
int r;
int saved_flags;
int mode;
char path[256];
(void)unused; /* deprecated parameter is no longer needed */
/* File descriptors that refer to files cannot be monitored with epoll.
* That restriction also applies to character devices like /dev/random
* (but obviously not /dev/tty.)
*/
type = uv_guess_handle(fd);
if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
return UV_EINVAL;
flags = 0;
newfd = -1;
/* Save the fd flags in case we need to restore them due to an error. */
do
saved_flags = fcntl(fd, F_GETFL);
while (saved_flags == -1 && errno == EINTR);
if (saved_flags == -1)
return UV__ERR(errno);
mode = saved_flags & O_ACCMODE;
/* Reopen the file descriptor when it refers to a tty. This lets us put the
* tty in non-blocking mode without affecting other processes that share it
* with us.
*
* Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
* affects fd 1 of `cat` because both file descriptors refer to the same
* struct file in the kernel. When we reopen our fd 0, it points to a
* different struct file, hence changing its properties doesn't affect
* other processes.
*/
if (type == UV_TTY) {
/* Reopening a pty in master mode won't work either because the reopened
* pty will be in slave mode (*BSD) or reopening will allocate a new
* master/slave pair (Linux). Therefore check if the fd points to a
* slave device.
*/
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
r = uv__open_cloexec(path, mode | O_NOCTTY);
else
r = -1;
if (r < 0) {
/* fallback to using blocking writes */
if (mode != O_RDONLY)
flags |= UV_HANDLE_BLOCKING_WRITES;
goto skip;
}
newfd = r;
r = uv__dup2_cloexec(newfd, fd);
if (r < 0 && r != UV_EINVAL) {
/* EINVAL means newfd == fd which could conceivably happen if another
* thread called close(fd) between our calls to isatty() and open().
* That's a rather unlikely event but let's handle it anyway.
*/
uv__close(newfd);
return r;
}
fd = newfd;
}
skip:
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
/* If anything fails beyond this point we need to remove the handle from
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
*/
if (!(flags & UV_HANDLE_BLOCKING_WRITES))
uv__nonblock(fd, 1);
#if defined(__APPLE__)
r = uv__stream_try_select((uv_stream_t*) tty, &fd);
if (r) {
int rc = r;
if (newfd != -1)
uv__close(newfd);
QUEUE_REMOVE(&tty->handle_queue);
do
r = fcntl(fd, F_SETFL, saved_flags);
while (r == -1 && errno == EINTR);
return rc;
}
#endif
if (mode != O_WRONLY)
flags |= UV_HANDLE_READABLE;
if (mode != O_RDONLY)
flags |= UV_HANDLE_WRITABLE;
uv__stream_open((uv_stream_t*) tty, fd, flags);
tty->mode = UV_TTY_MODE_NORMAL;
return 0;
}
static void uv__tty_make_raw(struct termios* tio) {
assert(tio != NULL);
#if defined __sun || defined __MVS__
/*
* This implementation of cfmakeraw for Solaris and derivatives is taken from
* http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
*/
tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
IGNCR | ICRNL | IXON);
tio->c_oflag &= ~OPOST;
tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tio->c_cflag &= ~(CSIZE | PARENB);
tio->c_cflag |= CS8;
#else
cfmakeraw(tio);
#endif /* #ifdef __sun */
}
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
struct termios tmp;
int fd;
if (tty->mode == (int) mode)
return 0;
fd = uv__stream_fd(tty);
if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
if (tcgetattr(fd, &tty->orig_termios))
return UV__ERR(errno);
/* This is used for uv_tty_reset_mode() */
uv_spinlock_lock(&termios_spinlock);
if (orig_termios_fd == -1) {
orig_termios = tty->orig_termios;
orig_termios_fd = fd;
}
uv_spinlock_unlock(&termios_spinlock);
}
tmp = tty->orig_termios;
switch (mode) {
case UV_TTY_MODE_NORMAL:
break;
case UV_TTY_MODE_RAW:
tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
tmp.c_oflag |= (ONLCR);
tmp.c_cflag |= (CS8);
tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
tmp.c_cc[VMIN] = 1;
tmp.c_cc[VTIME] = 0;
break;
case UV_TTY_MODE_IO:
uv__tty_make_raw(&tmp);
break;
}
/* Apply changes after draining */
if (tcsetattr(fd, TCSADRAIN, &tmp))
return UV__ERR(errno);
tty->mode = mode;
return 0;
}
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
struct winsize ws;
int err;
do
err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws);
while (err == -1 && errno == EINTR);
if (err == -1)
return UV__ERR(errno);
*width = ws.ws_col;
*height = ws.ws_row;
return 0;
}
uv_handle_type uv_guess_handle(uv_file file) {
struct sockaddr sa;
struct stat s;
socklen_t len;
int type;
if (file < 0)
return UV_UNKNOWN_HANDLE;
if (isatty(file))
return UV_TTY;
if (fstat(file, &s))
return UV_UNKNOWN_HANDLE;
if (S_ISREG(s.st_mode))
return UV_FILE;
if (S_ISCHR(s.st_mode))
return UV_FILE; /* XXX UV_NAMED_PIPE? */
if (S_ISFIFO(s.st_mode))
return UV_NAMED_PIPE;
if (!S_ISSOCK(s.st_mode))
return UV_UNKNOWN_HANDLE;
len = sizeof(type);
if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
return UV_UNKNOWN_HANDLE;
len = sizeof(sa);
if (getsockname(file, &sa, &len))
return UV_UNKNOWN_HANDLE;
if (type == SOCK_DGRAM)
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
return UV_UDP;
if (type == SOCK_STREAM) {
#if defined(_AIX) || defined(__DragonFly__)
/* on AIX/DragonFly the getsockname call returns an empty sa structure
* for sockets of type AF_UNIX. For all other types it will
* return a properly filled in structure.
*/
if (len == 0)
return UV_NAMED_PIPE;
#endif /* defined(_AIX) || defined(__DragonFly__) */
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
return UV_TCP;
if (sa.sa_family == AF_UNIX)
return UV_NAMED_PIPE;
}
return UV_UNKNOWN_HANDLE;
}
/* This function is async signal-safe, meaning that it's safe to call from
* inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
* critical section when the signal was raised.
*/
int uv_tty_reset_mode(void) {
int saved_errno;
int err;
saved_errno = errno;
if (!uv_spinlock_trylock(&termios_spinlock))
return UV_EBUSY; /* In uv_tty_set_mode(). */
err = 0;
if (orig_termios_fd != -1)
if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
err = UV__ERR(errno);
uv_spinlock_unlock(&termios_spinlock);
errno = saved_errno;
return err;
}
void uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
}
int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
return UV_ENOTSUP;
}

1332
deps/libuv/src/unix/udp.c vendored Normal file

File diff suppressed because it is too large Load Diff

928
deps/libuv/src/uv-common.c vendored Normal file
View File

@ -0,0 +1,928 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "uv-common.h"
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stddef.h> /* NULL */
#include <stdio.h>
#include <stdlib.h> /* malloc */
#include <string.h> /* memset */
#if defined(_WIN32)
# include <malloc.h> /* malloc */
#else
# include <net/if.h> /* if_nametoindex */
# include <sys/un.h> /* AF_UNIX, sockaddr_un */
#endif
typedef struct {
uv_malloc_func local_malloc;
uv_realloc_func local_realloc;
uv_calloc_func local_calloc;
uv_free_func local_free;
} uv__allocator_t;
static uv__allocator_t uv__allocator = {
malloc,
realloc,
calloc,
free,
};
char* uv__strdup(const char* s) {
size_t len = strlen(s) + 1;
char* m = uv__malloc(len);
if (m == NULL)
return NULL;
return memcpy(m, s, len);
}
char* uv__strndup(const char* s, size_t n) {
char* m;
size_t len = strlen(s);
if (n < len)
len = n;
m = uv__malloc(len + 1);
if (m == NULL)
return NULL;
m[len] = '\0';
return memcpy(m, s, len);
}
void* uv__malloc(size_t size) {
if (size > 0)
return uv__allocator.local_malloc(size);
return NULL;
}
void uv__free(void* ptr) {
int saved_errno;
/* Libuv expects that free() does not clobber errno. The system allocator
* honors that assumption but custom allocators may not be so careful.
*/
saved_errno = errno;
uv__allocator.local_free(ptr);
errno = saved_errno;
}
void* uv__calloc(size_t count, size_t size) {
return uv__allocator.local_calloc(count, size);
}
void* uv__realloc(void* ptr, size_t size) {
if (size > 0)
return uv__allocator.local_realloc(ptr, size);
uv__free(ptr);
return NULL;
}
void* uv__reallocf(void* ptr, size_t size) {
void* newptr;
newptr = uv__realloc(ptr, size);
if (newptr == NULL)
if (size > 0)
uv__free(ptr);
return newptr;
}
int uv_replace_allocator(uv_malloc_func malloc_func,
uv_realloc_func realloc_func,
uv_calloc_func calloc_func,
uv_free_func free_func) {
if (malloc_func == NULL || realloc_func == NULL ||
calloc_func == NULL || free_func == NULL) {
return UV_EINVAL;
}
uv__allocator.local_malloc = malloc_func;
uv__allocator.local_realloc = realloc_func;
uv__allocator.local_calloc = calloc_func;
uv__allocator.local_free = free_func;
return 0;
}
#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
size_t uv_handle_size(uv_handle_type type) {
switch (type) {
UV_HANDLE_TYPE_MAP(XX)
default:
return -1;
}
}
size_t uv_req_size(uv_req_type type) {
switch(type) {
UV_REQ_TYPE_MAP(XX)
default:
return -1;
}
}
#undef XX
size_t uv_loop_size(void) {
return sizeof(uv_loop_t);
}
uv_buf_t uv_buf_init(char* base, unsigned int len) {
uv_buf_t buf;
buf.base = base;
buf.len = len;
return buf;
}
static const char* uv__unknown_err_code(int err) {
char buf[32];
char* copy;
snprintf(buf, sizeof(buf), "Unknown system error %d", err);
copy = uv__strdup(buf);
return copy != NULL ? copy : "Unknown system error";
}
#define UV_ERR_NAME_GEN_R(name, _) \
case UV_## name: \
uv__strscpy(buf, #name, buflen); break;
char* uv_err_name_r(int err, char* buf, size_t buflen) {
switch (err) {
UV_ERRNO_MAP(UV_ERR_NAME_GEN_R)
default: snprintf(buf, buflen, "Unknown system error %d", err);
}
return buf;
}
#undef UV_ERR_NAME_GEN_R
#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
const char* uv_err_name(int err) {
switch (err) {
UV_ERRNO_MAP(UV_ERR_NAME_GEN)
}
return uv__unknown_err_code(err);
}
#undef UV_ERR_NAME_GEN
#define UV_STRERROR_GEN_R(name, msg) \
case UV_ ## name: \
snprintf(buf, buflen, "%s", msg); break;
char* uv_strerror_r(int err, char* buf, size_t buflen) {
switch (err) {
UV_ERRNO_MAP(UV_STRERROR_GEN_R)
default: snprintf(buf, buflen, "Unknown system error %d", err);
}
return buf;
}
#undef UV_STRERROR_GEN_R
#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
const char* uv_strerror(int err) {
switch (err) {
UV_ERRNO_MAP(UV_STRERROR_GEN)
}
return uv__unknown_err_code(err);
}
#undef UV_STRERROR_GEN
int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
memset(addr, 0, sizeof(*addr));
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
#ifdef SIN6_LEN
addr->sin_len = sizeof(*addr);
#endif
return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
}
int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
char address_part[40];
size_t address_part_size;
const char* zone_index;
memset(addr, 0, sizeof(*addr));
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(port);
#ifdef SIN6_LEN
addr->sin6_len = sizeof(*addr);
#endif
zone_index = strchr(ip, '%');
if (zone_index != NULL) {
address_part_size = zone_index - ip;
if (address_part_size >= sizeof(address_part))
address_part_size = sizeof(address_part) - 1;
memcpy(address_part, ip, address_part_size);
address_part[address_part_size] = '\0';
ip = address_part;
zone_index++; /* skip '%' */
/* NOTE: unknown interface (id=0) is silently ignored */
#ifdef _WIN32
addr->sin6_scope_id = atoi(zone_index);
#else
addr->sin6_scope_id = if_nametoindex(zone_index);
#endif
}
return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
}
int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {
return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
}
int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
}
int uv_tcp_bind(uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int flags) {
unsigned int addrlen;
if (handle->type != UV_TCP)
return UV_EINVAL;
if (addr->sa_family == AF_INET)
addrlen = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6)
addrlen = sizeof(struct sockaddr_in6);
else
return UV_EINVAL;
return uv__tcp_bind(handle, addr, addrlen, flags);
}
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned flags) {
unsigned extra_flags;
int domain;
int rc;
/* Use the lower 8 bits for the domain. */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return UV_EINVAL;
/* Use the higher bits for extra flags. */
extra_flags = flags & ~0xFF;
if (extra_flags & ~UV_UDP_RECVMMSG)
return UV_EINVAL;
rc = uv__udp_init_ex(loop, handle, flags, domain);
if (rc == 0)
if (extra_flags & UV_UDP_RECVMMSG)
handle->flags |= UV_HANDLE_UDP_RECVMMSG;
return rc;
}
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
}
int uv_udp_bind(uv_udp_t* handle,
const struct sockaddr* addr,
unsigned int flags) {
unsigned int addrlen;
if (handle->type != UV_UDP)
return UV_EINVAL;
if (addr->sa_family == AF_INET)
addrlen = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6)
addrlen = sizeof(struct sockaddr_in6);
else
return UV_EINVAL;
return uv__udp_bind(handle, addr, addrlen, flags);
}
int uv_tcp_connect(uv_connect_t* req,
uv_tcp_t* handle,
const struct sockaddr* addr,
uv_connect_cb cb) {
unsigned int addrlen;
if (handle->type != UV_TCP)
return UV_EINVAL;
if (addr->sa_family == AF_INET)
addrlen = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6)
addrlen = sizeof(struct sockaddr_in6);
else
return UV_EINVAL;
return uv__tcp_connect(req, handle, addr, addrlen, cb);
}
int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) {
unsigned int addrlen;
if (handle->type != UV_UDP)
return UV_EINVAL;
/* Disconnect the handle */
if (addr == NULL) {
if (!(handle->flags & UV_HANDLE_UDP_CONNECTED))
return UV_ENOTCONN;
return uv__udp_disconnect(handle);
}
if (addr->sa_family == AF_INET)
addrlen = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6)
addrlen = sizeof(struct sockaddr_in6);
else
return UV_EINVAL;
if (handle->flags & UV_HANDLE_UDP_CONNECTED)
return UV_EISCONN;
return uv__udp_connect(handle, addr, addrlen);
}
int uv__udp_is_connected(uv_udp_t* handle) {
struct sockaddr_storage addr;
int addrlen;
if (handle->type != UV_UDP)
return 0;
addrlen = sizeof(addr);
if (uv_udp_getpeername(handle, (struct sockaddr*) &addr, &addrlen) != 0)
return 0;
return addrlen > 0;
}
int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) {
unsigned int addrlen;
if (handle->type != UV_UDP)
return UV_EINVAL;
if (addr != NULL && (handle->flags & UV_HANDLE_UDP_CONNECTED))
return UV_EISCONN;
if (addr == NULL && !(handle->flags & UV_HANDLE_UDP_CONNECTED))
return UV_EDESTADDRREQ;
if (addr != NULL) {
if (addr->sa_family == AF_INET)
addrlen = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6)
addrlen = sizeof(struct sockaddr_in6);
#if defined(AF_UNIX) && !defined(_WIN32)
else if (addr->sa_family == AF_UNIX)
addrlen = sizeof(struct sockaddr_un);
#endif
else
return UV_EINVAL;
} else {
addrlen = 0;
}
return addrlen;
}
int 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) {
int addrlen;
addrlen = uv__udp_check_before_send(handle, addr);
if (addrlen < 0)
return addrlen;
return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
}
int uv_udp_try_send(uv_udp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
const struct sockaddr* addr) {
int addrlen;
addrlen = uv__udp_check_before_send(handle, addr);
if (addrlen < 0)
return addrlen;
return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
}
int uv_udp_recv_start(uv_udp_t* handle,
uv_alloc_cb alloc_cb,
uv_udp_recv_cb recv_cb) {
if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)
return UV_EINVAL;
else
return uv__udp_recv_start(handle, alloc_cb, recv_cb);
}
int uv_udp_recv_stop(uv_udp_t* handle) {
if (handle->type != UV_UDP)
return UV_EINVAL;
else
return uv__udp_recv_stop(handle);
}
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
QUEUE queue;
QUEUE* q;
uv_handle_t* h;
QUEUE_MOVE(&loop->handle_queue, &queue);
while (!QUEUE_EMPTY(&queue)) {
q = QUEUE_HEAD(&queue);
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
QUEUE_REMOVE(q);
QUEUE_INSERT_TAIL(&loop->handle_queue, q);
if (h->flags & UV_HANDLE_INTERNAL) continue;
walk_cb(h, arg);
}
}
static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
const char* type;
QUEUE* q;
uv_handle_t* h;
if (loop == NULL)
loop = uv_default_loop();
QUEUE_FOREACH(q, &loop->handle_queue) {
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
if (only_active && !uv__is_active(h))
continue;
switch (h->type) {
#define X(uc, lc) case UV_##uc: type = #lc; break;
UV_HANDLE_TYPE_MAP(X)
#undef X
default: type = "<unknown>";
}
fprintf(stream,
"[%c%c%c] %-8s %p\n",
"R-"[!(h->flags & UV_HANDLE_REF)],
"A-"[!(h->flags & UV_HANDLE_ACTIVE)],
"I-"[!(h->flags & UV_HANDLE_INTERNAL)],
type,
(void*)h);
}
}
void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
uv__print_handles(loop, 0, stream);
}
void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
uv__print_handles(loop, 1, stream);
}
void uv_ref(uv_handle_t* handle) {
uv__handle_ref(handle);
}
void uv_unref(uv_handle_t* handle) {
uv__handle_unref(handle);
}
int uv_has_ref(const uv_handle_t* handle) {
return uv__has_ref(handle);
}
void uv_stop(uv_loop_t* loop) {
loop->stop_flag = 1;
}
uint64_t uv_now(const uv_loop_t* loop) {
return loop->time;
}
size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
unsigned int i;
size_t bytes;
bytes = 0;
for (i = 0; i < nbufs; i++)
bytes += (size_t) bufs[i].len;
return bytes;
}
int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
return uv__socket_sockopt(handle, SO_RCVBUF, value);
}
int uv_send_buffer_size(uv_handle_t* handle, int *value) {
return uv__socket_sockopt(handle, SO_SNDBUF, value);
}
int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
size_t required_len;
if (!uv__is_active(handle)) {
*size = 0;
return UV_EINVAL;
}
required_len = strlen(handle->path);
if (required_len >= *size) {
*size = required_len + 1;
return UV_ENOBUFS;
}
memcpy(buffer, handle->path, required_len);
*size = required_len;
buffer[required_len] = '\0';
return 0;
}
/* The windows implementation does not have the same structure layout as
* the unix implementation (nbufs is not directly inside req but is
* contained in a nested union/struct) so this function locates it.
*/
static unsigned int* uv__get_nbufs(uv_fs_t* req) {
#ifdef _WIN32
return &req->fs.info.nbufs;
#else
return &req->nbufs;
#endif
}
/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows
* systems. So, the memory should be released using free(). On Windows,
* uv__malloc() is used, so use uv__free() to free memory.
*/
#ifdef _WIN32
# define uv__fs_scandir_free uv__free
#else
# define uv__fs_scandir_free free
#endif
void uv__fs_scandir_cleanup(uv_fs_t* req) {
uv__dirent_t** dents;
unsigned int* nbufs = uv__get_nbufs(req);
dents = req->ptr;
if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
(*nbufs)--;
for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
uv__fs_scandir_free(dents[*nbufs]);
uv__fs_scandir_free(req->ptr);
req->ptr = NULL;
}
int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
uv__dirent_t** dents;
uv__dirent_t* dent;
unsigned int* nbufs;
/* Check to see if req passed */
if (req->result < 0)
return req->result;
/* Ptr will be null if req was canceled or no files found */
if (!req->ptr)
return UV_EOF;
nbufs = uv__get_nbufs(req);
assert(nbufs);
dents = req->ptr;
/* Free previous entity */
if (*nbufs > 0)
uv__fs_scandir_free(dents[*nbufs - 1]);
/* End was already reached */
if (*nbufs == (unsigned int) req->result) {
uv__fs_scandir_free(dents);
req->ptr = NULL;
return UV_EOF;
}
dent = dents[(*nbufs)++];
ent->name = dent->d_name;
ent->type = uv__fs_get_dirent_type(dent);
return 0;
}
uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent) {
uv_dirent_type_t type;
#ifdef HAVE_DIRENT_TYPES
switch (dent->d_type) {
case UV__DT_DIR:
type = UV_DIRENT_DIR;
break;
case UV__DT_FILE:
type = UV_DIRENT_FILE;
break;
case UV__DT_LINK:
type = UV_DIRENT_LINK;
break;
case UV__DT_FIFO:
type = UV_DIRENT_FIFO;
break;
case UV__DT_SOCKET:
type = UV_DIRENT_SOCKET;
break;
case UV__DT_CHAR:
type = UV_DIRENT_CHAR;
break;
case UV__DT_BLOCK:
type = UV_DIRENT_BLOCK;
break;
default:
type = UV_DIRENT_UNKNOWN;
}
#else
type = UV_DIRENT_UNKNOWN;
#endif
return type;
}
void uv__fs_readdir_cleanup(uv_fs_t* req) {
uv_dir_t* dir;
uv_dirent_t* dirents;
int i;
if (req->ptr == NULL)
return;
dir = req->ptr;
dirents = dir->dirents;
req->ptr = NULL;
if (dirents == NULL)
return;
for (i = 0; i < req->result; ++i) {
uv__free((char*) dirents[i].name);
dirents[i].name = NULL;
}
}
int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
va_list ap;
int err;
va_start(ap, option);
/* Any platform-agnostic options should be handled here. */
err = uv__loop_configure(loop, option, ap);
va_end(ap);
return err;
}
static uv_loop_t default_loop_struct;
static uv_loop_t* default_loop_ptr;
uv_loop_t* uv_default_loop(void) {
if (default_loop_ptr != NULL)
return default_loop_ptr;
if (uv_loop_init(&default_loop_struct))
return NULL;
default_loop_ptr = &default_loop_struct;
return default_loop_ptr;
}
uv_loop_t* uv_loop_new(void) {
uv_loop_t* loop;
loop = uv__malloc(sizeof(*loop));
if (loop == NULL)
return NULL;
if (uv_loop_init(loop)) {
uv__free(loop);
return NULL;
}
return loop;
}
int uv_loop_close(uv_loop_t* loop) {
QUEUE* q;
uv_handle_t* h;
#ifndef NDEBUG
void* saved_data;
#endif
if (uv__has_active_reqs(loop))
return UV_EBUSY;
QUEUE_FOREACH(q, &loop->handle_queue) {
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
if (!(h->flags & UV_HANDLE_INTERNAL))
return UV_EBUSY;
}
uv__loop_close(loop);
#ifndef NDEBUG
saved_data = loop->data;
memset(loop, -1, sizeof(*loop));
loop->data = saved_data;
#endif
if (loop == default_loop_ptr)
default_loop_ptr = NULL;
return 0;
}
void uv_loop_delete(uv_loop_t* loop) {
uv_loop_t* default_loop;
int err;
default_loop = default_loop_ptr;
err = uv_loop_close(loop);
(void) err; /* Squelch compiler warnings. */
assert(err == 0);
if (loop != default_loop)
uv__free(loop);
}
void uv_os_free_environ(uv_env_item_t* envitems, int count) {
int i;
for (i = 0; i < count; i++) {
uv__free(envitems[i].name);
}
uv__free(envitems);
}
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
int i;
for (i = 0; i < count; i++)
uv__free(cpu_infos[i].model);
uv__free(cpu_infos);
}
#ifdef __GNUC__ /* Also covers __clang__ and __INTEL_COMPILER. */
__attribute__((destructor))
#endif
void uv_library_shutdown(void) {
static int was_shutdown;
if (uv__load_relaxed(&was_shutdown))
return;
uv__process_title_cleanup();
uv__signal_cleanup();
uv__threadpool_cleanup();
uv__store_relaxed(&was_shutdown, 1);
}
void uv__metrics_update_idle_time(uv_loop_t* loop) {
uv__loop_metrics_t* loop_metrics;
uint64_t entry_time;
uint64_t exit_time;
if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME))
return;
loop_metrics = uv__get_loop_metrics(loop);
/* The thread running uv__metrics_update_idle_time() is always the same
* thread that sets provider_entry_time. So it's unnecessary to lock before
* retrieving this value.
*/
if (loop_metrics->provider_entry_time == 0)
return;
exit_time = uv_hrtime();
uv_mutex_lock(&loop_metrics->lock);
entry_time = loop_metrics->provider_entry_time;
loop_metrics->provider_entry_time = 0;
loop_metrics->provider_idle_time += exit_time - entry_time;
uv_mutex_unlock(&loop_metrics->lock);
}
void uv__metrics_set_provider_entry_time(uv_loop_t* loop) {
uv__loop_metrics_t* loop_metrics;
uint64_t now;
if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME))
return;
now = uv_hrtime();
loop_metrics = uv__get_loop_metrics(loop);
uv_mutex_lock(&loop_metrics->lock);
loop_metrics->provider_entry_time = now;
uv_mutex_unlock(&loop_metrics->lock);
}
uint64_t uv_metrics_idle_time(uv_loop_t* loop) {
uv__loop_metrics_t* loop_metrics;
uint64_t entry_time;
uint64_t idle_time;
loop_metrics = uv__get_loop_metrics(loop);
uv_mutex_lock(&loop_metrics->lock);
idle_time = loop_metrics->provider_idle_time;
entry_time = loop_metrics->provider_entry_time;
uv_mutex_unlock(&loop_metrics->lock);
if (entry_time > 0)
idle_time += uv_hrtime() - entry_time;
return idle_time;
}

368
deps/libuv/src/uv-common.h vendored Normal file
View File

@ -0,0 +1,368 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* This file is private to libuv. It provides common functionality to both
* Windows and Unix backends.
*/
#ifndef UV_COMMON_H_
#define UV_COMMON_H_
#include <assert.h>
#include <stdarg.h>
#include <stddef.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
# include "uv/stdint-msvc2008.h"
#else
# include <stdint.h>
#endif
#include "uv.h"
#include "uv/tree.h"
#include "queue.h"
#include "strscpy.h"
#if EDOM > 0
# define UV__ERR(x) (-(x))
#else
# define UV__ERR(x) (x)
#endif
#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
extern int snprintf(char*, size_t, const char*, ...);
#endif
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define container_of(ptr, type, member) \
((type *) ((char *) (ptr) - offsetof(type, member)))
#define STATIC_ASSERT(expr) \
void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 7)
#define uv__load_relaxed(p) __atomic_load_n(p, __ATOMIC_RELAXED)
#define uv__store_relaxed(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED)
#else
#define uv__load_relaxed(p) (*p)
#define uv__store_relaxed(p, v) do *p = v; while (0)
#endif
/* Handle flags. Some flags are specific to Windows or UNIX. */
enum {
/* Used by all handles. */
UV_HANDLE_CLOSING = 0x00000001,
UV_HANDLE_CLOSED = 0x00000002,
UV_HANDLE_ACTIVE = 0x00000004,
UV_HANDLE_REF = 0x00000008,
UV_HANDLE_INTERNAL = 0x00000010,
UV_HANDLE_ENDGAME_QUEUED = 0x00000020,
/* Used by streams. */
UV_HANDLE_LISTENING = 0x00000040,
UV_HANDLE_CONNECTION = 0x00000080,
UV_HANDLE_SHUTTING = 0x00000100,
UV_HANDLE_SHUT = 0x00000200,
UV_HANDLE_READ_PARTIAL = 0x00000400,
UV_HANDLE_READ_EOF = 0x00000800,
/* Used by streams and UDP handles. */
UV_HANDLE_READING = 0x00001000,
UV_HANDLE_BOUND = 0x00002000,
UV_HANDLE_READABLE = 0x00004000,
UV_HANDLE_WRITABLE = 0x00008000,
UV_HANDLE_READ_PENDING = 0x00010000,
UV_HANDLE_SYNC_BYPASS_IOCP = 0x00020000,
UV_HANDLE_ZERO_READ = 0x00040000,
UV_HANDLE_EMULATE_IOCP = 0x00080000,
UV_HANDLE_BLOCKING_WRITES = 0x00100000,
UV_HANDLE_CANCELLATION_PENDING = 0x00200000,
/* Used by uv_tcp_t and uv_udp_t handles */
UV_HANDLE_IPV6 = 0x00400000,
/* Only used by uv_tcp_t handles. */
UV_HANDLE_TCP_NODELAY = 0x01000000,
UV_HANDLE_TCP_KEEPALIVE = 0x02000000,
UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000,
UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000,
UV_HANDLE_TCP_SOCKET_CLOSED = 0x10000000,
UV_HANDLE_SHARED_TCP_SOCKET = 0x20000000,
/* Only used by uv_udp_t handles. */
UV_HANDLE_UDP_PROCESSING = 0x01000000,
UV_HANDLE_UDP_CONNECTED = 0x02000000,
UV_HANDLE_UDP_RECVMMSG = 0x04000000,
/* Only used by uv_pipe_t handles. */
UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000,
UV_HANDLE_PIPESERVER = 0x02000000,
/* Only used by uv_tty_t handles. */
UV_HANDLE_TTY_READABLE = 0x01000000,
UV_HANDLE_TTY_RAW = 0x02000000,
UV_HANDLE_TTY_SAVED_POSITION = 0x04000000,
UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000,
/* Only used by uv_signal_t handles. */
UV_SIGNAL_ONE_SHOT_DISPATCHED = 0x01000000,
UV_SIGNAL_ONE_SHOT = 0x02000000,
/* Only used by uv_poll_t handles. */
UV_HANDLE_POLL_SLOW = 0x01000000
};
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
void uv__loop_close(uv_loop_t* loop);
int uv__tcp_bind(uv_tcp_t* tcp,
const struct sockaddr* addr,
unsigned int addrlen,
unsigned int flags);
int uv__tcp_connect(uv_connect_t* req,
uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen,
uv_connect_cb cb);
int uv__udp_init_ex(uv_loop_t* loop,
uv_udp_t* handle,
unsigned flags,
int domain);
int uv__udp_bind(uv_udp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen,
unsigned int flags);
int uv__udp_connect(uv_udp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen);
int uv__udp_disconnect(uv_udp_t* handle);
int uv__udp_is_connected(uv_udp_t* handle);
int uv__udp_send(uv_udp_send_t* req,
uv_udp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
const struct sockaddr* addr,
unsigned int addrlen,
uv_udp_send_cb send_cb);
int uv__udp_try_send(uv_udp_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
const struct sockaddr* addr,
unsigned int addrlen);
int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
uv_udp_recv_cb recv_cb);
int uv__udp_recv_stop(uv_udp_t* handle);
void uv__fs_poll_close(uv_fs_poll_t* handle);
int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
enum uv__work_kind {
UV__WORK_CPU,
UV__WORK_FAST_IO,
UV__WORK_SLOW_IO
};
void uv__work_submit(uv_loop_t* loop,
struct uv__work *w,
enum uv__work_kind kind,
void (*work)(struct uv__work *w),
void (*done)(struct uv__work *w, int status));
void uv__work_done(uv_async_t* handle);
size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
void uv__fs_scandir_cleanup(uv_fs_t* req);
void uv__fs_readdir_cleanup(uv_fs_t* req);
uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent);
int uv__next_timeout(const uv_loop_t* loop);
void uv__run_timers(uv_loop_t* loop);
void uv__timer_close(uv_timer_t* handle);
void uv__process_title_cleanup(void);
void uv__signal_cleanup(void);
void uv__threadpool_cleanup(void);
#define uv__has_active_reqs(loop) \
((loop)->active_reqs.count > 0)
#define uv__req_register(loop, req) \
do { \
(loop)->active_reqs.count++; \
} \
while (0)
#define uv__req_unregister(loop, req) \
do { \
assert(uv__has_active_reqs(loop)); \
(loop)->active_reqs.count--; \
} \
while (0)
#define uv__has_active_handles(loop) \
((loop)->active_handles > 0)
#define uv__active_handle_add(h) \
do { \
(h)->loop->active_handles++; \
} \
while (0)
#define uv__active_handle_rm(h) \
do { \
(h)->loop->active_handles--; \
} \
while (0)
#define uv__is_active(h) \
(((h)->flags & UV_HANDLE_ACTIVE) != 0)
#define uv__is_closing(h) \
(((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0)
#define uv__handle_start(h) \
do { \
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \
(h)->flags |= UV_HANDLE_ACTIVE; \
if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h); \
} \
while (0)
#define uv__handle_stop(h) \
do { \
if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break; \
(h)->flags &= ~UV_HANDLE_ACTIVE; \
if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h); \
} \
while (0)
#define uv__handle_ref(h) \
do { \
if (((h)->flags & UV_HANDLE_REF) != 0) break; \
(h)->flags |= UV_HANDLE_REF; \
if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
} \
while (0)
#define uv__handle_unref(h) \
do { \
if (((h)->flags & UV_HANDLE_REF) == 0) break; \
(h)->flags &= ~UV_HANDLE_REF; \
if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
} \
while (0)
#define uv__has_ref(h) \
(((h)->flags & UV_HANDLE_REF) != 0)
#if defined(_WIN32)
# define uv__handle_platform_init(h) ((h)->u.fd = -1)
#else
# define uv__handle_platform_init(h) ((h)->next_closing = NULL)
#endif
#define uv__handle_init(loop_, h, type_) \
do { \
(h)->loop = (loop_); \
(h)->type = (type_); \
(h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \
QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
uv__handle_platform_init(h); \
} \
while (0)
/* Note: uses an open-coded version of SET_REQ_SUCCESS() because of
* a circular dependency between src/uv-common.h and src/win/internal.h.
*/
#if defined(_WIN32)
# define UV_REQ_INIT(req, typ) \
do { \
(req)->type = (typ); \
(req)->u.io.overlapped.Internal = 0; /* SET_REQ_SUCCESS() */ \
} \
while (0)
#else
# define UV_REQ_INIT(req, typ) \
do { \
(req)->type = (typ); \
} \
while (0)
#endif
#define uv__req_init(loop, req, typ) \
do { \
UV_REQ_INIT(req, typ); \
uv__req_register(loop, req); \
} \
while (0)
#define uv__get_internal_fields(loop) \
((uv__loop_internal_fields_t*) loop->internal_fields)
#define uv__get_loop_metrics(loop) \
(&uv__get_internal_fields(loop)->loop_metrics)
/* Allocator prototypes */
void *uv__calloc(size_t count, size_t size);
char *uv__strdup(const char* s);
char *uv__strndup(const char* s, size_t n);
void* uv__malloc(size_t size);
void uv__free(void* ptr);
void* uv__realloc(void* ptr, size_t size);
void* uv__reallocf(void* ptr, size_t size);
typedef struct uv__loop_metrics_s uv__loop_metrics_t;
typedef struct uv__loop_internal_fields_s uv__loop_internal_fields_t;
struct uv__loop_metrics_s {
uint64_t provider_entry_time;
uint64_t provider_idle_time;
uv_mutex_t lock;
};
void uv__metrics_update_idle_time(uv_loop_t* loop);
void uv__metrics_set_provider_entry_time(uv_loop_t* loop);
struct uv__loop_internal_fields_s {
unsigned int flags;
uv__loop_metrics_t loop_metrics;
};
#endif /* UV_COMMON_H_ */

119
deps/libuv/src/uv-data-getter-setters.c vendored Normal file
View File

@ -0,0 +1,119 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
const char* uv_handle_type_name(uv_handle_type type) {
switch (type) {
#define XX(uc,lc) case UV_##uc: return #lc;
UV_HANDLE_TYPE_MAP(XX)
#undef XX
case UV_FILE: return "file";
case UV_HANDLE_TYPE_MAX:
case UV_UNKNOWN_HANDLE: return NULL;
}
return NULL;
}
uv_handle_type uv_handle_get_type(const uv_handle_t* handle) {
return handle->type;
}
void* uv_handle_get_data(const uv_handle_t* handle) {
return handle->data;
}
uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) {
return handle->loop;
}
void uv_handle_set_data(uv_handle_t* handle, void* data) {
handle->data = data;
}
const char* uv_req_type_name(uv_req_type type) {
switch (type) {
#define XX(uc,lc) case UV_##uc: return #lc;
UV_REQ_TYPE_MAP(XX)
#undef XX
case UV_REQ_TYPE_MAX:
case UV_UNKNOWN_REQ:
default: /* UV_REQ_TYPE_PRIVATE */
break;
}
return NULL;
}
uv_req_type uv_req_get_type(const uv_req_t* req) {
return req->type;
}
void* uv_req_get_data(const uv_req_t* req) {
return req->data;
}
void uv_req_set_data(uv_req_t* req, void* data) {
req->data = data;
}
size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) {
return stream->write_queue_size;
}
size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) {
return handle->send_queue_size;
}
size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) {
return handle->send_queue_count;
}
uv_pid_t uv_process_get_pid(const uv_process_t* proc) {
return proc->pid;
}
uv_fs_type uv_fs_get_type(const uv_fs_t* req) {
return req->fs_type;
}
ssize_t uv_fs_get_result(const uv_fs_t* req) {
return req->result;
}
void* uv_fs_get_ptr(const uv_fs_t* req) {
return req->ptr;
}
const char* uv_fs_get_path(const uv_fs_t* req) {
return req->path;
}
uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) {
return &req->statbuf;
}
void* uv_loop_get_data(const uv_loop_t* loop) {
return loop->data;
}
void uv_loop_set_data(uv_loop_t* loop, void* data) {
loop->data = data;
}

45
deps/libuv/src/version.c vendored Normal file
View File

@ -0,0 +1,45 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v)
#define UV_STRINGIFY_HELPER(v) #v
#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \
UV_STRINGIFY(UV_VERSION_MINOR) "." \
UV_STRINGIFY(UV_VERSION_PATCH)
#if UV_VERSION_IS_RELEASE
# define UV_VERSION_STRING UV_VERSION_STRING_BASE
#else
# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX
#endif
unsigned int uv_version(void) {
return UV_VERSION_HEX;
}
const char* uv_version_string(void) {
return UV_VERSION_STRING;
}

98
deps/libuv/src/win/async.c vendored Normal file
View File

@ -0,0 +1,98 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include "uv.h"
#include "internal.h"
#include "atomicops-inl.h"
#include "handle-inl.h"
#include "req-inl.h"
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING &&
!handle->async_sent) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
uv__handle_close(handle);
}
}
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
uv_req_t* req;
uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC);
handle->async_sent = 0;
handle->async_cb = async_cb;
req = &handle->async_req;
UV_REQ_INIT(req, UV_WAKEUP);
req->data = handle;
uv__handle_start(handle);
return 0;
}
void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
if (!((uv_async_t*)handle)->async_sent) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
uv__handle_closing(handle);
}
int uv_async_send(uv_async_t* handle) {
uv_loop_t* loop = handle->loop;
if (handle->type != UV_ASYNC) {
/* Can't set errno because that's not thread-safe. */
return -1;
}
/* The user should make sure never to call uv_async_send to a closing or
* closed handle. */
assert(!(handle->flags & UV_HANDLE_CLOSING));
if (!uv__atomic_exchange_set(&handle->async_sent)) {
POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
}
return 0;
}
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
uv_req_t* req) {
assert(handle->type == UV_ASYNC);
assert(req->type == UV_WAKEUP);
handle->async_sent = 0;
if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*)handle);
} else if (handle->async_cb != NULL) {
handle->async_cb(handle);
}
}

57
deps/libuv/src/win/atomicops-inl.h vendored Normal file
View File

@ -0,0 +1,57 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_WIN_ATOMICOPS_INL_H_
#define UV_WIN_ATOMICOPS_INL_H_
#include "uv.h"
#include "internal.h"
/* Atomic set operation on char */
#ifdef _MSC_VER /* MSVC */
/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less
* efficient than InterlockedExchange, but InterlockedExchange8 does not exist,
* and interlocked operations on larger targets might require the target to be
* aligned. */
#pragma intrinsic(_InterlockedOr8)
static char INLINE uv__atomic_exchange_set(char volatile* target) {
return _InterlockedOr8(target, 1);
}
#else /* GCC */
/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
static inline char uv__atomic_exchange_set(char volatile* target) {
const char one = 1;
char old_value;
__asm__ __volatile__ ("lock xchgb %0, %1\n\t"
: "=r"(old_value), "=m"(*target)
: "0"(one), "m"(*target)
: "memory");
return old_value;
}
#endif
#endif /* UV_WIN_ATOMICOPS_INL_H_ */

748
deps/libuv/src/win/core.c vendored Normal file
View File

@ -0,0 +1,748 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
#include <crtdbg.h>
#endif
#include "uv.h"
#include "internal.h"
#include "queue.h"
#include "handle-inl.h"
#include "heap-inl.h"
#include "req-inl.h"
/* uv_once initialization guards */
static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
/* Our crt debug report handler allows us to temporarily disable asserts
* just for the current thread.
*/
UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
return FALSE;
if (ret_val) {
/* Set ret_val to 0 to continue with normal execution.
* Set ret_val to 1 to trigger a breakpoint.
*/
if(IsDebuggerPresent())
*ret_val = 1;
else
*ret_val = 0;
}
/* Don't call _CrtDbgReport. */
return TRUE;
}
#else
UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
#endif
#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
const wchar_t* function, const wchar_t * file, unsigned int line,
uintptr_t reserved) {
/* No-op. */
}
#endif
static uv_loop_t** uv__loops;
static int uv__loops_size;
static int uv__loops_capacity;
#define UV__LOOPS_CHUNK_SIZE 8
static uv_mutex_t uv__loops_lock;
static void uv__loops_init(void) {
uv_mutex_init(&uv__loops_lock);
}
static int uv__loops_add(uv_loop_t* loop) {
uv_loop_t** new_loops;
int new_capacity, i;
uv_mutex_lock(&uv__loops_lock);
if (uv__loops_size == uv__loops_capacity) {
new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
if (!new_loops)
goto failed_loops_realloc;
uv__loops = new_loops;
for (i = uv__loops_capacity; i < new_capacity; ++i)
uv__loops[i] = NULL;
uv__loops_capacity = new_capacity;
}
uv__loops[uv__loops_size] = loop;
++uv__loops_size;
uv_mutex_unlock(&uv__loops_lock);
return 0;
failed_loops_realloc:
uv_mutex_unlock(&uv__loops_lock);
return ERROR_OUTOFMEMORY;
}
static void uv__loops_remove(uv_loop_t* loop) {
int loop_index;
int smaller_capacity;
uv_loop_t** new_loops;
uv_mutex_lock(&uv__loops_lock);
for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
if (uv__loops[loop_index] == loop)
break;
}
/* If loop was not found, ignore */
if (loop_index == uv__loops_size)
goto loop_removed;
uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
uv__loops[uv__loops_size - 1] = NULL;
--uv__loops_size;
if (uv__loops_size == 0) {
uv__loops_capacity = 0;
uv__free(uv__loops);
uv__loops = NULL;
goto loop_removed;
}
/* If we didn't grow to big skip downsizing */
if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
goto loop_removed;
/* Downsize only if more than half of buffer is free */
smaller_capacity = uv__loops_capacity / 2;
if (uv__loops_size >= smaller_capacity)
goto loop_removed;
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
if (!new_loops)
goto loop_removed;
uv__loops = new_loops;
uv__loops_capacity = smaller_capacity;
loop_removed:
uv_mutex_unlock(&uv__loops_lock);
}
void uv__wake_all_loops(void) {
int i;
uv_loop_t* loop;
uv_mutex_lock(&uv__loops_lock);
for (i = 0; i < uv__loops_size; ++i) {
loop = uv__loops[i];
assert(loop);
if (loop->iocp != INVALID_HANDLE_VALUE)
PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
}
uv_mutex_unlock(&uv__loops_lock);
}
static void uv_init(void) {
/* Tell Windows that we will handle critical errors. */
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
/* Tell the CRT to not exit the application when an invalid parameter is
* passed. The main issue is that invalid FDs will trigger this behavior.
*/
#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
_set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
#endif
/* We also need to setup our debug report handler because some CRT
* functions (eg _get_osfhandle) raise an assert when called with invalid
* FDs even though they return the proper error code in the release build.
*/
#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
_CrtSetReportHook(uv__crt_dbg_report_handler);
#endif
/* Initialize tracking of all uv loops */
uv__loops_init();
/* Fetch winapi function pointers. This must be done first because other
* initialization code might need these function pointers to be loaded.
*/
uv_winapi_init();
/* Initialize winsock */
uv_winsock_init();
/* Initialize FS */
uv_fs_init();
/* Initialize signal stuff */
uv_signals_init();
/* Initialize console */
uv_console_init();
/* Initialize utilities */
uv__util_init();
/* Initialize system wakeup detection */
uv__init_detect_system_wakeup();
}
int uv_loop_init(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
struct heap* timer_heap;
int err;
/* Initialize libuv itself first */
uv__once_init();
/* Create an I/O completion port */
loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
if (loop->iocp == NULL)
return uv_translate_sys_error(GetLastError());
lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
if (lfields == NULL)
return UV_ENOMEM;
loop->internal_fields = lfields;
err = uv_mutex_init(&lfields->loop_metrics.lock);
if (err)
goto fail_metrics_mutex_init;
/* To prevent uninitialized memory access, loop->time must be initialized
* to zero before calling uv_update_time for the first time.
*/
loop->time = 0;
uv_update_time(loop);
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->handle_queue);
loop->active_reqs.count = 0;
loop->active_handles = 0;
loop->pending_reqs_tail = NULL;
loop->endgame_handles = NULL;
loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap));
if (timer_heap == NULL) {
err = UV_ENOMEM;
goto fail_timers_alloc;
}
heap_init(timer_heap);
loop->check_handles = NULL;
loop->prepare_handles = NULL;
loop->idle_handles = NULL;
loop->next_prepare_handle = NULL;
loop->next_check_handle = NULL;
loop->next_idle_handle = NULL;
memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
loop->active_tcp_streams = 0;
loop->active_udp_streams = 0;
loop->timer_counter = 0;
loop->stop_flag = 0;
err = uv_mutex_init(&loop->wq_mutex);
if (err)
goto fail_mutex_init;
err = uv_async_init(loop, &loop->wq_async, uv__work_done);
if (err)
goto fail_async_init;
uv__handle_unref(&loop->wq_async);
loop->wq_async.flags |= UV_HANDLE_INTERNAL;
err = uv__loops_add(loop);
if (err)
goto fail_async_init;
return 0;
fail_async_init:
uv_mutex_destroy(&loop->wq_mutex);
fail_mutex_init:
uv__free(timer_heap);
loop->timer_heap = NULL;
fail_timers_alloc:
uv_mutex_destroy(&lfields->loop_metrics.lock);
fail_metrics_mutex_init:
uv__free(lfields);
loop->internal_fields = NULL;
CloseHandle(loop->iocp);
loop->iocp = INVALID_HANDLE_VALUE;
return err;
}
void uv_update_time(uv_loop_t* loop) {
uint64_t new_time = uv__hrtime(1000);
assert(new_time >= loop->time);
loop->time = new_time;
}
void uv__once_init(void) {
uv_once(&uv_init_guard_, uv_init);
}
void uv__loop_close(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
size_t i;
uv__loops_remove(loop);
/* Close the async handle without needing an extra loop iteration.
* We might have a pending message, but we're just going to destroy the IOCP
* soon, so we can just discard it now without the usual risk of a getting
* another notification from GetQueuedCompletionStatusEx after calling the
* close_cb (which we also skip defining). We'll assert later that queue was
* actually empty and all reqs handled. */
loop->wq_async.async_sent = 0;
loop->wq_async.close_cb = NULL;
uv__handle_closing(&loop->wq_async);
uv__handle_close(&loop->wq_async);
for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
SOCKET sock = loop->poll_peer_sockets[i];
if (sock != 0 && sock != INVALID_SOCKET)
closesocket(sock);
}
uv_mutex_lock(&loop->wq_mutex);
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
assert(!uv__has_active_reqs(loop));
uv_mutex_unlock(&loop->wq_mutex);
uv_mutex_destroy(&loop->wq_mutex);
uv__free(loop->timer_heap);
loop->timer_heap = NULL;
lfields = uv__get_internal_fields(loop);
uv_mutex_destroy(&lfields->loop_metrics.lock);
uv__free(lfields);
loop->internal_fields = NULL;
CloseHandle(loop->iocp);
}
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
uv__loop_internal_fields_t* lfields;
lfields = uv__get_internal_fields(loop);
if (option == UV_METRICS_IDLE_TIME) {
lfields->flags |= UV_METRICS_IDLE_TIME;
return 0;
}
return UV_ENOSYS;
}
int uv_backend_fd(const uv_loop_t* loop) {
return -1;
}
int uv_loop_fork(uv_loop_t* loop) {
return UV_ENOSYS;
}
int uv_backend_timeout(const uv_loop_t* loop) {
if (loop->stop_flag != 0)
return 0;
if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
return 0;
if (loop->pending_reqs_tail)
return 0;
if (loop->endgame_handles)
return 0;
if (loop->idle_handles)
return 0;
return uv__next_timeout(loop);
}
static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
DWORD bytes;
ULONG_PTR key;
OVERLAPPED* overlapped;
uv_req_t* req;
int repeat;
uint64_t timeout_time;
uint64_t user_timeout;
int reset_timeout;
timeout_time = loop->time + timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (repeat = 0; ; repeat++) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
GetQueuedCompletionStatus(loop->iocp,
&bytes,
&key,
&overlapped,
timeout);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
/* Placed here because on success the loop will break whether there is an
* empty package or not, or if GetQueuedCompletionStatus returned early then
* the timeout will be updated and the loop will run again. In either case
* the idle time will need to be updated.
*/
uv__metrics_update_idle_time(loop);
if (overlapped) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlapped);
uv_insert_pending_req(loop, req);
/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
} else if (timeout > 0) {
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout target time is reached.
*/
uv_update_time(loop);
if (timeout_time > loop->time) {
timeout = (DWORD)(timeout_time - loop->time);
/* The first call to GetQueuedCompletionStatus should return very
* close to the target time and the second should reach it, but
* this is not stated in the documentation. To make sure a busy
* loop cannot happen, the timeout is increased exponentially
* starting on the third round.
*/
timeout += repeat ? (1 << (repeat - 1)) : 0;
continue;
}
}
break;
}
}
static void uv__poll(uv_loop_t* loop, DWORD timeout) {
BOOL success;
uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[128];
ULONG count;
ULONG i;
int repeat;
uint64_t timeout_time;
uint64_t user_timeout;
int reset_timeout;
timeout_time = loop->time + timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (repeat = 0; ; repeat++) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
success = pGetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
&count,
timeout,
FALSE);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
/* Placed here because on success the loop will break whether there is an
* empty package or not, or if GetQueuedCompletionStatus returned early then
* the timeout will be updated and the loop will run again. In either case
* the idle time will need to be updated.
*/
uv__metrics_update_idle_time(loop);
if (success) {
for (i = 0; i < count; i++) {
/* Package was dequeued, but see if it is not a empty package
* meant only to wake us up.
*/
if (overlappeds[i].lpOverlapped) {
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
uv_insert_pending_req(loop, req);
}
}
/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
} else if (timeout > 0) {
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout target time is reached.
*/
uv_update_time(loop);
if (timeout_time > loop->time) {
timeout = (DWORD)(timeout_time - loop->time);
/* The first call to GetQueuedCompletionStatus should return very
* close to the target time and the second should reach it, but
* this is not stated in the documentation. To make sure a busy
* loop cannot happen, the timeout is increased exponentially
* starting on the third round.
*/
timeout += repeat ? (1 << (repeat - 1)) : 0;
continue;
}
}
break;
}
}
static int uv__loop_alive(const uv_loop_t* loop) {
return uv__has_active_handles(loop) ||
uv__has_active_reqs(loop) ||
loop->endgame_handles != NULL;
}
int uv_loop_alive(const uv_loop_t* loop) {
return uv__loop_alive(loop);
}
int uv_run(uv_loop_t *loop, uv_run_mode mode) {
DWORD timeout;
int r;
int ran_pending;
r = uv__loop_alive(loop);
if (!r)
uv_update_time(loop);
while (r != 0 && loop->stop_flag == 0) {
uv_update_time(loop);
uv__run_timers(loop);
ran_pending = uv_process_reqs(loop);
uv_idle_invoke(loop);
uv_prepare_invoke(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
if (pGetQueuedCompletionStatusEx)
uv__poll(loop, timeout);
else
uv__poll_wine(loop, timeout);
/* Run one final update on the provider_idle_time in case uv__poll*
* returned because the timeout expired, but no events were received. This
* call will be ignored if the provider_entry_time was either never set (if
* the timeout == 0) or was already updated b/c an event was received.
*/
uv__metrics_update_idle_time(loop);
uv_check_invoke(loop);
uv_process_endgames(loop);
if (mode == UV_RUN_ONCE) {
/* UV_RUN_ONCE implies forward progress: at least one callback must have
* been invoked when it returns. uv__io_poll() can return without doing
* I/O (meaning: no callbacks) when its timeout expires - which means we
* have pending timers that satisfy the forward progress constraint.
*
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
* the check.
*/
uv__run_timers(loop);
}
r = uv__loop_alive(loop);
if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
break;
}
/* The if statement lets the compiler compile it to a conditional store.
* Avoids dirtying a cache line.
*/
if (loop->stop_flag != 0)
loop->stop_flag = 0;
return r;
}
int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
uv_os_fd_t fd_out;
switch (handle->type) {
case UV_TCP:
fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
break;
case UV_NAMED_PIPE:
fd_out = ((uv_pipe_t*) handle)->handle;
break;
case UV_TTY:
fd_out = ((uv_tty_t*) handle)->handle;
break;
case UV_UDP:
fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
break;
case UV_POLL:
fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
break;
default:
return UV_EINVAL;
}
if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
return UV_EBADF;
*fd = fd_out;
return 0;
}
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
int r;
int len;
SOCKET socket;
if (handle == NULL || value == NULL)
return UV_EINVAL;
if (handle->type == UV_TCP)
socket = ((uv_tcp_t*) handle)->socket;
else if (handle->type == UV_UDP)
socket = ((uv_udp_t*) handle)->socket;
else
return UV_ENOTSUP;
len = sizeof(*value);
if (*value == 0)
r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
else
r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
if (r == SOCKET_ERROR)
return uv_translate_sys_error(WSAGetLastError());
return 0;
}
int uv_cpumask_size(void) {
return (int)(sizeof(DWORD_PTR) * 8);
}
int uv__getsockpeername(const uv_handle_t* handle,
uv__peersockfunc func,
struct sockaddr* name,
int* namelen,
int delayed_error) {
int result;
uv_os_fd_t fd;
result = uv_fileno(handle, &fd);
if (result != 0)
return result;
if (delayed_error)
return uv_translate_sys_error(delayed_error);
result = func((SOCKET) fd, name, namelen);
if (result != 0)
return uv_translate_sys_error(WSAGetLastError());
return 0;
}

56
deps/libuv/src/win/detect-wakeup.c vendored Normal file
View File

@ -0,0 +1,56 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include "winapi.h"
static void uv__register_system_resume_callback(void);
void uv__init_detect_system_wakeup(void) {
/* Try registering system power event callback. This is the cleanest
* method, but it will only work on Win8 and above.
*/
uv__register_system_resume_callback();
}
static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
ULONG Type,
PVOID Setting) {
if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
uv__wake_all_loops();
return 0;
}
static void uv__register_system_resume_callback(void) {
_DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
_HPOWERNOTIFY registration_handle;
if (pPowerRegisterSuspendResumeNotification == NULL)
return;
recipient.Callback = uv__system_resume_callback;
recipient.Context = NULL;
(*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
&recipient,
&registration_handle);
}

136
deps/libuv/src/win/dl.c vendored Normal file
View File

@ -0,0 +1,136 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno);
int uv_dlopen(const char* filename, uv_lib_t* lib) {
WCHAR filename_w[32768];
lib->handle = NULL;
lib->errmsg = NULL;
if (!MultiByteToWideChar(CP_UTF8,
0,
filename,
-1,
filename_w,
ARRAY_SIZE(filename_w))) {
return uv__dlerror(lib, filename, GetLastError());
}
lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (lib->handle == NULL) {
return uv__dlerror(lib, filename, GetLastError());
}
return 0;
}
void uv_dlclose(uv_lib_t* lib) {
if (lib->errmsg) {
LocalFree((void*)lib->errmsg);
lib->errmsg = NULL;
}
if (lib->handle) {
/* Ignore errors. No good way to signal them without leaking memory. */
FreeLibrary(lib->handle);
lib->handle = NULL;
}
}
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
/* Cast though integer to suppress pedantic warning about forbidden cast. */
*ptr = (void*)(uintptr_t) GetProcAddress(lib->handle, name);
return uv__dlerror(lib, "", *ptr ? 0 : GetLastError());
}
const char* uv_dlerror(const uv_lib_t* lib) {
return lib->errmsg ? lib->errmsg : "no error";
}
static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
static const CHAR fallback_error[] = "error: %1!d!";
DWORD_PTR args[1];
args[0] = (DWORD_PTR) errorno;
FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
fallback_error, 0, 0,
(LPSTR) &lib->errmsg,
0, (va_list*) args);
}
static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) {
DWORD_PTR arg;
DWORD res;
char* msg;
if (lib->errmsg) {
LocalFree(lib->errmsg);
lib->errmsg = NULL;
}
if (errorno == 0)
return 0;
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(LPSTR) &lib->errmsg, 0, NULL);
if (!res && (GetLastError() == ERROR_MUI_FILE_NOT_FOUND ||
GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)) {
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
0, (LPSTR) &lib->errmsg, 0, NULL);
}
if (res && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) {
msg = lib->errmsg;
lib->errmsg = NULL;
arg = (DWORD_PTR) filename;
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_FROM_STRING,
msg,
0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg);
LocalFree(msg);
}
if (!res)
uv__format_fallback_error(lib, errorno);
return -1;
}

173
deps/libuv/src/win/error.c vendored Normal file
View File

@ -0,0 +1,173 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uv.h"
#include "internal.h"
/*
* Display an error message and abort the event loop.
*/
void uv_fatal_error(const int errorno, const char* syscall) {
char* buf = NULL;
const char* errmsg;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
if (buf) {
errmsg = buf;
} else {
errmsg = "Unknown error";
}
/* FormatMessage messages include a newline character already, so don't add
* another. */
if (syscall) {
fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
} else {
fprintf(stderr, "(%d) %s", errorno, errmsg);
}
if (buf) {
LocalFree(buf);
}
DebugBreak();
abort();
}
int uv_translate_sys_error(int sys_errno) {
if (sys_errno <= 0) {
return sys_errno; /* If < 0 then it's already a libuv error. */
}
switch (sys_errno) {
case ERROR_NOACCESS: return UV_EACCES;
case WSAEACCES: return UV_EACCES;
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
case ERROR_CANT_ACCESS_FILE: return UV_EACCES;
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
case WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
case WSAEWOULDBLOCK: return UV_EAGAIN;
case WSAEALREADY: return UV_EALREADY;
case ERROR_INVALID_FLAGS: return UV_EBADF;
case ERROR_INVALID_HANDLE: return UV_EBADF;
case ERROR_LOCK_VIOLATION: return UV_EBUSY;
case ERROR_PIPE_BUSY: return UV_EBUSY;
case ERROR_SHARING_VIOLATION: return UV_EBUSY;
case ERROR_OPERATION_ABORTED: return UV_ECANCELED;
case WSAEINTR: return UV_ECANCELED;
case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET;
case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED;
case WSAECONNABORTED: return UV_ECONNABORTED;
case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
case WSAECONNREFUSED: return UV_ECONNREFUSED;
case ERROR_NETNAME_DELETED: return UV_ECONNRESET;
case WSAECONNRESET: return UV_ECONNRESET;
case ERROR_ALREADY_EXISTS: return UV_EEXIST;
case ERROR_FILE_EXISTS: return UV_EEXIST;
case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
case WSAEFAULT: return UV_EFAULT;
case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
case ERROR_INVALID_DATA: return UV_EINVAL;
case ERROR_INVALID_PARAMETER: return UV_EINVAL;
case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
case WSAEINVAL: return UV_EINVAL;
case WSAEPFNOSUPPORT: return UV_EINVAL;
case WSAESOCKTNOSUPPORT: return UV_EINVAL;
case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
case ERROR_BUS_RESET: return UV_EIO;
case ERROR_CRC: return UV_EIO;
case ERROR_DEVICE_DOOR_OPEN: return UV_EIO;
case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO;
case ERROR_DISK_CORRUPT: return UV_EIO;
case ERROR_EOM_OVERFLOW: return UV_EIO;
case ERROR_FILEMARK_DETECTED: return UV_EIO;
case ERROR_GEN_FAILURE: return UV_EIO;
case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO;
case ERROR_IO_DEVICE: return UV_EIO;
case ERROR_NO_DATA_DETECTED: return UV_EIO;
case ERROR_NO_SIGNAL_SENT: return UV_EIO;
case ERROR_OPEN_FAILED: return UV_EIO;
case ERROR_SETMARK_DETECTED: return UV_EIO;
case ERROR_SIGNAL_REFUSED: return UV_EIO;
case WSAEISCONN: return UV_EISCONN;
case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP;
case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
case WSAEMFILE: return UV_EMFILE;
case WSAEMSGSIZE: return UV_EMSGSIZE;
case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
case WSAENETUNREACH: return UV_ENETUNREACH;
case WSAENOBUFS: return UV_ENOBUFS;
case ERROR_BAD_PATHNAME: return UV_ENOENT;
case ERROR_DIRECTORY: return UV_ENOENT;
case ERROR_ENVVAR_NOT_FOUND: return UV_ENOENT;
case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
case ERROR_INVALID_NAME: return UV_ENOENT;
case ERROR_INVALID_DRIVE: return UV_ENOENT;
case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
case WSAHOST_NOT_FOUND: return UV_ENOENT;
case WSANO_DATA: return UV_ENOENT;
case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM;
case ERROR_OUTOFMEMORY: return UV_ENOMEM;
case ERROR_CANNOT_MAKE: return UV_ENOSPC;
case ERROR_DISK_FULL: return UV_ENOSPC;
case ERROR_EA_TABLE_FULL: return UV_ENOSPC;
case ERROR_END_OF_MEDIA: return UV_ENOSPC;
case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC;
case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
case WSAENOTCONN: return UV_ENOTCONN;
case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY;
case WSAENOTSOCK: return UV_ENOTSOCK;
case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
case ERROR_BROKEN_PIPE: return UV_EOF;
case ERROR_ACCESS_DENIED: return UV_EPERM;
case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
case ERROR_BAD_PIPE: return UV_EPIPE;
case ERROR_NO_DATA: return UV_EPIPE;
case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
case WSAESHUTDOWN: return UV_EPIPE;
case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
case ERROR_WRITE_PROTECT: return UV_EROFS;
case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
case WSAETIMEDOUT: return UV_ETIMEDOUT;
case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
case ERROR_INVALID_FUNCTION: return UV_EISDIR;
case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
default: return UV_UNKNOWN;
}
}

608
deps/libuv/src/win/fs-event.c vendored Normal file
View File

@ -0,0 +1,608 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
const unsigned int uv_directory_watcher_buffer_size = 4096;
static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
uv_fs_event_t* handle) {
assert(handle->dir_handle != INVALID_HANDLE_VALUE);
assert(!handle->req_pending);
memset(&(handle->req.u.io.overlapped), 0,
sizeof(handle->req.u.io.overlapped));
if (!ReadDirectoryChangesW(handle->dir_handle,
handle->buffer,
uv_directory_watcher_buffer_size,
(handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY,
NULL,
&handle->req.u.io.overlapped,
NULL)) {
/* Make this req pending reporting an error. */
SET_REQ_ERROR(&handle->req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
}
handle->req_pending = 1;
}
static void uv_relative_path(const WCHAR* filename,
const WCHAR* dir,
WCHAR** relpath) {
size_t relpathlen;
size_t filenamelen = wcslen(filename);
size_t dirlen = wcslen(dir);
assert(!_wcsnicmp(filename, dir, dirlen));
if (dirlen > 0 && dir[dirlen - 1] == '\\')
dirlen--;
relpathlen = filenamelen - dirlen - 1;
*relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR));
if (!*relpath)
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
wcsncpy(*relpath, filename + dirlen + 1, relpathlen);
(*relpath)[relpathlen] = L'\0';
}
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
WCHAR** file) {
size_t len, i;
DWORD dir_len;
if (filename == NULL) {
if (dir != NULL)
*dir = NULL;
*file = NULL;
return 0;
}
len = wcslen(filename);
i = len;
while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
if (i == 0) {
if (dir) {
dir_len = GetCurrentDirectoryW(0, NULL);
if (dir_len == 0) {
return -1;
}
*dir = (WCHAR*)uv__malloc(dir_len * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!GetCurrentDirectoryW(dir_len, *dir)) {
uv__free(*dir);
*dir = NULL;
return -1;
}
}
*file = wcsdup(filename);
} else {
if (dir) {
*dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
wcsncpy(*dir, filename, i + 1);
(*dir)[i + 1] = L'\0';
}
*file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
if (!*file) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
wcsncpy(*file, filename + i + 1, len - i - 1);
(*file)[len - i - 1] = L'\0';
}
return 0;
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
handle->dir_handle = INVALID_HANDLE_VALUE;
handle->buffer = NULL;
handle->req_pending = 0;
handle->filew = NULL;
handle->short_filew = NULL;
handle->dirw = NULL;
UV_REQ_INIT(&handle->req, UV_FS_EVENT_REQ);
handle->req.data = handle;
return 0;
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
const char* path,
unsigned int flags) {
int name_size, is_path_dir, size;
DWORD attr, last_error;
WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
DWORD short_path_buffer_len;
WCHAR *short_path_buffer;
WCHAR* short_path, *long_path;
short_path = NULL;
if (uv__is_active(handle))
return UV_EINVAL;
handle->cb = cb;
handle->path = uv__strdup(path);
if (!handle->path) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
uv__handle_start(handle);
/* Convert name to UTF16. */
name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
sizeof(WCHAR);
pathw = (WCHAR*)uv__malloc(name_size);
if (!pathw) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!MultiByteToWideChar(CP_UTF8,
0,
path,
-1,
pathw,
name_size / sizeof(WCHAR))) {
return uv_translate_sys_error(GetLastError());
}
/* Determine whether path is a file or a directory. */
attr = GetFileAttributesW(pathw);
if (attr == INVALID_FILE_ATTRIBUTES) {
last_error = GetLastError();
goto error;
}
is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
if (is_path_dir) {
/* path is a directory, so that's the directory that we will watch. */
/* Convert to long path. */
size = GetLongPathNameW(pathw, NULL, 0);
if (size) {
long_path = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
if (!long_path) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
size = GetLongPathNameW(pathw, long_path, size);
if (size) {
long_path[size] = '\0';
} else {
uv__free(long_path);
long_path = NULL;
}
if (long_path) {
uv__free(pathw);
pathw = long_path;
}
}
dir_to_watch = pathw;
} else {
/*
* path is a file. So we split path into dir & file parts, and
* watch the dir directory.
*/
/* Convert to short path. */
short_path_buffer = NULL;
short_path_buffer_len = GetShortPathNameW(pathw, NULL, 0);
if (short_path_buffer_len == 0) {
goto short_path_done;
}
short_path_buffer = uv__malloc(short_path_buffer_len * sizeof(WCHAR));
if (short_path_buffer == NULL) {
goto short_path_done;
}
if (GetShortPathNameW(pathw,
short_path_buffer,
short_path_buffer_len) == 0) {
uv__free(short_path_buffer);
short_path_buffer = NULL;
}
short_path_done:
short_path = short_path_buffer;
if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
last_error = GetLastError();
goto error;
}
if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
last_error = GetLastError();
goto error;
}
dir_to_watch = dir;
uv__free(pathw);
pathw = NULL;
}
handle->dir_handle = CreateFileW(dir_to_watch,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_DELETE |
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED,
NULL);
if (dir) {
uv__free(dir);
dir = NULL;
}
if (handle->dir_handle == INVALID_HANDLE_VALUE) {
last_error = GetLastError();
goto error;
}
if (CreateIoCompletionPort(handle->dir_handle,
handle->loop->iocp,
(ULONG_PTR)handle,
0) == NULL) {
last_error = GetLastError();
goto error;
}
if (!handle->buffer) {
handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
}
if (!handle->buffer) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
memset(&(handle->req.u.io.overlapped), 0,
sizeof(handle->req.u.io.overlapped));
if (!ReadDirectoryChangesW(handle->dir_handle,
handle->buffer,
uv_directory_watcher_buffer_size,
(flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY,
NULL,
&handle->req.u.io.overlapped,
NULL)) {
last_error = GetLastError();
goto error;
}
assert(is_path_dir ? pathw != NULL : pathw == NULL);
handle->dirw = pathw;
handle->req_pending = 1;
return 0;
error:
if (handle->path) {
uv__free(handle->path);
handle->path = NULL;
}
if (handle->filew) {
uv__free(handle->filew);
handle->filew = NULL;
}
if (handle->short_filew) {
uv__free(handle->short_filew);
handle->short_filew = NULL;
}
uv__free(pathw);
if (handle->dir_handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle->dir_handle);
handle->dir_handle = INVALID_HANDLE_VALUE;
}
if (handle->buffer) {
uv__free(handle->buffer);
handle->buffer = NULL;
}
if (uv__is_active(handle))
uv__handle_stop(handle);
uv__free(short_path);
return uv_translate_sys_error(last_error);
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
return 0;
if (handle->dir_handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle->dir_handle);
handle->dir_handle = INVALID_HANDLE_VALUE;
}
uv__handle_stop(handle);
if (handle->filew) {
uv__free(handle->filew);
handle->filew = NULL;
}
if (handle->short_filew) {
uv__free(handle->short_filew);
handle->short_filew = NULL;
}
if (handle->path) {
uv__free(handle->path);
handle->path = NULL;
}
if (handle->dirw) {
uv__free(handle->dirw);
handle->dirw = NULL;
}
return 0;
}
static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
size_t str_len;
if (str == NULL)
return -1;
str_len = wcslen(str);
/*
Since we only care about equality, return early if the strings
aren't the same length
*/
if (str_len != (file_name_len / sizeof(WCHAR)))
return -1;
return _wcsnicmp(str, file_name, str_len);
}
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
uv_fs_event_t* handle) {
FILE_NOTIFY_INFORMATION* file_info;
int err, sizew, size;
char* filename = NULL;
WCHAR* filenamew = NULL;
WCHAR* long_filenamew = NULL;
DWORD offset = 0;
assert(req->type == UV_FS_EVENT_REQ);
assert(handle->req_pending);
handle->req_pending = 0;
/* Don't report any callbacks if:
* - We're closing, just push the handle onto the endgame queue
* - We are not active, just ignore the callback
*/
if (!uv__is_active(handle)) {
if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
return;
}
file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
if (REQ_SUCCESS(req)) {
if (req->u.io.overlapped.InternalHigh > 0) {
do {
file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
assert(!filename);
assert(!filenamew);
assert(!long_filenamew);
/*
* Fire the event only if we were asked to watch a directory,
* or if the filename filter matches.
*/
if (handle->dirw ||
file_info_cmp(handle->filew,
file_info->FileName,
file_info->FileNameLength) == 0 ||
file_info_cmp(handle->short_filew,
file_info->FileName,
file_info->FileNameLength) == 0) {
if (handle->dirw) {
/*
* We attempt to resolve the long form of the file name explicitly.
* We only do this for file names that might still exist on disk.
* If this fails, we use the name given by ReadDirectoryChangesW.
* This may be the long form or the 8.3 short name in some cases.
*/
if (file_info->Action != FILE_ACTION_REMOVED &&
file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
/* Construct a full path to the file. */
size = wcslen(handle->dirw) +
file_info->FileNameLength / sizeof(WCHAR) + 2;
filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
if (!filenamew) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
_snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
file_info->FileNameLength / (DWORD)sizeof(WCHAR),
file_info->FileName);
filenamew[size - 1] = L'\0';
/* Convert to long name. */
size = GetLongPathNameW(filenamew, NULL, 0);
if (size) {
long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
if (!long_filenamew) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
size = GetLongPathNameW(filenamew, long_filenamew, size);
if (size) {
long_filenamew[size] = '\0';
} else {
uv__free(long_filenamew);
long_filenamew = NULL;
}
}
uv__free(filenamew);
if (long_filenamew) {
/* Get the file name out of the long path. */
uv_relative_path(long_filenamew,
handle->dirw,
&filenamew);
uv__free(long_filenamew);
long_filenamew = filenamew;
sizew = -1;
} else {
/* We couldn't get the long filename, use the one reported. */
filenamew = file_info->FileName;
sizew = file_info->FileNameLength / sizeof(WCHAR);
}
} else {
/*
* Removed or renamed events cannot be resolved to the long form.
* We therefore use the name given by ReadDirectoryChangesW.
* This may be the long form or the 8.3 short name in some cases.
*/
filenamew = file_info->FileName;
sizew = file_info->FileNameLength / sizeof(WCHAR);
}
} else {
/* We already have the long name of the file, so just use it. */
filenamew = handle->filew;
sizew = -1;
}
/* Convert the filename to utf8. */
uv__convert_utf16_to_utf8(filenamew, sizew, &filename);
switch (file_info->Action) {
case FILE_ACTION_ADDED:
case FILE_ACTION_REMOVED:
case FILE_ACTION_RENAMED_OLD_NAME:
case FILE_ACTION_RENAMED_NEW_NAME:
handle->cb(handle, filename, UV_RENAME, 0);
break;
case FILE_ACTION_MODIFIED:
handle->cb(handle, filename, UV_CHANGE, 0);
break;
}
uv__free(filename);
filename = NULL;
uv__free(long_filenamew);
long_filenamew = NULL;
filenamew = NULL;
}
offset = file_info->NextEntryOffset;
} while (offset && !(handle->flags & UV_HANDLE_CLOSING));
} else {
handle->cb(handle, NULL, UV_CHANGE, 0);
}
} else {
err = GET_REQ_ERROR(req);
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
}
if (!(handle->flags & UV_HANDLE_CLOSING)) {
uv_fs_event_queue_readdirchanges(loop, handle);
} else {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
}
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
uv__handle_closing(handle);
if (!handle->req_pending) {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
}
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
if (handle->buffer) {
uv__free(handle->buffer);
handle->buffer = NULL;
}
uv__handle_close(handle);
}
}

200
deps/libuv/src/win/fs-fd-hash-inl.h vendored Normal file
View File

@ -0,0 +1,200 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_WIN_FS_FD_HASH_INL_H_
#define UV_WIN_FS_FD_HASH_INL_H_
#include "uv.h"
#include "internal.h"
/* Files are only inserted in uv__fd_hash when the UV_FS_O_FILEMAP flag is
* specified. Thus, when uv__fd_hash_get returns true, the file mapping in the
* info structure should be used for read/write operations.
*
* If the file is empty, the mapping field will be set to
* INVALID_HANDLE_VALUE. This is not an issue since the file mapping needs to
* be created anyway when the file size changes.
*
* Since file descriptors are sequential integers, the modulo operator is used
* as hashing function. For each bucket, a single linked list of arrays is
* kept to minimize allocations. A statically allocated memory buffer is kept
* for the first array in each bucket. */
#define UV__FD_HASH_SIZE 256
#define UV__FD_HASH_GROUP_SIZE 16
struct uv__fd_info_s {
int flags;
BOOLEAN is_directory;
HANDLE mapping;
LARGE_INTEGER size;
LARGE_INTEGER current_pos;
};
struct uv__fd_hash_entry_s {
uv_file fd;
struct uv__fd_info_s info;
};
struct uv__fd_hash_entry_group_s {
struct uv__fd_hash_entry_s entries[UV__FD_HASH_GROUP_SIZE];
struct uv__fd_hash_entry_group_s* next;
};
struct uv__fd_hash_bucket_s {
size_t size;
struct uv__fd_hash_entry_group_s* data;
};
static uv_mutex_t uv__fd_hash_mutex;
static struct uv__fd_hash_entry_group_s
uv__fd_hash_entry_initial[UV__FD_HASH_SIZE * UV__FD_HASH_GROUP_SIZE];
static struct uv__fd_hash_bucket_s uv__fd_hash[UV__FD_HASH_SIZE];
INLINE static void uv__fd_hash_init(void) {
size_t i;
int err;
err = uv_mutex_init(&uv__fd_hash_mutex);
if (err) {
uv_fatal_error(err, "uv_mutex_init");
}
for (i = 0; i < ARRAY_SIZE(uv__fd_hash); ++i) {
uv__fd_hash[i].size = 0;
uv__fd_hash[i].data =
uv__fd_hash_entry_initial + i * UV__FD_HASH_GROUP_SIZE;
}
}
#define FIND_COMMON_VARIABLES \
unsigned i; \
unsigned bucket = fd % ARRAY_SIZE(uv__fd_hash); \
struct uv__fd_hash_entry_s* entry_ptr = NULL; \
struct uv__fd_hash_entry_group_s* group_ptr; \
struct uv__fd_hash_bucket_s* bucket_ptr = &uv__fd_hash[bucket];
#define FIND_IN_GROUP_PTR(group_size) \
do { \
for (i = 0; i < group_size; ++i) { \
if (group_ptr->entries[i].fd == fd) { \
entry_ptr = &group_ptr->entries[i]; \
break; \
} \
} \
} while (0)
#define FIND_IN_BUCKET_PTR() \
do { \
size_t first_group_size = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE; \
if (bucket_ptr->size != 0 && first_group_size == 0) \
first_group_size = UV__FD_HASH_GROUP_SIZE; \
group_ptr = bucket_ptr->data; \
FIND_IN_GROUP_PTR(first_group_size); \
for (group_ptr = group_ptr->next; \
group_ptr != NULL && entry_ptr == NULL; \
group_ptr = group_ptr->next) \
FIND_IN_GROUP_PTR(UV__FD_HASH_GROUP_SIZE); \
} while (0)
INLINE static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) {
FIND_COMMON_VARIABLES
uv_mutex_lock(&uv__fd_hash_mutex);
FIND_IN_BUCKET_PTR();
if (entry_ptr != NULL) {
*info = entry_ptr->info;
}
uv_mutex_unlock(&uv__fd_hash_mutex);
return entry_ptr != NULL;
}
INLINE static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) {
FIND_COMMON_VARIABLES
uv_mutex_lock(&uv__fd_hash_mutex);
FIND_IN_BUCKET_PTR();
if (entry_ptr == NULL) {
i = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE;
if (bucket_ptr->size != 0 && i == 0) {
struct uv__fd_hash_entry_group_s* new_group_ptr =
uv__malloc(sizeof(*new_group_ptr));
if (new_group_ptr == NULL) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
new_group_ptr->next = bucket_ptr->data;
bucket_ptr->data = new_group_ptr;
}
bucket_ptr->size += 1;
entry_ptr = &bucket_ptr->data->entries[i];
entry_ptr->fd = fd;
}
entry_ptr->info = *info;
uv_mutex_unlock(&uv__fd_hash_mutex);
}
INLINE static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) {
FIND_COMMON_VARIABLES
uv_mutex_lock(&uv__fd_hash_mutex);
FIND_IN_BUCKET_PTR();
if (entry_ptr != NULL) {
*info = entry_ptr->info;
bucket_ptr->size -= 1;
i = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE;
if (entry_ptr != &bucket_ptr->data->entries[i]) {
*entry_ptr = bucket_ptr->data->entries[i];
}
if (bucket_ptr->size != 0 &&
bucket_ptr->size % UV__FD_HASH_GROUP_SIZE == 0) {
struct uv__fd_hash_entry_group_s* old_group_ptr = bucket_ptr->data;
bucket_ptr->data = old_group_ptr->next;
uv__free(old_group_ptr);
}
}
uv_mutex_unlock(&uv__fd_hash_mutex);
return entry_ptr != NULL;
}
#undef FIND_COMMON_VARIABLES
#undef FIND_IN_GROUP_PTR
#undef FIND_IN_BUCKET_PTR
#endif /* UV_WIN_FS_FD_HASH_INL_H_ */

3428
deps/libuv/src/win/fs.c vendored Normal file

File diff suppressed because it is too large Load Diff

463
deps/libuv/src/win/getaddrinfo.c vendored Normal file
View File

@ -0,0 +1,463 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include "uv.h"
#include "internal.h"
#include "req-inl.h"
#include "idna.h"
/* EAI_* constants. */
#include <winsock2.h>
/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
#include <iphlpapi.h>
int uv__getaddrinfo_translate_error(int sys_err) {
switch (sys_err) {
case 0: return 0;
case WSATRY_AGAIN: return UV_EAI_AGAIN;
case WSAEINVAL: return UV_EAI_BADFLAGS;
case WSANO_RECOVERY: return UV_EAI_FAIL;
case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
default: return uv_translate_sys_error(sys_err);
}
}
/*
* MinGW is missing this
*/
#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
typedef struct addrinfoW {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
WCHAR* ai_canonname;
struct sockaddr* ai_addr;
struct addrinfoW* ai_next;
} ADDRINFOW, *PADDRINFOW;
DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
const WCHAR* service,
const ADDRINFOW* hints,
PADDRINFOW* result);
DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
#endif
/* Adjust size value to be multiple of 4. Use to keep pointer aligned.
* Do we need different versions of this for different architectures? */
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
#ifndef NDIS_IF_MAX_STRING_SIZE
#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
#endif
static void uv__getaddrinfo_work(struct uv__work* w) {
uv_getaddrinfo_t* req;
struct addrinfoW* hints;
int err;
req = container_of(w, uv_getaddrinfo_t, work_req);
hints = req->addrinfow;
req->addrinfow = NULL;
err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
req->retcode = uv__getaddrinfo_translate_error(err);
}
/*
* Called from uv_run when complete. Call user specified callback
* then free returned addrinfo
* Returned addrinfo strings are converted from UTF-16 to UTF-8.
*
* To minimize allocation we calculate total size required,
* and copy all structs and referenced strings into the one block.
* Each size calculation is adjusted to avoid unaligned pointers.
*/
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
uv_getaddrinfo_t* req;
int addrinfo_len = 0;
int name_len = 0;
size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
struct addrinfoW* addrinfow_ptr;
struct addrinfo* addrinfo_ptr;
char* alloc_ptr = NULL;
char* cur_ptr = NULL;
req = container_of(w, uv_getaddrinfo_t, work_req);
/* release input parameter memory */
uv__free(req->alloc);
req->alloc = NULL;
if (status == UV_ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
goto complete;
}
if (req->retcode == 0) {
/* Convert addrinfoW to addrinfo. First calculate required length. */
addrinfow_ptr = req->addrinfow;
while (addrinfow_ptr != NULL) {
addrinfo_len += addrinfo_struct_len +
ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
NULL,
0,
NULL,
NULL);
if (name_len == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
goto complete;
}
addrinfo_len += ALIGNED_SIZE(name_len);
}
addrinfow_ptr = addrinfow_ptr->ai_next;
}
/* allocate memory for addrinfo results */
alloc_ptr = (char*)uv__malloc(addrinfo_len);
/* do conversions */
if (alloc_ptr != NULL) {
cur_ptr = alloc_ptr;
addrinfow_ptr = req->addrinfow;
while (addrinfow_ptr != NULL) {
/* copy addrinfo struct data */
assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
addrinfo_ptr = (struct addrinfo*)cur_ptr;
addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
addrinfo_ptr->ai_canonname = NULL;
addrinfo_ptr->ai_addr = NULL;
addrinfo_ptr->ai_next = NULL;
cur_ptr += addrinfo_struct_len;
/* copy sockaddr */
if (addrinfo_ptr->ai_addrlen > 0) {
assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
alloc_ptr + addrinfo_len);
memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
}
/* convert canonical name to UTF-8 */
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
NULL,
0,
NULL,
NULL);
assert(name_len > 0);
assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
cur_ptr,
name_len,
NULL,
NULL);
assert(name_len > 0);
addrinfo_ptr->ai_canonname = cur_ptr;
cur_ptr += ALIGNED_SIZE(name_len);
}
assert(cur_ptr <= alloc_ptr + addrinfo_len);
/* set next ptr */
addrinfow_ptr = addrinfow_ptr->ai_next;
if (addrinfow_ptr != NULL) {
addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
}
}
req->addrinfo = (struct addrinfo*)alloc_ptr;
} else {
req->retcode = UV_EAI_MEMORY;
}
}
/* return memory to system */
if (req->addrinfow != NULL) {
FreeAddrInfoW(req->addrinfow);
req->addrinfow = NULL;
}
complete:
uv__req_unregister(req->loop, req);
/* finally do callback with converted result */
if (req->getaddrinfo_cb)
req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
}
void uv_freeaddrinfo(struct addrinfo* ai) {
char* alloc_ptr = (char*)ai;
/* release copied result memory */
uv__free(alloc_ptr);
}
/*
* Entry point for getaddrinfo
* we convert the UTF-8 strings to UNICODE
* and save the UNICODE string pointers in the req
* We also copy hints so that caller does not need to keep memory until the
* callback.
* return 0 if a callback will be made
* return error code if validation fails
*
* To minimize allocation we calculate total size required,
* and copy all structs and referenced strings into the one block.
* Each size calculation is adjusted to avoid unaligned pointers.
*/
int uv_getaddrinfo(uv_loop_t* loop,
uv_getaddrinfo_t* req,
uv_getaddrinfo_cb getaddrinfo_cb,
const char* node,
const char* service,
const struct addrinfo* hints) {
char hostname_ascii[256];
int nodesize = 0;
int servicesize = 0;
int hintssize = 0;
char* alloc_ptr = NULL;
int err;
long rc;
if (req == NULL || (node == NULL && service == NULL)) {
return UV_EINVAL;
}
UV_REQ_INIT(req, UV_GETADDRINFO);
req->getaddrinfo_cb = getaddrinfo_cb;
req->addrinfo = NULL;
req->loop = loop;
req->retcode = 0;
/* calculate required memory size for all input values */
if (node != NULL) {
rc = uv__idna_toascii(node,
node + strlen(node),
hostname_ascii,
hostname_ascii + sizeof(hostname_ascii));
if (rc < 0)
return rc;
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
-1, NULL, 0) * sizeof(WCHAR));
if (nodesize == 0) {
err = GetLastError();
goto error;
}
node = hostname_ascii;
}
if (service != NULL) {
servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
0,
service,
-1,
NULL,
0) *
sizeof(WCHAR));
if (servicesize == 0) {
err = GetLastError();
goto error;
}
}
if (hints != NULL) {
hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
}
/* allocate memory for inputs, and partition it as needed */
alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
if (!alloc_ptr) {
err = WSAENOBUFS;
goto error;
}
/* save alloc_ptr now so we can free if error */
req->alloc = (void*)alloc_ptr;
/* Convert node string to UTF16 into allocated memory and save pointer in the
* request. */
if (node != NULL) {
req->node = (WCHAR*)alloc_ptr;
if (MultiByteToWideChar(CP_UTF8,
0,
node,
-1,
(WCHAR*) alloc_ptr,
nodesize / sizeof(WCHAR)) == 0) {
err = GetLastError();
goto error;
}
alloc_ptr += nodesize;
} else {
req->node = NULL;
}
/* Convert service string to UTF16 into allocated memory and save pointer in
* the req. */
if (service != NULL) {
req->service = (WCHAR*)alloc_ptr;
if (MultiByteToWideChar(CP_UTF8,
0,
service,
-1,
(WCHAR*) alloc_ptr,
servicesize / sizeof(WCHAR)) == 0) {
err = GetLastError();
goto error;
}
alloc_ptr += servicesize;
} else {
req->service = NULL;
}
/* copy hints to allocated memory and save pointer in req */
if (hints != NULL) {
req->addrinfow = (struct addrinfoW*)alloc_ptr;
req->addrinfow->ai_family = hints->ai_family;
req->addrinfow->ai_socktype = hints->ai_socktype;
req->addrinfow->ai_protocol = hints->ai_protocol;
req->addrinfow->ai_flags = hints->ai_flags;
req->addrinfow->ai_addrlen = 0;
req->addrinfow->ai_canonname = NULL;
req->addrinfow->ai_addr = NULL;
req->addrinfow->ai_next = NULL;
} else {
req->addrinfow = NULL;
}
uv__req_register(loop, req);
if (getaddrinfo_cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getaddrinfo_work,
uv__getaddrinfo_done);
return 0;
} else {
uv__getaddrinfo_work(&req->work_req);
uv__getaddrinfo_done(&req->work_req, 0);
return req->retcode;
}
error:
if (req != NULL) {
uv__free(req->alloc);
req->alloc = NULL;
}
return uv_translate_sys_error(err);
}
int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
NET_LUID luid;
wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
DWORD bufsize;
int r;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
r = ConvertInterfaceIndexToLuid(ifindex, &luid);
if (r != 0)
return uv_translate_sys_error(r);
r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
if (r != 0)
return uv_translate_sys_error(r);
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
*size = bufsize;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
wname,
-1,
buffer,
*size,
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
*size = bufsize - 1;
return 0;
}
int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
int r;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
r = snprintf(buffer, *size, "%d", ifindex);
if (r < 0)
return uv_translate_sys_error(r);
if (r >= (int) *size) {
*size = r + 1;
return UV_ENOBUFS;
}
*size = r;
return 0;
}

157
deps/libuv/src/win/getnameinfo.c vendored Normal file
View File

@ -0,0 +1,157 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <stdio.h>
#include "uv.h"
#include "internal.h"
#include "req-inl.h"
#ifndef GetNameInfo
int WSAAPI GetNameInfoW(
const SOCKADDR *pSockaddr,
socklen_t SockaddrLength,
PWCHAR pNodeBuffer,
DWORD NodeBufferSize,
PWCHAR pServiceBuffer,
DWORD ServiceBufferSize,
INT Flags
);
#endif
static void uv__getnameinfo_work(struct uv__work* w) {
uv_getnameinfo_t* req;
WCHAR host[NI_MAXHOST];
WCHAR service[NI_MAXSERV];
int ret;
req = container_of(w, uv_getnameinfo_t, work_req);
if (GetNameInfoW((struct sockaddr*)&req->storage,
sizeof(req->storage),
host,
ARRAY_SIZE(host),
service,
ARRAY_SIZE(service),
req->flags)) {
ret = WSAGetLastError();
req->retcode = uv__getaddrinfo_translate_error(ret);
return;
}
ret = WideCharToMultiByte(CP_UTF8,
0,
host,
-1,
req->host,
sizeof(req->host),
NULL,
NULL);
if (ret == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
return;
}
ret = WideCharToMultiByte(CP_UTF8,
0,
service,
-1,
req->service,
sizeof(req->service),
NULL,
NULL);
if (ret == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
}
}
/*
* Called from uv_run when complete.
*/
static void uv__getnameinfo_done(struct uv__work* w, int status) {
uv_getnameinfo_t* req;
char* host;
char* service;
req = container_of(w, uv_getnameinfo_t, work_req);
uv__req_unregister(req->loop, req);
host = service = NULL;
if (status == UV_ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
} else if (req->retcode == 0) {
host = req->host;
service = req->service;
}
if (req->getnameinfo_cb)
req->getnameinfo_cb(req, req->retcode, host, service);
}
/*
* Entry point for getnameinfo
* return 0 if a callback will be made
* return error code if validation fails
*/
int uv_getnameinfo(uv_loop_t* loop,
uv_getnameinfo_t* req,
uv_getnameinfo_cb getnameinfo_cb,
const struct sockaddr* addr,
int flags) {
if (req == NULL || addr == NULL)
return UV_EINVAL;
if (addr->sa_family == AF_INET) {
memcpy(&req->storage,
addr,
sizeof(struct sockaddr_in));
} else if (addr->sa_family == AF_INET6) {
memcpy(&req->storage,
addr,
sizeof(struct sockaddr_in6));
} else {
return UV_EINVAL;
}
UV_REQ_INIT(req, UV_GETNAMEINFO);
uv__req_register(loop, req);
req->getnameinfo_cb = getnameinfo_cb;
req->flags = flags;
req->loop = loop;
req->retcode = 0;
if (getnameinfo_cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getnameinfo_work,
uv__getnameinfo_done);
return 0;
} else {
uv__getnameinfo_work(&req->work_req);
uv__getnameinfo_done(&req->work_req, 0);
return req->retcode;
}
}

180
deps/libuv/src/win/handle-inl.h vendored Normal file
View File

@ -0,0 +1,180 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_WIN_HANDLE_INL_H_
#define UV_WIN_HANDLE_INL_H_
#include <assert.h>
#include <io.h>
#include "uv.h"
#include "internal.h"
#define DECREASE_ACTIVE_COUNT(loop, handle) \
do { \
if (--(handle)->activecnt == 0 && \
!((handle)->flags & UV_HANDLE_CLOSING)) { \
uv__handle_stop((handle)); \
} \
assert((handle)->activecnt >= 0); \
} while (0)
#define INCREASE_ACTIVE_COUNT(loop, handle) \
do { \
if ((handle)->activecnt++ == 0) { \
uv__handle_start((handle)); \
} \
assert((handle)->activecnt > 0); \
} while (0)
#define DECREASE_PENDING_REQ_COUNT(handle) \
do { \
assert(handle->reqs_pending > 0); \
handle->reqs_pending--; \
\
if (handle->flags & UV_HANDLE_CLOSING && \
handle->reqs_pending == 0) { \
uv_want_endgame(loop, (uv_handle_t*)handle); \
} \
} while (0)
#define uv__handle_closing(handle) \
do { \
assert(!((handle)->flags & UV_HANDLE_CLOSING)); \
\
if (!(((handle)->flags & UV_HANDLE_ACTIVE) && \
((handle)->flags & UV_HANDLE_REF))) \
uv__active_handle_add((uv_handle_t*) (handle)); \
\
(handle)->flags |= UV_HANDLE_CLOSING; \
(handle)->flags &= ~UV_HANDLE_ACTIVE; \
} while (0)
#define uv__handle_close(handle) \
do { \
QUEUE_REMOVE(&(handle)->handle_queue); \
uv__active_handle_rm((uv_handle_t*) (handle)); \
\
(handle)->flags |= UV_HANDLE_CLOSED; \
\
if ((handle)->close_cb) \
(handle)->close_cb((uv_handle_t*) (handle)); \
} while (0)
INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
handle->endgame_next = loop->endgame_handles;
loop->endgame_handles = handle;
}
}
INLINE static void uv_process_endgames(uv_loop_t* loop) {
uv_handle_t* handle;
while (loop->endgame_handles) {
handle = loop->endgame_handles;
loop->endgame_handles = handle->endgame_next;
handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
switch (handle->type) {
case UV_TCP:
uv_tcp_endgame(loop, (uv_tcp_t*) handle);
break;
case UV_NAMED_PIPE:
uv_pipe_endgame(loop, (uv_pipe_t*) handle);
break;
case UV_TTY:
uv_tty_endgame(loop, (uv_tty_t*) handle);
break;
case UV_UDP:
uv_udp_endgame(loop, (uv_udp_t*) handle);
break;
case UV_POLL:
uv_poll_endgame(loop, (uv_poll_t*) handle);
break;
case UV_TIMER:
uv__timer_close((uv_timer_t*) handle);
uv__handle_close(handle);
break;
case UV_PREPARE:
case UV_CHECK:
case UV_IDLE:
uv_loop_watcher_endgame(loop, handle);
break;
case UV_ASYNC:
uv_async_endgame(loop, (uv_async_t*) handle);
break;
case UV_SIGNAL:
uv_signal_endgame(loop, (uv_signal_t*) handle);
break;
case UV_PROCESS:
uv_process_endgame(loop, (uv_process_t*) handle);
break;
case UV_FS_EVENT:
uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
break;
case UV_FS_POLL:
uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle);
break;
default:
assert(0);
break;
}
}
}
INLINE static HANDLE uv__get_osfhandle(int fd)
{
/* _get_osfhandle() raises an assert in debug builds if the FD is invalid.
* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE for
* invalid FDs in release builds (or if you let the assert continue). So this
* wrapper function disables asserts when calling _get_osfhandle. */
HANDLE handle;
UV_BEGIN_DISABLE_CRT_ASSERT();
handle = (HANDLE) _get_osfhandle(fd);
UV_END_DISABLE_CRT_ASSERT();
return handle;
}
#endif /* UV_WIN_HANDLE_INL_H_ */

162
deps/libuv/src/win/handle.c vendored Normal file
View File

@ -0,0 +1,162 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <io.h>
#include <stdlib.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
uv_handle_type uv_guess_handle(uv_file file) {
HANDLE handle;
DWORD mode;
if (file < 0) {
return UV_UNKNOWN_HANDLE;
}
handle = uv__get_osfhandle(file);
switch (GetFileType(handle)) {
case FILE_TYPE_CHAR:
if (GetConsoleMode(handle, &mode)) {
return UV_TTY;
} else {
return UV_FILE;
}
case FILE_TYPE_PIPE:
return UV_NAMED_PIPE;
case FILE_TYPE_DISK:
return UV_FILE;
default:
return UV_UNKNOWN_HANDLE;
}
}
int uv_is_active(const uv_handle_t* handle) {
return (handle->flags & UV_HANDLE_ACTIVE) &&
!(handle->flags & UV_HANDLE_CLOSING);
}
void uv_close(uv_handle_t* handle, uv_close_cb cb) {
uv_loop_t* loop = handle->loop;
if (handle->flags & UV_HANDLE_CLOSING) {
assert(0);
return;
}
handle->close_cb = cb;
/* Handle-specific close actions */
switch (handle->type) {
case UV_TCP:
uv_tcp_close(loop, (uv_tcp_t*)handle);
return;
case UV_NAMED_PIPE:
uv_pipe_close(loop, (uv_pipe_t*) handle);
return;
case UV_TTY:
uv_tty_close((uv_tty_t*) handle);
return;
case UV_UDP:
uv_udp_close(loop, (uv_udp_t*) handle);
return;
case UV_POLL:
uv_poll_close(loop, (uv_poll_t*) handle);
return;
case UV_TIMER:
uv_timer_stop((uv_timer_t*)handle);
uv__handle_closing(handle);
uv_want_endgame(loop, handle);
return;
case UV_PREPARE:
uv_prepare_stop((uv_prepare_t*)handle);
uv__handle_closing(handle);
uv_want_endgame(loop, handle);
return;
case UV_CHECK:
uv_check_stop((uv_check_t*)handle);
uv__handle_closing(handle);
uv_want_endgame(loop, handle);
return;
case UV_IDLE:
uv_idle_stop((uv_idle_t*)handle);
uv__handle_closing(handle);
uv_want_endgame(loop, handle);
return;
case UV_ASYNC:
uv_async_close(loop, (uv_async_t*) handle);
return;
case UV_SIGNAL:
uv_signal_close(loop, (uv_signal_t*) handle);
return;
case UV_PROCESS:
uv_process_close(loop, (uv_process_t*) handle);
return;
case UV_FS_EVENT:
uv_fs_event_close(loop, (uv_fs_event_t*) handle);
return;
case UV_FS_POLL:
uv__fs_poll_close((uv_fs_poll_t*) handle);
uv__handle_closing(handle);
return;
default:
/* Not supported */
abort();
}
}
int uv_is_closing(const uv_handle_t* handle) {
return !!(handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED));
}
uv_os_fd_t uv_get_osfhandle(int fd) {
return uv__get_osfhandle(fd);
}
int uv_open_osfhandle(uv_os_fd_t os_fd) {
return _open_osfhandle((intptr_t) os_fd, 0);
}

344
deps/libuv/src/win/internal.h vendored Normal file
View File

@ -0,0 +1,344 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_WIN_INTERNAL_H_
#define UV_WIN_INTERNAL_H_
#include "uv.h"
#include "../uv-common.h"
#include "uv/tree.h"
#include "winapi.h"
#include "winsock.h"
#ifdef _MSC_VER
# define INLINE __inline
# define UV_THREAD_LOCAL __declspec( thread )
#else
# define INLINE inline
# define UV_THREAD_LOCAL __thread
#endif
#ifdef _DEBUG
extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
#define UV_BEGIN_DISABLE_CRT_ASSERT() \
{ \
int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
uv__crt_assert_enabled = FALSE;
#define UV_END_DISABLE_CRT_ASSERT() \
uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
}
#else
#define UV_BEGIN_DISABLE_CRT_ASSERT()
#define UV_END_DISABLE_CRT_ASSERT()
#endif
/*
* TCP
*/
typedef enum {
UV__IPC_SOCKET_XFER_NONE = 0,
UV__IPC_SOCKET_XFER_TCP_CONNECTION,
UV__IPC_SOCKET_XFER_TCP_SERVER
} uv__ipc_socket_xfer_type_t;
typedef struct {
WSAPROTOCOL_INFOW socket_info;
uint32_t delayed_error;
} uv__ipc_socket_xfer_info_t;
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
unsigned int nbufs);
void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_write_t* req);
void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_req_t* req);
void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_connect_t* req);
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
int uv__tcp_xfer_export(uv_tcp_t* handle,
int pid,
uv__ipc_socket_xfer_type_t* xfer_type,
uv__ipc_socket_xfer_info_t* xfer_info);
int uv__tcp_xfer_import(uv_tcp_t* tcp,
uv__ipc_socket_xfer_type_t xfer_type,
uv__ipc_socket_xfer_info_t* xfer_info);
/*
* UDP
*/
void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
uv_udp_send_t* req);
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
/*
* Pipes
*/
int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
char* name, size_t nameSize);
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
void uv__pipe_read_stop(uv_pipe_t* handle);
int uv__pipe_write(uv_loop_t* loop,
uv_write_t* req,
uv_pipe_t* handle,
const uv_buf_t bufs[],
size_t nbufs,
uv_stream_t* send_handle,
uv_write_cb cb);
void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_req_t* req);
void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_write_t* req);
void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_req_t* raw_req);
void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_connect_t* req);
void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_shutdown_t* req);
void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
/*
* TTY
*/
void uv_console_init(void);
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
int uv_tty_read_stop(uv_tty_t* handle);
int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
unsigned int nbufs);
void uv_tty_close(uv_tty_t* handle);
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* req);
void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
uv_write_t* req);
/*
* uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it
*/
void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* raw_req);
/*
* uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it
*/
void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
uv_connect_t* req);
void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
/*
* Poll watchers
*/
void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
uv_req_t* req);
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
/*
* Loop watchers
*/
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
void uv_prepare_invoke(uv_loop_t* loop);
void uv_check_invoke(uv_loop_t* loop);
void uv_idle_invoke(uv_loop_t* loop);
void uv__once_init(void);
/*
* Async watcher
*/
void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
uv_req_t* req);
/*
* Signal watcher
*/
void uv_signals_init(void);
int uv__signal_dispatch(int signum);
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
uv_req_t* req);
/*
* Spawn
*/
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
/*
* Error
*/
int uv_translate_sys_error(int sys_errno);
/*
* FS
*/
void uv_fs_init(void);
/*
* FS Event
*/
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
uv_fs_event_t* handle);
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
/*
* Stat poller.
*/
void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
/*
* Utilities.
*/
void uv__util_init(void);
uint64_t uv__hrtime(unsigned int scale);
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);
typedef int (WINAPI *uv__peersockfunc)(SOCKET, struct sockaddr*, int*);
int uv__getsockpeername(const uv_handle_t* handle,
uv__peersockfunc func,
struct sockaddr* name,
int* namelen,
int delayed_error);
int uv__random_rtlgenrandom(void* buf, size_t buflen);
/*
* Process stdio handles.
*/
int uv__stdio_create(uv_loop_t* loop,
const uv_process_options_t* options,
BYTE** buffer_ptr);
void uv__stdio_destroy(BYTE* buffer);
void uv__stdio_noinherit(BYTE* buffer);
int uv__stdio_verify(BYTE* buffer, WORD size);
WORD uv__stdio_size(BYTE* buffer);
HANDLE uv__stdio_handle(BYTE* buffer, int fd);
/*
* Winapi and ntapi utility functions
*/
void uv_winapi_init(void);
/*
* Winsock utility functions
*/
void uv_winsock_init(void);
int uv_ntstatus_to_winsock_error(NTSTATUS status);
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
int* addr_len, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
/* Whether there are any non-IFS LSPs stacked on TCP */
extern int uv_tcp_non_ifs_lsp_ipv4;
extern int uv_tcp_non_ifs_lsp_ipv6;
/* Ip address used to bind to any port at any interface */
extern struct sockaddr_in uv_addr_ip4_any_;
extern struct sockaddr_in6 uv_addr_ip6_any_;
/*
* Wake all loops with fake message
*/
void uv__wake_all_loops(void);
/*
* Init system wake-up detection
*/
void uv__init_detect_system_wakeup(void);
#endif /* UV_WIN_INTERNAL_H_ */

122
deps/libuv/src/win/loop-watcher.c vendored Normal file
View File

@ -0,0 +1,122 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_close(handle);
}
}
#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
\
return 0; \
} \
\
\
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
uv_loop_t* loop = handle->loop; \
uv_##name##_t* old_head; \
\
assert(handle->type == UV_##NAME); \
\
if (uv__is_active(handle)) \
return 0; \
\
if (cb == NULL) \
return UV_EINVAL; \
\
old_head = loop->name##_handles; \
\
handle->name##_next = old_head; \
handle->name##_prev = NULL; \
\
if (old_head) { \
old_head->name##_prev = handle; \
} \
\
loop->name##_handles = handle; \
\
handle->name##_cb = cb; \
uv__handle_start(handle); \
\
return 0; \
} \
\
\
int uv_##name##_stop(uv_##name##_t* handle) { \
uv_loop_t* loop = handle->loop; \
\
assert(handle->type == UV_##NAME); \
\
if (!uv__is_active(handle)) \
return 0; \
\
/* Update loop head if needed */ \
if (loop->name##_handles == handle) { \
loop->name##_handles = handle->name##_next; \
} \
\
/* Update the iterator-next pointer of needed */ \
if (loop->next_##name##_handle == handle) { \
loop->next_##name##_handle = handle->name##_next; \
} \
\
if (handle->name##_prev) { \
handle->name##_prev->name##_next = handle->name##_next; \
} \
if (handle->name##_next) { \
handle->name##_next->name##_prev = handle->name##_prev; \
} \
\
uv__handle_stop(handle); \
\
return 0; \
} \
\
\
void uv_##name##_invoke(uv_loop_t* loop) { \
uv_##name##_t* handle; \
\
(loop)->next_##name##_handle = (loop)->name##_handles; \
\
while ((loop)->next_##name##_handle != NULL) { \
handle = (loop)->next_##name##_handle; \
(loop)->next_##name##_handle = handle->name##_next; \
\
handle->name##_cb(handle); \
} \
}
UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
UV_LOOP_WATCHER_DEFINE(check, CHECK)
UV_LOOP_WATCHER_DEFINE(idle, IDLE)

2393
deps/libuv/src/win/pipe.c vendored Normal file

File diff suppressed because it is too large Load Diff

584
deps/libuv/src/win/poll.c vendored Normal file
View File

@ -0,0 +1,584 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <io.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
{0xe70f1aa0, 0xab8b, 0x11cf,
{0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
{0xf9eab0c0, 0x26d4, 0x11d0,
{0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
{0x9fc48064, 0x7298, 0x43e4,
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
};
typedef struct uv_single_fd_set_s {
unsigned int fd_count;
SOCKET fd_array[1];
} uv_single_fd_set_t;
static OVERLAPPED overlapped_dummy_;
static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
static AFD_POLL_INFO afd_poll_info_dummy_;
static void uv__init_overlapped_dummy(void) {
HANDLE event;
event = CreateEvent(NULL, TRUE, TRUE, NULL);
if (event == NULL)
uv_fatal_error(GetLastError(), "CreateEvent");
memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
}
static OVERLAPPED* uv__get_overlapped_dummy(void) {
uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
return &overlapped_dummy_;
}
static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
return &afd_poll_info_dummy_;
}
static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
uv_req_t* req;
AFD_POLL_INFO* afd_poll_info;
int result;
/* Find a yet unsubmitted req to submit. */
if (handle->submitted_events_1 == 0) {
req = &handle->poll_req_1;
afd_poll_info = &handle->afd_poll_info_1;
handle->submitted_events_1 = handle->events;
handle->mask_events_1 = 0;
handle->mask_events_2 = handle->events;
} else if (handle->submitted_events_2 == 0) {
req = &handle->poll_req_2;
afd_poll_info = &handle->afd_poll_info_2;
handle->submitted_events_2 = handle->events;
handle->mask_events_1 = handle->events;
handle->mask_events_2 = 0;
} else {
/* Just wait until there's an unsubmitted req. This will happen almost
* immediately as one of the 2 outstanding requests is about to return.
* When this happens, uv__fast_poll_process_poll_req will be called, and
* the pending events, if needed, will be processed in a subsequent
* request. */
return;
}
/* Setting Exclusive to TRUE makes the other poll request return if there is
* any. */
afd_poll_info->Exclusive = TRUE;
afd_poll_info->NumberOfHandles = 1;
afd_poll_info->Timeout.QuadPart = INT64_MAX;
afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info->Handles[0].Status = 0;
afd_poll_info->Handles[0].Events = 0;
if (handle->events & UV_READABLE) {
afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
} else {
if (handle->events & UV_DISCONNECT) {
afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT;
}
}
if (handle->events & UV_WRITABLE) {
afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
}
memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
result = uv_msafd_poll((SOCKET) handle->peer_socket,
afd_poll_info,
afd_poll_info,
&req->u.io.overlapped);
if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
/* Queue this req, reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, req);
}
}
static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
uv_req_t* req) {
unsigned char mask_events;
AFD_POLL_INFO* afd_poll_info;
if (req == &handle->poll_req_1) {
afd_poll_info = &handle->afd_poll_info_1;
handle->submitted_events_1 = 0;
mask_events = handle->mask_events_1;
} else if (req == &handle->poll_req_2) {
afd_poll_info = &handle->afd_poll_info_2;
handle->submitted_events_2 = 0;
mask_events = handle->mask_events_2;
} else {
assert(0);
return;
}
/* Report an error unless the select was just interrupted. */
if (!REQ_SUCCESS(req)) {
DWORD error = GET_REQ_SOCK_ERROR(req);
if (error != WSAEINTR && handle->events != 0) {
handle->events = 0; /* Stop the watcher */
handle->poll_cb(handle, uv_translate_sys_error(error), 0);
}
} else if (afd_poll_info->NumberOfHandles >= 1) {
unsigned char events = 0;
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
events |= UV_READABLE;
if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) {
events |= UV_DISCONNECT;
}
}
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
AFD_POLL_CONNECT_FAIL)) != 0) {
events |= UV_WRITABLE;
}
events &= handle->events & ~mask_events;
if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
/* Stop polling. */
handle->events = 0;
if (uv__is_active(handle))
uv__handle_stop(handle);
}
if (events != 0) {
handle->poll_cb(handle, 0, events);
}
}
if ((handle->events & ~(handle->submitted_events_1 |
handle->submitted_events_2)) != 0) {
uv__fast_poll_submit_poll_req(loop, handle);
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
WSAPROTOCOL_INFOW* protocol_info) {
SOCKET sock = 0;
sock = WSASocketW(protocol_info->iAddressFamily,
protocol_info->iSocketType,
protocol_info->iProtocol,
protocol_info,
0,
WSA_FLAG_OVERLAPPED);
if (sock == INVALID_SOCKET) {
return INVALID_SOCKET;
}
if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
goto error;
};
if (CreateIoCompletionPort((HANDLE) sock,
iocp,
(ULONG_PTR) sock,
0) == NULL) {
goto error;
}
return sock;
error:
closesocket(sock);
return INVALID_SOCKET;
}
static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
WSAPROTOCOL_INFOW* protocol_info) {
int index, i;
SOCKET peer_socket;
index = -1;
for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
if (memcmp((void*) &protocol_info->ProviderId,
(void*) &uv_msafd_provider_ids[i],
sizeof protocol_info->ProviderId) == 0) {
index = i;
}
}
/* Check if the protocol uses an msafd socket. */
if (index < 0) {
return INVALID_SOCKET;
}
/* If we didn't (try) to create a peer socket yet, try to make one. Don't try
* again if the peer socket creation failed earlier for the same protocol. */
peer_socket = loop->poll_peer_sockets[index];
if (peer_socket == 0) {
peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
loop->poll_peer_sockets[index] = peer_socket;
}
return peer_socket;
}
static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
uv_req_t* req = (uv_req_t*) arg;
uv_poll_t* handle = (uv_poll_t*) req->data;
unsigned char reported_events;
int r;
uv_single_fd_set_t rfds, wfds, efds;
struct timeval timeout;
assert(handle->type == UV_POLL);
assert(req->type == UV_POLL_REQ);
if (handle->events & UV_READABLE) {
rfds.fd_count = 1;
rfds.fd_array[0] = handle->socket;
} else {
rfds.fd_count = 0;
}
if (handle->events & UV_WRITABLE) {
wfds.fd_count = 1;
wfds.fd_array[0] = handle->socket;
efds.fd_count = 1;
efds.fd_array[0] = handle->socket;
} else {
wfds.fd_count = 0;
efds.fd_count = 0;
}
/* Make the select() time out after 3 minutes. If select() hangs because the
* user closed the socket, we will at least not hang indefinitely. */
timeout.tv_sec = 3 * 60;
timeout.tv_usec = 0;
r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
if (r == SOCKET_ERROR) {
/* Queue this req, reporting an error. */
SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
POST_COMPLETION_FOR_REQ(handle->loop, req);
return 0;
}
reported_events = 0;
if (r > 0) {
if (rfds.fd_count > 0) {
assert(rfds.fd_count == 1);
assert(rfds.fd_array[0] == handle->socket);
reported_events |= UV_READABLE;
}
if (wfds.fd_count > 0) {
assert(wfds.fd_count == 1);
assert(wfds.fd_array[0] == handle->socket);
reported_events |= UV_WRITABLE;
} else if (efds.fd_count > 0) {
assert(efds.fd_count == 1);
assert(efds.fd_array[0] == handle->socket);
reported_events |= UV_WRITABLE;
}
}
SET_REQ_SUCCESS(req);
req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
POST_COMPLETION_FOR_REQ(handle->loop, req);
return 0;
}
static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
uv_req_t* req;
/* Find a yet unsubmitted req to submit. */
if (handle->submitted_events_1 == 0) {
req = &handle->poll_req_1;
handle->submitted_events_1 = handle->events;
handle->mask_events_1 = 0;
handle->mask_events_2 = handle->events;
} else if (handle->submitted_events_2 == 0) {
req = &handle->poll_req_2;
handle->submitted_events_2 = handle->events;
handle->mask_events_1 = handle->events;
handle->mask_events_2 = 0;
} else {
assert(0);
return;
}
if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
(void*) req,
WT_EXECUTELONGFUNCTION)) {
/* Make this req pending, reporting an error. */
SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, req);
}
}
static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
uv_req_t* req) {
unsigned char mask_events;
int err;
if (req == &handle->poll_req_1) {
handle->submitted_events_1 = 0;
mask_events = handle->mask_events_1;
} else if (req == &handle->poll_req_2) {
handle->submitted_events_2 = 0;
mask_events = handle->mask_events_2;
} else {
assert(0);
return;
}
if (!REQ_SUCCESS(req)) {
/* Error. */
if (handle->events != 0) {
err = GET_REQ_ERROR(req);
handle->events = 0; /* Stop the watcher */
handle->poll_cb(handle, uv_translate_sys_error(err), 0);
}
} else {
/* Got some events. */
int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
if (events != 0) {
handle->poll_cb(handle, 0, events);
}
}
if ((handle->events & ~(handle->submitted_events_1 |
handle->submitted_events_2)) != 0) {
uv__slow_poll_submit_poll_req(loop, handle);
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
}
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
uv_os_sock_t socket) {
WSAPROTOCOL_INFOW protocol_info;
int len;
SOCKET peer_socket, base_socket;
DWORD bytes;
DWORD yes = 1;
/* Set the socket to nonblocking mode */
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
return uv_translate_sys_error(WSAGetLastError());
/* Try to obtain a base handle for the socket. This increases this chances that
* we find an AFD handle and are able to use the fast poll mechanism. This will
* always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE
* ioctl. */
#ifndef NDEBUG
base_socket = INVALID_SOCKET;
#endif
if (WSAIoctl(socket,
SIO_BASE_HANDLE,
NULL,
0,
&base_socket,
sizeof base_socket,
&bytes,
NULL,
NULL) == 0) {
assert(base_socket != 0 && base_socket != INVALID_SOCKET);
socket = base_socket;
}
uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
handle->socket = socket;
handle->events = 0;
/* Obtain protocol information about the socket. */
len = sizeof protocol_info;
if (getsockopt(socket,
SOL_SOCKET,
SO_PROTOCOL_INFOW,
(char*) &protocol_info,
&len) != 0) {
return uv_translate_sys_error(WSAGetLastError());
}
/* Get the peer socket that is needed to enable fast poll. If the returned
* value is NULL, the protocol is not implemented by MSAFD and we'll have to
* use slow mode. */
peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
if (peer_socket != INVALID_SOCKET) {
/* Initialize fast poll specific fields. */
handle->peer_socket = peer_socket;
} else {
/* Initialize slow poll specific fields. */
handle->flags |= UV_HANDLE_POLL_SLOW;
}
/* Initialize 2 poll reqs. */
handle->submitted_events_1 = 0;
UV_REQ_INIT(&handle->poll_req_1, UV_POLL_REQ);
handle->poll_req_1.data = handle;
handle->submitted_events_2 = 0;
UV_REQ_INIT(&handle->poll_req_2, UV_POLL_REQ);
handle->poll_req_2.data = handle;
return 0;
}
static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) {
int submitted_events;
assert(handle->type == UV_POLL);
assert(!(handle->flags & UV_HANDLE_CLOSING));
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
handle->events = events;
handle->poll_cb = cb;
if (handle->events == 0) {
uv__handle_stop(handle);
return 0;
}
uv__handle_start(handle);
submitted_events = handle->submitted_events_1 | handle->submitted_events_2;
if (handle->events & ~submitted_events) {
if (handle->flags & UV_HANDLE_POLL_SLOW) {
uv__slow_poll_submit_poll_req(handle->loop, handle);
} else {
uv__fast_poll_submit_poll_req(handle->loop, handle);
}
}
return 0;
}
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
return uv__poll_set(handle, events, cb);
}
int uv_poll_stop(uv_poll_t* handle) {
return uv__poll_set(handle, 0, handle->poll_cb);
}
void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
uv__fast_poll_process_poll_req(loop, handle, req);
} else {
uv__slow_poll_process_poll_req(loop, handle, req);
}
}
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
AFD_POLL_INFO afd_poll_info;
DWORD error;
int result;
handle->events = 0;
uv__handle_closing(handle);
if (handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
return 0;
}
if (handle->flags & UV_HANDLE_POLL_SLOW)
return 0;
/* Cancel outstanding poll requests by executing another, unique poll
* request that forces the outstanding ones to return. */
afd_poll_info.Exclusive = TRUE;
afd_poll_info.NumberOfHandles = 1;
afd_poll_info.Timeout.QuadPart = INT64_MAX;
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info.Handles[0].Status = 0;
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
result = uv_msafd_poll(handle->socket,
&afd_poll_info,
uv__get_afd_poll_info_dummy(),
uv__get_overlapped_dummy());
if (result == SOCKET_ERROR) {
error = WSAGetLastError();
if (error != WSA_IO_PENDING)
return uv_translate_sys_error(error);
}
return 0;
}
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED));
assert(handle->submitted_events_1 == 0);
assert(handle->submitted_events_2 == 0);
uv__handle_close(handle);
}

512
deps/libuv/src/win/process-stdio.c vendored Normal file
View File

@ -0,0 +1,512 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
/*
* The `child_stdio_buffer` buffer has the following layout:
* int number_of_fds
* unsigned char crt_flags[number_of_fds]
* HANDLE os_handle[number_of_fds]
*/
#define CHILD_STDIO_SIZE(count) \
(sizeof(int) + \
sizeof(unsigned char) * (count) + \
sizeof(uintptr_t) * (count))
#define CHILD_STDIO_COUNT(buffer) \
*((unsigned int*) (buffer))
#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
*((unsigned char*) (buffer) + sizeof(int) + fd)
#define CHILD_STDIO_HANDLE(buffer, fd) \
*((HANDLE*) ((unsigned char*) (buffer) + \
sizeof(int) + \
sizeof(unsigned char) * \
CHILD_STDIO_COUNT((buffer)) + \
sizeof(HANDLE) * (fd)))
/* CRT file descriptor mode flags */
#define FOPEN 0x01
#define FEOFLAG 0x02
#define FCRLF 0x04
#define FPIPE 0x08
#define FNOINHERIT 0x10
#define FAPPEND 0x20
#define FDEV 0x40
#define FTEXT 0x80
/*
* Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
* the parent process. Don't check for errors - the stdio handles may not be
* valid, or may be closed already. There is no guarantee that this function
* does a perfect job.
*/
void uv_disable_stdio_inheritance(void) {
HANDLE handle;
STARTUPINFOW si;
/* Make the windows stdio handles non-inheritable. */
handle = GetStdHandle(STD_INPUT_HANDLE);
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
handle = GetStdHandle(STD_OUTPUT_HANDLE);
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
handle = GetStdHandle(STD_ERROR_HANDLE);
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
/* Make inherited CRT FDs non-inheritable. */
GetStartupInfoW(&si);
if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
uv__stdio_noinherit(si.lpReserved2);
}
static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
char pipe_name[64];
SECURITY_ATTRIBUTES sa;
DWORD server_access = 0;
DWORD client_access = 0;
HANDLE child_pipe = INVALID_HANDLE_VALUE;
int err;
int overlap;
if (flags & UV_READABLE_PIPE) {
/* The server needs inbound access too, otherwise CreateNamedPipe() won't
* give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
* state of the write buffer when we're trying to shutdown the pipe. */
server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
}
if (flags & UV_WRITABLE_PIPE) {
server_access |= PIPE_ACCESS_INBOUND;
client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
}
/* Create server pipe handle. */
err = uv_stdio_pipe_server(loop,
server_pipe,
server_access,
pipe_name,
sizeof(pipe_name));
if (err)
goto error;
/* Create child pipe handle. */
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
child_pipe = CreateFileA(pipe_name,
client_access,
0,
&sa,
OPEN_EXISTING,
overlap ? FILE_FLAG_OVERLAPPED : 0,
NULL);
if (child_pipe == INVALID_HANDLE_VALUE) {
err = GetLastError();
goto error;
}
#ifndef NDEBUG
/* Validate that the pipe was opened in the right mode. */
{
DWORD mode;
BOOL r = GetNamedPipeHandleState(child_pipe,
&mode,
NULL,
NULL,
NULL,
NULL,
0);
assert(r == TRUE);
assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
}
#endif
/* Do a blocking ConnectNamedPipe. This should not block because we have both
* ends of the pipe created. */
if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
if (GetLastError() != ERROR_PIPE_CONNECTED) {
err = GetLastError();
goto error;
}
}
/* The server end is now readable and/or writable. */
if (flags & UV_READABLE_PIPE)
server_pipe->flags |= UV_HANDLE_WRITABLE;
if (flags & UV_WRITABLE_PIPE)
server_pipe->flags |= UV_HANDLE_READABLE;
*child_pipe_ptr = child_pipe;
return 0;
error:
if (server_pipe->handle != INVALID_HANDLE_VALUE) {
uv_pipe_cleanup(loop, server_pipe);
}
if (child_pipe != INVALID_HANDLE_VALUE) {
CloseHandle(child_pipe);
}
return err;
}
static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
HANDLE current_process;
/* _get_osfhandle will sometimes return -2 in case of an error. This seems to
* happen when fd <= 2 and the process' corresponding stdio handle is set to
* NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so
* this situation goes unnoticed until someone tries to use the duplicate.
* Therefore we filter out known-invalid handles here. */
if (handle == INVALID_HANDLE_VALUE ||
handle == NULL ||
handle == (HANDLE) -2) {
*dup = INVALID_HANDLE_VALUE;
return ERROR_INVALID_HANDLE;
}
current_process = GetCurrentProcess();
if (!DuplicateHandle(current_process,
handle,
current_process,
dup,
0,
TRUE,
DUPLICATE_SAME_ACCESS)) {
*dup = INVALID_HANDLE_VALUE;
return GetLastError();
}
return 0;
}
static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
HANDLE handle;
if (fd == -1) {
*dup = INVALID_HANDLE_VALUE;
return ERROR_INVALID_HANDLE;
}
handle = uv__get_osfhandle(fd);
return uv__duplicate_handle(loop, handle, dup);
}
int uv__create_nul_handle(HANDLE* handle_ptr,
DWORD access) {
HANDLE handle;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
handle = CreateFileW(L"NUL",
access,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
0,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
return GetLastError();
}
*handle_ptr = handle;
return 0;
}
int uv__stdio_create(uv_loop_t* loop,
const uv_process_options_t* options,
BYTE** buffer_ptr) {
BYTE* buffer;
int count, i;
int err;
count = options->stdio_count;
if (count < 0 || count > 255) {
/* Only support FDs 0-255 */
return ERROR_NOT_SUPPORTED;
} else if (count < 3) {
/* There should always be at least 3 stdio handles. */
count = 3;
}
/* Allocate the child stdio buffer */
buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
if (buffer == NULL) {
return ERROR_OUTOFMEMORY;
}
/* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean
* up on failure. */
CHILD_STDIO_COUNT(buffer) = count;
for (i = 0; i < count; i++) {
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
}
for (i = 0; i < count; i++) {
uv_stdio_container_t fdopt;
if (i < options->stdio_count) {
fdopt = options->stdio[i];
} else {
fdopt.flags = UV_IGNORE;
}
switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
UV_INHERIT_STREAM)) {
case UV_IGNORE:
/* Starting a process with no stdin/stout/stderr can confuse it. So no
* matter what the user specified, we make sure the first three FDs are
* always open in their typical modes, e. g. stdin be readable and
* stdout/err should be writable. For FDs > 2, don't do anything - all
* handles in the stdio buffer are initialized with.
* INVALID_HANDLE_VALUE, which should be okay. */
if (i <= 2) {
DWORD access = (i == 0) ? FILE_GENERIC_READ :
FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
access);
if (err)
goto error;
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
}
break;
case UV_CREATE_PIPE: {
/* Create a pair of two connected pipe ends; one end is turned into an
* uv_pipe_t for use by the parent. The other one is given to the
* child. */
uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
HANDLE child_pipe = INVALID_HANDLE_VALUE;
/* Create a new, connected pipe pair. stdio[i]. stream should point to
* an uninitialized, but not connected pipe handle. */
assert(fdopt.data.stream->type == UV_NAMED_PIPE);
assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
err = uv__create_stdio_pipe_pair(loop,
parent_pipe,
&child_pipe,
fdopt.flags);
if (err)
goto error;
CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
break;
}
case UV_INHERIT_FD: {
/* Inherit a raw FD. */
HANDLE child_handle;
/* Make an inheritable duplicate of the handle. */
err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
if (err) {
/* If fdopt. data. fd is not valid and fd <= 2, then ignore the
* error. */
if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
break;
}
goto error;
}
/* Figure out what the type is. */
switch (GetFileType(child_handle)) {
case FILE_TYPE_DISK:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
break;
case FILE_TYPE_PIPE:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
break;
case FILE_TYPE_CHAR:
case FILE_TYPE_REMOTE:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
break;
case FILE_TYPE_UNKNOWN:
if (GetLastError() != 0) {
err = GetLastError();
CloseHandle(child_handle);
goto error;
}
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
break;
default:
assert(0);
return -1;
}
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
break;
}
case UV_INHERIT_STREAM: {
/* Use an existing stream as the stdio handle for the child. */
HANDLE stream_handle, child_handle;
unsigned char crt_flags;
uv_stream_t* stream = fdopt.data.stream;
/* Leech the handle out of the stream. */
if (stream->type == UV_TTY) {
stream_handle = ((uv_tty_t*) stream)->handle;
crt_flags = FOPEN | FDEV;
} else if (stream->type == UV_NAMED_PIPE &&
stream->flags & UV_HANDLE_CONNECTION) {
stream_handle = ((uv_pipe_t*) stream)->handle;
crt_flags = FOPEN | FPIPE;
} else {
stream_handle = INVALID_HANDLE_VALUE;
crt_flags = 0;
}
if (stream_handle == NULL ||
stream_handle == INVALID_HANDLE_VALUE) {
/* The handle is already closed, or not yet created, or the stream
* type is not supported. */
err = ERROR_NOT_SUPPORTED;
goto error;
}
/* Make an inheritable copy of the handle. */
err = uv__duplicate_handle(loop, stream_handle, &child_handle);
if (err)
goto error;
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
break;
}
default:
assert(0);
return -1;
}
}
*buffer_ptr = buffer;
return 0;
error:
uv__stdio_destroy(buffer);
return err;
}
void uv__stdio_destroy(BYTE* buffer) {
int i, count;
count = CHILD_STDIO_COUNT(buffer);
for (i = 0; i < count; i++) {
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
}
}
uv__free(buffer);
}
void uv__stdio_noinherit(BYTE* buffer) {
int i, count;
count = CHILD_STDIO_COUNT(buffer);
for (i = 0; i < count; i++) {
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
if (handle != INVALID_HANDLE_VALUE) {
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
}
}
}
int uv__stdio_verify(BYTE* buffer, WORD size) {
unsigned int count;
/* Check the buffer pointer. */
if (buffer == NULL)
return 0;
/* Verify that the buffer is at least big enough to hold the count. */
if (size < CHILD_STDIO_SIZE(0))
return 0;
/* Verify if the count is within range. */
count = CHILD_STDIO_COUNT(buffer);
if (count > 256)
return 0;
/* Verify that the buffer size is big enough to hold info for N FDs. */
if (size < CHILD_STDIO_SIZE(count))
return 0;
return 1;
}
WORD uv__stdio_size(BYTE* buffer) {
return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
}
HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
return CHILD_STDIO_HANDLE(buffer, fd);
}

1281
deps/libuv/src/win/process.c vendored Normal file

File diff suppressed because it is too large Load Diff

221
deps/libuv/src/win/req-inl.h vendored Normal file
View File

@ -0,0 +1,221 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_WIN_REQ_INL_H_
#define UV_WIN_REQ_INL_H_
#include <assert.h>
#include "uv.h"
#include "internal.h"
#define SET_REQ_STATUS(req, status) \
(req)->u.io.overlapped.Internal = (ULONG_PTR) (status)
#define SET_REQ_ERROR(req, error) \
SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
/* Note: used open-coded in UV_REQ_INIT() because of a circular dependency
* between src/uv-common.h and src/win/internal.h.
*/
#define SET_REQ_SUCCESS(req) \
SET_REQ_STATUS((req), STATUS_SUCCESS)
#define GET_REQ_STATUS(req) \
((NTSTATUS) (req)->u.io.overlapped.Internal)
#define REQ_SUCCESS(req) \
(NT_SUCCESS(GET_REQ_STATUS((req))))
#define GET_REQ_ERROR(req) \
(pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
#define GET_REQ_SOCK_ERROR(req) \
(uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
#define REGISTER_HANDLE_REQ(loop, handle, req) \
do { \
INCREASE_ACTIVE_COUNT((loop), (handle)); \
uv__req_register((loop), (req)); \
} while (0)
#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
do { \
DECREASE_ACTIVE_COUNT((loop), (handle)); \
uv__req_unregister((loop), (req)); \
} while (0)
#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
#define UV_SUCCEEDED_WITH_IOCP(result) \
((result) || (GetLastError() == ERROR_IO_PENDING))
#define POST_COMPLETION_FOR_REQ(loop, req) \
if (!PostQueuedCompletionStatus((loop)->iocp, \
0, \
0, \
&((req)->u.io.overlapped))) { \
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
}
INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
}
INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
req->next_req = NULL;
if (loop->pending_reqs_tail) {
#ifdef _DEBUG
/* Ensure the request is not already in the queue, or the queue
* will get corrupted.
*/
uv_req_t* current = loop->pending_reqs_tail;
do {
assert(req != current);
current = current->next_req;
} while(current != loop->pending_reqs_tail);
#endif
req->next_req = loop->pending_reqs_tail->next_req;
loop->pending_reqs_tail->next_req = req;
loop->pending_reqs_tail = req;
} else {
req->next_req = req;
loop->pending_reqs_tail = req;
}
}
#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
do { \
switch (((uv_handle_t*) (req)->handle_at)->type) { \
case UV_TCP: \
uv_process_tcp_##method##_req(loop, \
(uv_tcp_t*) ((req)->handle_at), \
req); \
break; \
\
case UV_NAMED_PIPE: \
uv_process_pipe_##method##_req(loop, \
(uv_pipe_t*) ((req)->handle_at), \
req); \
break; \
\
case UV_TTY: \
uv_process_tty_##method##_req(loop, \
(uv_tty_t*) ((req)->handle_at), \
req); \
break; \
\
default: \
assert(0); \
} \
} while (0)
INLINE static int uv_process_reqs(uv_loop_t* loop) {
uv_req_t* req;
uv_req_t* first;
uv_req_t* next;
if (loop->pending_reqs_tail == NULL)
return 0;
first = loop->pending_reqs_tail->next_req;
next = first;
loop->pending_reqs_tail = NULL;
while (next != NULL) {
req = next;
next = req->next_req != first ? req->next_req : NULL;
switch (req->type) {
case UV_READ:
DELEGATE_STREAM_REQ(loop, req, read, data);
break;
case UV_WRITE:
DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
break;
case UV_ACCEPT:
DELEGATE_STREAM_REQ(loop, req, accept, data);
break;
case UV_CONNECT:
DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
break;
case UV_SHUTDOWN:
/* Tcp shutdown requests don't come here. */
assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
uv_process_pipe_shutdown_req(
loop,
(uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
(uv_shutdown_t*) req);
break;
case UV_UDP_RECV:
uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
break;
case UV_UDP_SEND:
uv_process_udp_send_req(loop,
((uv_udp_send_t*) req)->handle,
(uv_udp_send_t*) req);
break;
case UV_WAKEUP:
uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
break;
case UV_SIGNAL_REQ:
uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
break;
case UV_POLL_REQ:
uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
break;
case UV_PROCESS_EXIT:
uv_process_proc_exit(loop, (uv_process_t*) req->data);
break;
case UV_FS_EVENT_REQ:
uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
break;
default:
assert(0);
}
}
return 1;
}
#endif /* UV_WIN_REQ_INL_H_ */

282
deps/libuv/src/win/signal.c vendored Normal file
View File

@ -0,0 +1,282 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <signal.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
RB_HEAD(uv_signal_tree_s, uv_signal_s);
static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
static CRITICAL_SECTION uv__signal_lock;
static BOOL WINAPI uv__signal_control_handler(DWORD type);
int uv__signal_start(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum,
int oneshot);
void uv_signals_init(void) {
InitializeCriticalSection(&uv__signal_lock);
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
abort();
}
void uv__signal_cleanup(void) {
/* TODO(bnoordhuis) Undo effects of uv_signal_init()? */
}
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
/* Compare signums first so all watchers with the same signnum end up
* adjacent. */
if (w1->signum < w2->signum) return -1;
if (w1->signum > w2->signum) return 1;
/* Sort by loop pointer, so we can easily look up the first item after
* { .signum = x, .loop = NULL }. */
if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
return 0;
}
RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare)
/*
* Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
* Returns 1 if the signal was dispatched to any watcher, or 0 if there were
* no active signal watchers observing this signal.
*/
int uv__signal_dispatch(int signum) {
uv_signal_t lookup;
uv_signal_t* handle;
int dispatched;
dispatched = 0;
EnterCriticalSection(&uv__signal_lock);
lookup.signum = signum;
lookup.loop = NULL;
for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
handle != NULL && handle->signum == signum;
handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
unsigned long previous = InterlockedExchange(
(volatile LONG*) &handle->pending_signum, signum);
if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED)
continue;
if (!previous) {
POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
}
dispatched = 1;
if (handle->flags & UV_SIGNAL_ONE_SHOT)
handle->flags |= UV_SIGNAL_ONE_SHOT_DISPATCHED;
}
LeaveCriticalSection(&uv__signal_lock);
return dispatched;
}
static BOOL WINAPI uv__signal_control_handler(DWORD type) {
switch (type) {
case CTRL_C_EVENT:
return uv__signal_dispatch(SIGINT);
case CTRL_BREAK_EVENT:
return uv__signal_dispatch(SIGBREAK);
case CTRL_CLOSE_EVENT:
if (uv__signal_dispatch(SIGHUP)) {
/* Windows will terminate the process after the control handler
* returns. After that it will just terminate our process. Therefore
* block the signal handler so the main loop has some time to pick up
* the signal and do something for a few seconds. */
Sleep(INFINITE);
return TRUE;
}
return FALSE;
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
/* These signals are only sent to services. Services have their own
* notification mechanism, so there's no point in handling these. */
default:
/* We don't handle these. */
return FALSE;
}
}
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
handle->pending_signum = 0;
handle->signum = 0;
handle->signal_cb = NULL;
UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ);
handle->signal_req.data = handle;
return 0;
}
int uv_signal_stop(uv_signal_t* handle) {
uv_signal_t* removed_handle;
/* If the watcher wasn't started, this is a no-op. */
if (handle->signum == 0)
return 0;
EnterCriticalSection(&uv__signal_lock);
removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
assert(removed_handle == handle);
LeaveCriticalSection(&uv__signal_lock);
handle->signum = 0;
uv__handle_stop(handle);
return 0;
}
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
return uv__signal_start(handle, signal_cb, signum, 0);
}
int uv_signal_start_oneshot(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum) {
return uv__signal_start(handle, signal_cb, signum, 1);
}
int uv__signal_start(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum,
int oneshot) {
/* Test for invalid signal values. */
if (signum <= 0 || signum >= NSIG)
return UV_EINVAL;
/* Short circuit: if the signal watcher is already watching {signum} don't go
* through the process of deregistering and registering the handler.
* Additionally, this avoids pending signals getting lost in the (small) time
* frame that handle->signum == 0. */
if (signum == handle->signum) {
handle->signal_cb = signal_cb;
return 0;
}
/* If the signal handler was already active, stop it first. */
if (handle->signum != 0) {
int r = uv_signal_stop(handle);
/* uv_signal_stop is infallible. */
assert(r == 0);
}
EnterCriticalSection(&uv__signal_lock);
handle->signum = signum;
if (oneshot)
handle->flags |= UV_SIGNAL_ONE_SHOT;
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
LeaveCriticalSection(&uv__signal_lock);
handle->signal_cb = signal_cb;
uv__handle_start(handle);
return 0;
}
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
uv_req_t* req) {
long dispatched_signum;
assert(handle->type == UV_SIGNAL);
assert(req->type == UV_SIGNAL_REQ);
dispatched_signum = InterlockedExchange(
(volatile LONG*) &handle->pending_signum, 0);
assert(dispatched_signum != 0);
/* Check if the pending signal equals the signum that we are watching for.
* These can get out of sync when the handler is stopped and restarted while
* the signal_req is pending. */
if (dispatched_signum == handle->signum)
handle->signal_cb(handle, dispatched_signum);
if (handle->flags & UV_SIGNAL_ONE_SHOT)
uv_signal_stop(handle);
if (handle->flags & UV_HANDLE_CLOSING) {
/* When it is closing, it must be stopped at this point. */
assert(handle->signum == 0);
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
uv_signal_stop(handle);
uv__handle_closing(handle);
if (handle->pending_signum == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED));
assert(handle->signum == 0);
assert(handle->pending_signum == 0);
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_close(handle);
}

42
deps/libuv/src/win/snprintf.c vendored Normal file
View File

@ -0,0 +1,42 @@
/* Copyright the libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdio.h>
#include <stdarg.h>
/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
* on overflow...
*/
int snprintf(char* buf, size_t len, const char* fmt, ...) {
int n;
va_list ap;
va_start(ap, fmt);
n = _vscprintf(fmt, ap);
vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
va_end(ap);
return n;
}
#endif

54
deps/libuv/src/win/stream-inl.h vendored Normal file
View File

@ -0,0 +1,54 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_WIN_STREAM_INL_H_
#define UV_WIN_STREAM_INL_H_
#include <assert.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
INLINE static void uv_stream_init(uv_loop_t* loop,
uv_stream_t* handle,
uv_handle_type type) {
uv__handle_init(loop, (uv_handle_t*) handle, type);
handle->write_queue_size = 0;
handle->activecnt = 0;
handle->stream.conn.shutdown_req = NULL;
handle->stream.conn.write_reqs_pending = 0;
UV_REQ_INIT(&handle->read_req, UV_READ);
handle->read_req.event_handle = NULL;
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
handle->read_req.data = handle;
}
INLINE static void uv_connection_init(uv_stream_t* handle) {
handle->flags |= UV_HANDLE_CONNECTION;
}
#endif /* UV_WIN_STREAM_INL_H_ */

243
deps/libuv/src/win/stream.c vendored Normal file
View File

@ -0,0 +1,243 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
int err;
err = ERROR_INVALID_PARAMETER;
switch (stream->type) {
case UV_TCP:
err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
break;
case UV_NAMED_PIPE:
err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
break;
default:
assert(0);
}
return uv_translate_sys_error(err);
}
int uv_accept(uv_stream_t* server, uv_stream_t* client) {
int err;
err = ERROR_INVALID_PARAMETER;
switch (server->type) {
case UV_TCP:
err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
break;
case UV_NAMED_PIPE:
err = uv_pipe_accept((uv_pipe_t*)server, client);
break;
default:
assert(0);
}
return uv_translate_sys_error(err);
}
int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) {
int err;
if (handle->flags & UV_HANDLE_READING) {
return UV_EALREADY;
}
if (!(handle->flags & UV_HANDLE_READABLE)) {
return UV_ENOTCONN;
}
err = ERROR_INVALID_PARAMETER;
switch (handle->type) {
case UV_TCP:
err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
break;
case UV_NAMED_PIPE:
err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
break;
case UV_TTY:
err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
break;
default:
assert(0);
}
return uv_translate_sys_error(err);
}
int uv_read_stop(uv_stream_t* handle) {
int err;
if (!(handle->flags & UV_HANDLE_READING))
return 0;
err = 0;
if (handle->type == UV_TTY) {
err = uv_tty_read_stop((uv_tty_t*) handle);
} else if (handle->type == UV_NAMED_PIPE) {
uv__pipe_read_stop((uv_pipe_t*) handle);
} else {
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(handle->loop, handle);
}
return uv_translate_sys_error(err);
}
int uv_write(uv_write_t* req,
uv_stream_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_write_cb cb) {
uv_loop_t* loop = handle->loop;
int err;
if (!(handle->flags & UV_HANDLE_WRITABLE)) {
return UV_EPIPE;
}
err = ERROR_INVALID_PARAMETER;
switch (handle->type) {
case UV_TCP:
err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
break;
case UV_NAMED_PIPE:
err = uv__pipe_write(
loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb);
break;
case UV_TTY:
err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
break;
default:
assert(0);
}
return uv_translate_sys_error(err);
}
int uv_write2(uv_write_t* req,
uv_stream_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_stream_t* send_handle,
uv_write_cb cb) {
uv_loop_t* loop = handle->loop;
int err;
if (send_handle == NULL) {
return uv_write(req, handle, bufs, nbufs, cb);
}
if (handle->type != UV_NAMED_PIPE || !((uv_pipe_t*) handle)->ipc) {
return UV_EINVAL;
} else if (!(handle->flags & UV_HANDLE_WRITABLE)) {
return UV_EPIPE;
}
err = uv__pipe_write(
loop, req, (uv_pipe_t*) handle, bufs, nbufs, send_handle, cb);
return uv_translate_sys_error(err);
}
int uv_try_write(uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs) {
if (stream->flags & UV_HANDLE_CLOSING)
return UV_EBADF;
if (!(stream->flags & UV_HANDLE_WRITABLE))
return UV_EPIPE;
switch (stream->type) {
case UV_TCP:
return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs);
case UV_TTY:
return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs);
case UV_NAMED_PIPE:
return UV_EAGAIN;
default:
assert(0);
return UV_ENOSYS;
}
}
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
uv_loop_t* loop = handle->loop;
if (!(handle->flags & UV_HANDLE_WRITABLE) ||
handle->flags & UV_HANDLE_SHUTTING ||
uv__is_closing(handle)) {
return UV_ENOTCONN;
}
UV_REQ_INIT(req, UV_SHUTDOWN);
req->handle = handle;
req->cb = cb;
handle->flags &= ~UV_HANDLE_WRITABLE;
handle->flags |= UV_HANDLE_SHUTTING;
handle->stream.conn.shutdown_req = req;
handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);
uv_want_endgame(loop, (uv_handle_t*)handle);
return 0;
}
int uv_is_readable(const uv_stream_t* handle) {
return !!(handle->flags & UV_HANDLE_READABLE);
}
int uv_is_writable(const uv_stream_t* handle) {
return !!(handle->flags & UV_HANDLE_WRITABLE);
}
int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
if (handle->type != UV_NAMED_PIPE)
return UV_EINVAL;
if (blocking != 0)
handle->flags |= UV_HANDLE_BLOCKING_WRITES;
else
handle->flags &= ~UV_HANDLE_BLOCKING_WRITES;
return 0;
}

1573
deps/libuv/src/win/tcp.c vendored Normal file

File diff suppressed because it is too large Load Diff

520
deps/libuv/src/win/thread.c vendored Normal file
View File

@ -0,0 +1,520 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#if defined(__MINGW64_VERSION_MAJOR)
/* MemoryBarrier expands to __mm_mfence in some cases (x86+sse2), which may
* require this header in some versions of mingw64. */
#include <intrin.h>
#endif
#include "uv.h"
#include "internal.h"
static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
DWORD result;
HANDLE existing_event, created_event;
created_event = CreateEvent(NULL, 1, 0, NULL);
if (created_event == 0) {
/* Could fail in a low-memory situation? */
uv_fatal_error(GetLastError(), "CreateEvent");
}
existing_event = InterlockedCompareExchangePointer(&guard->event,
created_event,
NULL);
if (existing_event == NULL) {
/* We won the race */
callback();
result = SetEvent(created_event);
assert(result);
guard->ran = 1;
} else {
/* We lost the race. Destroy the event we created and wait for the existing
* one to become signaled. */
CloseHandle(created_event);
result = WaitForSingleObject(existing_event, INFINITE);
assert(result == WAIT_OBJECT_0);
}
}
void uv_once(uv_once_t* guard, void (*callback)(void)) {
/* Fast case - avoid WaitForSingleObject. */
if (guard->ran) {
return;
}
uv__once_inner(guard, callback);
}
/* Verify that uv_thread_t can be stored in a TLS slot. */
STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));
static uv_key_t uv__current_thread_key;
static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
static void uv__init_current_thread_key(void) {
if (uv_key_create(&uv__current_thread_key))
abort();
}
struct thread_ctx {
void (*entry)(void* arg);
void* arg;
uv_thread_t self;
};
static UINT __stdcall uv__thread_start(void* arg) {
struct thread_ctx *ctx_p;
struct thread_ctx ctx;
ctx_p = arg;
ctx = *ctx_p;
uv__free(ctx_p);
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
uv_key_set(&uv__current_thread_key, (void*) ctx.self);
ctx.entry(ctx.arg);
return 0;
}
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
uv_thread_options_t params;
params.flags = UV_THREAD_NO_FLAGS;
return uv_thread_create_ex(tid, &params, entry, arg);
}
int uv_thread_create_ex(uv_thread_t* tid,
const uv_thread_options_t* params,
void (*entry)(void *arg),
void *arg) {
struct thread_ctx* ctx;
int err;
HANDLE thread;
SYSTEM_INFO sysinfo;
size_t stack_size;
size_t pagesize;
stack_size =
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
if (stack_size != 0) {
GetNativeSystemInfo(&sysinfo);
pagesize = (size_t)sysinfo.dwPageSize;
/* Round up to the nearest page boundary. */
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
if ((unsigned)stack_size != stack_size)
return UV_EINVAL;
}
ctx = uv__malloc(sizeof(*ctx));
if (ctx == NULL)
return UV_ENOMEM;
ctx->entry = entry;
ctx->arg = arg;
/* Create the thread in suspended state so we have a chance to pass
* its own creation handle to it */
thread = (HANDLE) _beginthreadex(NULL,
(unsigned)stack_size,
uv__thread_start,
ctx,
CREATE_SUSPENDED,
NULL);
if (thread == NULL) {
err = errno;
uv__free(ctx);
} else {
err = 0;
*tid = thread;
ctx->self = thread;
ResumeThread(thread);
}
switch (err) {
case 0:
return 0;
case EACCES:
return UV_EACCES;
case EAGAIN:
return UV_EAGAIN;
case EINVAL:
return UV_EINVAL;
}
return UV_EIO;
}
uv_thread_t uv_thread_self(void) {
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
return (uv_thread_t) uv_key_get(&uv__current_thread_key);
}
int uv_thread_join(uv_thread_t *tid) {
if (WaitForSingleObject(*tid, INFINITE))
return uv_translate_sys_error(GetLastError());
else {
CloseHandle(*tid);
*tid = 0;
MemoryBarrier(); /* For feature parity with pthread_join(). */
return 0;
}
}
int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
return *t1 == *t2;
}
int uv_mutex_init(uv_mutex_t* mutex) {
InitializeCriticalSection(mutex);
return 0;
}
int uv_mutex_init_recursive(uv_mutex_t* mutex) {
return uv_mutex_init(mutex);
}
void uv_mutex_destroy(uv_mutex_t* mutex) {
DeleteCriticalSection(mutex);
}
void uv_mutex_lock(uv_mutex_t* mutex) {
EnterCriticalSection(mutex);
}
int uv_mutex_trylock(uv_mutex_t* mutex) {
if (TryEnterCriticalSection(mutex))
return 0;
else
return UV_EBUSY;
}
void uv_mutex_unlock(uv_mutex_t* mutex) {
LeaveCriticalSection(mutex);
}
int uv_rwlock_init(uv_rwlock_t* rwlock) {
/* Initialize the semaphore that acts as the write lock. */
HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
if (handle == NULL)
return uv_translate_sys_error(GetLastError());
rwlock->state_.write_semaphore_ = handle;
/* Initialize the critical section protecting the reader count. */
InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
/* Initialize the reader count. */
rwlock->state_.num_readers_ = 0;
return 0;
}
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
CloseHandle(rwlock->state_.write_semaphore_);
}
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
/* Acquire the lock that protects the reader count. */
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
/* Increase the reader count, and lock for write if this is the first
* reader.
*/
if (++rwlock->state_.num_readers_ == 1) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
/* Release the lock that protects the reader count. */
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
}
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
int err;
if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
return UV_EBUSY;
err = 0;
if (rwlock->state_.num_readers_ == 0) {
/* Currently there are no other readers, which means that the write lock
* needs to be acquired.
*/
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
if (r == WAIT_OBJECT_0)
rwlock->state_.num_readers_++;
else if (r == WAIT_TIMEOUT)
err = UV_EBUSY;
else if (r == WAIT_FAILED)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
} else {
/* The write lock has already been acquired because there are other
* active readers.
*/
rwlock->state_.num_readers_++;
}
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
return err;
}
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
if (--rwlock->state_.num_readers_ == 0) {
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
}
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
}
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
if (r == WAIT_OBJECT_0)
return 0;
else if (r == WAIT_TIMEOUT)
return UV_EBUSY;
else
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
}
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
*sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
if (*sem == NULL)
return uv_translate_sys_error(GetLastError());
else
return 0;
}
void uv_sem_destroy(uv_sem_t* sem) {
if (!CloseHandle(*sem))
abort();
}
void uv_sem_post(uv_sem_t* sem) {
if (!ReleaseSemaphore(*sem, 1, NULL))
abort();
}
void uv_sem_wait(uv_sem_t* sem) {
if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
abort();
}
int uv_sem_trywait(uv_sem_t* sem) {
DWORD r = WaitForSingleObject(*sem, 0);
if (r == WAIT_OBJECT_0)
return 0;
if (r == WAIT_TIMEOUT)
return UV_EAGAIN;
abort();
return -1; /* Satisfy the compiler. */
}
int uv_cond_init(uv_cond_t* cond) {
InitializeConditionVariable(&cond->cond_var);
return 0;
}
void uv_cond_destroy(uv_cond_t* cond) {
/* nothing to do */
(void) &cond;
}
void uv_cond_signal(uv_cond_t* cond) {
WakeConditionVariable(&cond->cond_var);
}
void uv_cond_broadcast(uv_cond_t* cond) {
WakeAllConditionVariable(&cond->cond_var);
}
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
abort();
}
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
return 0;
if (GetLastError() != ERROR_TIMEOUT)
abort();
return UV_ETIMEDOUT;
}
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
int err;
barrier->n = count;
barrier->count = 0;
err = uv_mutex_init(&barrier->mutex);
if (err)
return err;
err = uv_sem_init(&barrier->turnstile1, 0);
if (err)
goto error2;
err = uv_sem_init(&barrier->turnstile2, 1);
if (err)
goto error;
return 0;
error:
uv_sem_destroy(&barrier->turnstile1);
error2:
uv_mutex_destroy(&barrier->mutex);
return err;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
uv_sem_destroy(&barrier->turnstile2);
uv_sem_destroy(&barrier->turnstile1);
uv_mutex_destroy(&barrier->mutex);
}
int uv_barrier_wait(uv_barrier_t* barrier) {
int serial_thread;
uv_mutex_lock(&barrier->mutex);
if (++barrier->count == barrier->n) {
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile1);
}
uv_mutex_unlock(&barrier->mutex);
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile1);
uv_mutex_lock(&barrier->mutex);
serial_thread = (--barrier->count == 0);
if (serial_thread) {
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile2);
}
uv_mutex_unlock(&barrier->mutex);
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile2);
return serial_thread;
}
int uv_key_create(uv_key_t* key) {
key->tls_index = TlsAlloc();
if (key->tls_index == TLS_OUT_OF_INDEXES)
return UV_ENOMEM;
return 0;
}
void uv_key_delete(uv_key_t* key) {
if (TlsFree(key->tls_index) == FALSE)
abort();
key->tls_index = TLS_OUT_OF_INDEXES;
}
void* uv_key_get(uv_key_t* key) {
void* value;
value = TlsGetValue(key->tls_index);
if (value == NULL)
if (GetLastError() != ERROR_SUCCESS)
abort();
return value;
}
void uv_key_set(uv_key_t* key, void* value) {
if (TlsSetValue(key->tls_index, value) == FALSE)
abort();
}

2452
deps/libuv/src/win/tty.c vendored Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More