mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpinet] Update to libuv 1.44.1 (#4232)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,30 @@
|
||||
From 6a2f0c13071618ae8cbf84bff2e659b862e57ecd Mon Sep 17 00:00:00 2001
|
||||
From f6b4cd53205fabd10ed0e2b275f3882aa0017061 Mon Sep 17 00:00:00 2001
|
||||
From: PJ Reiniger <pj.reiniger@gmail.com>
|
||||
Date: Tue, 26 Apr 2022 15:09:43 -0400
|
||||
Subject: [PATCH 2/7] Fix warnings
|
||||
|
||||
---
|
||||
include/uv/win.h | 5 +++++
|
||||
src/idna.c | 2 +-
|
||||
src/inet.c | 4 ++++
|
||||
src/threadpool.c | 4 ++++
|
||||
src/unix/core.c | 12 ++++++++++--
|
||||
src/unix/internal.h | 4 ++--
|
||||
src/unix/thread.c | 6 ------
|
||||
src/uv-common.c | 8 ++++++++
|
||||
src/win/fs-event.c | 2 ++
|
||||
src/win/fs.c | 3 ++-
|
||||
src/win/pipe.c | 2 ++
|
||||
src/win/process.c | 2 ++
|
||||
src/win/tty.c | 2 ++
|
||||
13 files changed, 44 insertions(+), 12 deletions(-)
|
||||
include/uv/win.h | 5 +++
|
||||
src/idna.c | 2 +-
|
||||
src/inet.c | 4 ++
|
||||
src/threadpool.c | 4 ++
|
||||
src/unix/core.c | 12 ++++-
|
||||
src/unix/darwin.c | 106 +++++++++++++++++++++++---------------------
|
||||
src/unix/internal.h | 4 +-
|
||||
src/unix/thread.c | 6 ---
|
||||
src/uv-common.c | 8 ++++
|
||||
src/win/fs-event.c | 2 +
|
||||
src/win/fs.c | 2 +
|
||||
src/win/pipe.c | 2 +
|
||||
src/win/process.c | 2 +
|
||||
src/win/tty.c | 2 +
|
||||
14 files changed, 99 insertions(+), 62 deletions(-)
|
||||
|
||||
diff --git a/include/uv/win.h b/include/uv/win.h
|
||||
index acbd958b..354e0989 100644
|
||||
index 62be4b04..fe36a532 100644
|
||||
--- a/include/uv/win.h
|
||||
+++ b/include/uv/win.h
|
||||
@@ -194,11 +194,16 @@ typedef int (WSAAPI* LPFN_WSARECVFROM)
|
||||
@@ -201,11 +201,16 @@ typedef int (WSAAPI* LPFN_WSARECVFROM)
|
||||
LPWSAOVERLAPPED overlapped,
|
||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
|
||||
|
||||
@@ -41,10 +42,10 @@ index acbd958b..354e0989 100644
|
||||
typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE;
|
||||
#endif
|
||||
diff --git a/src/idna.c b/src/idna.c
|
||||
index 13ffac6b..6b2406ca 100644
|
||||
index 93d982ca..36a39a08 100644
|
||||
--- a/src/idna.c
|
||||
+++ b/src/idna.c
|
||||
@@ -103,7 +103,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
@@ -106,7 +106,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
char** d, char* de) {
|
||||
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
const char* ss;
|
||||
@@ -54,7 +55,7 @@ index 13ffac6b..6b2406ca 100644
|
||||
unsigned k;
|
||||
unsigned n;
|
||||
diff --git a/src/inet.c b/src/inet.c
|
||||
index 7e208b53..167ec118 100644
|
||||
index ca8b6ac8..1b190255 100644
|
||||
--- a/src/inet.c
|
||||
+++ b/src/inet.c
|
||||
@@ -27,6 +27,10 @@
|
||||
@@ -69,7 +70,7 @@ index 7e208b53..167ec118 100644
|
||||
#define UV__INET6_ADDRSTRLEN 46
|
||||
|
||||
diff --git a/src/threadpool.c b/src/threadpool.c
|
||||
index 9cb863e7..515bf407 100644
|
||||
index 1241ace1..718972c3 100644
|
||||
--- a/src/threadpool.c
|
||||
+++ b/src/threadpool.c
|
||||
@@ -27,6 +27,10 @@
|
||||
@@ -84,11 +85,11 @@ index 9cb863e7..515bf407 100644
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
diff --git a/src/unix/core.c b/src/unix/core.c
|
||||
index ef98b6ce..adb278bc 100644
|
||||
index c59e5352..be2ad1fc 100644
|
||||
--- a/src/unix/core.c
|
||||
+++ b/src/unix/core.c
|
||||
@@ -513,6 +513,16 @@ skip:
|
||||
}
|
||||
@@ -524,6 +524,16 @@ int uv__accept(int sockfd) {
|
||||
return peerfd;
|
||||
}
|
||||
|
||||
+#if defined(__APPLE__)
|
||||
@@ -104,10 +105,10 @@ index ef98b6ce..adb278bc 100644
|
||||
|
||||
/* close() on macos has the "interesting" quirk that it fails with EINTR
|
||||
* without closing the file descriptor when a thread is in the cancel state.
|
||||
@@ -527,10 +537,8 @@ int uv__close_nocancel(int fd) {
|
||||
@@ -538,10 +548,8 @@ int uv__close_nocancel(int fd) {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
|
||||
#if defined(__LP64__)
|
||||
#if defined(__LP64__) || TARGET_OS_IPHONE
|
||||
- extern int close$NOCANCEL(int);
|
||||
return close$NOCANCEL(fd);
|
||||
#else
|
||||
@@ -115,11 +116,135 @@ index ef98b6ce..adb278bc 100644
|
||||
return close$NOCANCEL$UNIX2003(fd);
|
||||
#endif
|
||||
#pragma GCC diagnostic pop
|
||||
diff --git a/src/unix/darwin.c b/src/unix/darwin.c
|
||||
index 5fbf7342..eeb35720 100644
|
||||
--- a/src/unix/darwin.c
|
||||
+++ b/src/unix/darwin.c
|
||||
@@ -253,64 +253,68 @@ static int uv__get_cpu_speed(uint64_t* speed) {
|
||||
|
||||
#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) {
|
||||
- const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref);
|
||||
- CFIndex len = pCFDataGetLength(freq_ref);
|
||||
- if (len == 8)
|
||||
- memcpy(speed, freq_ref_ptr, 8);
|
||||
- else if (len == 4) {
|
||||
- uint32_t v;
|
||||
- memcpy(&v, freq_ref_ptr, 4);
|
||||
- *speed = v;
|
||||
- } else {
|
||||
- *speed = 0;
|
||||
- }
|
||||
+ // Braces ensure goto doesn't jump into device_type_str's and
|
||||
+ // clock_frequency_str's lifetimes after their initialization
|
||||
+ {
|
||||
+ 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);
|
||||
|
||||
- pCFRelease(freq_ref);
|
||||
- pCFRelease(data);
|
||||
- break;
|
||||
+ 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) {
|
||||
+ const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref);
|
||||
+ CFIndex len = pCFDataGetLength(freq_ref);
|
||||
+ if (len == 8)
|
||||
+ memcpy(speed, freq_ref_ptr, 8);
|
||||
+ else if (len == 4) {
|
||||
+ uint32_t v;
|
||||
+ memcpy(&v, freq_ref_ptr, 4);
|
||||
+ *speed = v;
|
||||
+ } else {
|
||||
+ *speed = 0;
|
||||
+ }
|
||||
+
|
||||
+ pCFRelease(freq_ref);
|
||||
+ pCFRelease(data);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
+ pCFRelease(data);
|
||||
}
|
||||
- pCFRelease(data);
|
||||
- }
|
||||
|
||||
- service = pIOIteratorNext(it);
|
||||
- }
|
||||
+ service = pIOIteratorNext(it);
|
||||
+ }
|
||||
|
||||
- pIOObjectRelease(it);
|
||||
+ pIOObjectRelease(it);
|
||||
|
||||
- err = 0;
|
||||
+ err = 0;
|
||||
|
||||
- if (device_type_str != NULL)
|
||||
- pCFRelease(device_type_str);
|
||||
- if (clock_frequency_str != NULL)
|
||||
- pCFRelease(clock_frequency_str);
|
||||
+ if (device_type_str != NULL)
|
||||
+ pCFRelease(device_type_str);
|
||||
+ if (clock_frequency_str != NULL)
|
||||
+ pCFRelease(clock_frequency_str);
|
||||
+ }
|
||||
|
||||
out:
|
||||
if (core_foundation_handle != NULL)
|
||||
diff --git a/src/unix/internal.h b/src/unix/internal.h
|
||||
index 26061647..2db30350 100644
|
||||
index f418572d..5a867db7 100644
|
||||
--- a/src/unix/internal.h
|
||||
+++ b/src/unix/internal.h
|
||||
@@ -301,8 +301,8 @@ UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
|
||||
@@ -313,8 +313,8 @@ UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
|
||||
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
|
||||
}
|
||||
|
||||
@@ -131,12 +256,12 @@ index 26061647..2db30350 100644
|
||||
s = strrchr(path, '/');
|
||||
if (s == NULL)
|
||||
diff --git a/src/unix/thread.c b/src/unix/thread.c
|
||||
index c702d418..c753be9b 100644
|
||||
index 759cd0c2..64726bd6 100644
|
||||
--- a/src/unix/thread.c
|
||||
+++ b/src/unix/thread.c
|
||||
@@ -222,12 +222,6 @@ int uv_thread_create_ex(uv_thread_t* tid,
|
||||
size_t pagesize;
|
||||
@@ -244,12 +244,6 @@ int uv_thread_create_ex(uv_thread_t* tid,
|
||||
size_t stack_size;
|
||||
size_t min_stack_size;
|
||||
|
||||
- /* Used to squelch a -Wcast-function-type warning. */
|
||||
- union {
|
||||
@@ -148,10 +273,10 @@ index c702d418..c753be9b 100644
|
||||
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
|
||||
|
||||
diff --git a/src/uv-common.c b/src/uv-common.c
|
||||
index 47473346..b61a703d 100644
|
||||
index 73d19caf..c287246f 100644
|
||||
--- a/src/uv-common.c
|
||||
+++ b/src/uv-common.c
|
||||
@@ -698,6 +698,10 @@ void uv__fs_readdir_cleanup(uv_fs_t* req) {
|
||||
@@ -756,6 +756,10 @@ void uv__fs_readdir_cleanup(uv_fs_t* req) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +287,7 @@ index 47473346..b61a703d 100644
|
||||
|
||||
int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
|
||||
va_list ap;
|
||||
@@ -711,6 +715,10 @@ int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
|
||||
@@ -769,6 +773,10 @@ int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -174,7 +299,7 @@ index 47473346..b61a703d 100644
|
||||
static uv_loop_t default_loop_struct;
|
||||
static uv_loop_t* default_loop_ptr;
|
||||
diff --git a/src/win/fs-event.c b/src/win/fs-event.c
|
||||
index 78741bfe..b9ec0256 100644
|
||||
index 15046731..3244a4e4 100644
|
||||
--- a/src/win/fs-event.c
|
||||
+++ b/src/win/fs-event.c
|
||||
@@ -19,6 +19,8 @@
|
||||
@@ -187,7 +312,7 @@ index 78741bfe..b9ec0256 100644
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
diff --git a/src/win/fs.c b/src/win/fs.c
|
||||
index dc0b8984..5434698b 100644
|
||||
index 8374012f..f71b3c04 100644
|
||||
--- a/src/win/fs.c
|
||||
+++ b/src/win/fs.c
|
||||
@@ -19,6 +19,8 @@
|
||||
@@ -199,16 +324,8 @@ index dc0b8984..5434698b 100644
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <direct.h>
|
||||
@@ -1563,7 +1565,6 @@ static void fs__ftruncate(uv_fs_t* req) {
|
||||
static void fs__copyfile(uv_fs_t* req) {
|
||||
int flags;
|
||||
int overwrite;
|
||||
- DWORD error;
|
||||
uv_stat_t statbuf;
|
||||
uv_stat_t new_statbuf;
|
||||
|
||||
diff --git a/src/win/pipe.c b/src/win/pipe.c
|
||||
index 138f9ed6..0c03a065 100644
|
||||
index 9fb73b4e..ff4e8d25 100644
|
||||
--- a/src/win/pipe.c
|
||||
+++ b/src/win/pipe.c
|
||||
@@ -19,6 +19,8 @@
|
||||
@@ -221,7 +338,7 @@ index 138f9ed6..0c03a065 100644
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
diff --git a/src/win/process.c b/src/win/process.c
|
||||
index f3c9a43e..15f3b65e 100644
|
||||
index e857db3e..a49016f6 100644
|
||||
--- a/src/win/process.c
|
||||
+++ b/src/win/process.c
|
||||
@@ -19,6 +19,8 @@
|
||||
@@ -234,7 +351,7 @@ index f3c9a43e..15f3b65e 100644
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
diff --git a/src/win/tty.c b/src/win/tty.c
|
||||
index a5d58bf7..deec66fe 100644
|
||||
index 98c58883..f6131d45 100644
|
||||
--- a/src/win/tty.c
|
||||
+++ b/src/win/tty.c
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
From b2ce6f41afa612eb31a8c8ac3e5f23783fb81d5f Mon Sep 17 00:00:00 2001
|
||||
From 20120ec8cb9310e243a71fe5bf9bee37eac7614b Mon Sep 17 00:00:00 2001
|
||||
From: PJ Reiniger <pj.reiniger@gmail.com>
|
||||
Date: Tue, 26 Apr 2022 15:19:14 -0400
|
||||
Subject: [PATCH 3/7] Preprocessor cleanup
|
||||
|
||||
---
|
||||
include/uv.h | 18 +-----------------
|
||||
include/uv/unix.h | 6 ------
|
||||
include/uv/unix.h | 8 --------
|
||||
include/uv/win.h | 6 +-----
|
||||
src/unix/internal.h | 4 ++++
|
||||
src/unix/poll.c | 5 +++--
|
||||
src/unix/internal.h | 2 ++
|
||||
src/win/fs.c | 1 +
|
||||
src/win/tty.c | 2 ++
|
||||
src/win/util.c | 6 ++++++
|
||||
src/win/util.c | 8 ++++++++
|
||||
src/win/winsock.c | 1 +
|
||||
9 files changed, 19 insertions(+), 30 deletions(-)
|
||||
8 files changed, 16 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/include/uv.h b/include/uv.h
|
||||
index f97801ce..ccf62c8f 100644
|
||||
index ee1c94cc..dbaeb1e9 100644
|
||||
--- a/include/uv.h
|
||||
+++ b/include/uv.h
|
||||
@@ -23,9 +23,6 @@
|
||||
@@ -27,9 +26,9 @@ index f97801ce..ccf62c8f 100644
|
||||
-extern "C" {
|
||||
-#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Windows - set up dll import/export decorators. */
|
||||
@@ -50,11 +47,7 @@ extern "C" {
|
||||
#if defined(BUILDING_UV_SHARED) && defined(USING_UV_SHARED)
|
||||
#error "Define either BUILDING_UV_SHARED or USING_UV_SHARED, not both."
|
||||
@@ -56,11 +53,7 @@ extern "C" {
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -42,9 +41,9 @@ index f97801ce..ccf62c8f 100644
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include "uv/win.h"
|
||||
@@ -692,16 +685,10 @@ UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode);
|
||||
UV_EXTERN int uv_tty_reset_mode(void);
|
||||
UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
|
||||
@@ -767,16 +760,10 @@ UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
|
||||
UV_EXTERN void uv_tty_set_vterm_state(uv_tty_vtermstate_t state);
|
||||
UV_EXTERN int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state);
|
||||
|
||||
-#ifdef __cplusplus
|
||||
-extern "C++" {
|
||||
@@ -59,7 +58,7 @@ index f97801ce..ccf62c8f 100644
|
||||
UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
|
||||
|
||||
/*
|
||||
@@ -1693,7 +1680,4 @@ UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
|
||||
@@ -1844,7 +1831,4 @@ UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
|
||||
#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS
|
||||
#undef UV__ERR
|
||||
|
||||
@@ -68,15 +67,17 @@ index f97801ce..ccf62c8f 100644
|
||||
-#endif
|
||||
#endif /* UV_H */
|
||||
diff --git a/include/uv/unix.h b/include/uv/unix.h
|
||||
index a647593a..504bab7c 100644
|
||||
index 420be86c..256fef37 100644
|
||||
--- a/include/uv/unix.h
|
||||
+++ b/include/uv/unix.h
|
||||
@@ -47,12 +47,6 @@
|
||||
@@ -47,14 +47,6 @@
|
||||
|
||||
#if defined(__linux__)
|
||||
# include "uv/linux.h"
|
||||
-#elif defined (__MVS__)
|
||||
-# include "uv/os390.h"
|
||||
-#elif defined(__PASE__) /* __PASE__ and _AIX are both defined on IBM i */
|
||||
-# include "uv/posix.h" /* IBM i needs uv/posix.h, not uv/aix.h */
|
||||
-#elif defined(_AIX)
|
||||
-# include "uv/aix.h"
|
||||
-#elif defined(__sun)
|
||||
@@ -85,10 +86,10 @@ index a647593a..504bab7c 100644
|
||||
# include "uv/darwin.h"
|
||||
#elif defined(__DragonFly__) || \
|
||||
diff --git a/include/uv/win.h b/include/uv/win.h
|
||||
index 354e0989..ca5242f7 100644
|
||||
index fe36a532..7b013173 100644
|
||||
--- a/include/uv/win.h
|
||||
+++ b/include/uv/win.h
|
||||
@@ -53,11 +53,7 @@ typedef struct pollfd {
|
||||
@@ -60,11 +60,7 @@ typedef struct pollfd {
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -102,22 +103,10 @@ index 354e0989..ca5242f7 100644
|
||||
#include "uv/tree.h"
|
||||
#include "uv/threadpool.h"
|
||||
diff --git a/src/unix/internal.h b/src/unix/internal.h
|
||||
index 2db30350..13ca2e63 100644
|
||||
index 5a867db7..7e1d408f 100644
|
||||
--- a/src/unix/internal.h
|
||||
+++ b/src/unix/internal.h
|
||||
@@ -168,9 +168,11 @@ struct uv__stream_queued_fds_s {
|
||||
defined(__NetBSD__)
|
||||
#define uv__cloexec uv__cloexec_ioctl
|
||||
#define uv__nonblock uv__nonblock_ioctl
|
||||
+#define UV__NONBLOCK_IS_IOCTL
|
||||
#else
|
||||
#define uv__cloexec uv__cloexec_fcntl
|
||||
#define uv__nonblock uv__nonblock_fcntl
|
||||
+#define UV__NONBLOCK_IS_FCNTL
|
||||
#endif
|
||||
|
||||
/* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute
|
||||
@@ -183,6 +185,8 @@ struct uv__stream_queued_fds_s {
|
||||
@@ -192,6 +192,8 @@ struct uv__stream_queued_fds_s {
|
||||
#if defined(__linux__) && O_NDELAY != O_NONBLOCK
|
||||
#undef uv__nonblock
|
||||
#define uv__nonblock uv__nonblock_fcntl
|
||||
@@ -126,37 +115,20 @@ index 2db30350..13ca2e63 100644
|
||||
#endif
|
||||
|
||||
/* core */
|
||||
diff --git a/src/unix/poll.c b/src/unix/poll.c
|
||||
index 3d5022b2..d578611e 100644
|
||||
--- a/src/unix/poll.c
|
||||
+++ b/src/unix/poll.c
|
||||
@@ -79,9 +79,10 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
||||
* Workaround for e.g. kqueue fds not supporting ioctls.
|
||||
*/
|
||||
err = uv__nonblock(fd, 1);
|
||||
+#ifdef UV__NONBLOCK_IS_IOCTL
|
||||
if (err == UV_ENOTTY)
|
||||
- if (uv__nonblock == uv__nonblock_ioctl)
|
||||
- err = uv__nonblock_fcntl(fd, 1);
|
||||
+ err = uv__nonblock_fcntl(fd, 1);
|
||||
+#endif
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
diff --git a/src/win/fs.c b/src/win/fs.c
|
||||
index 5434698b..6b9e37b0 100644
|
||||
index f71b3c04..71c9b169 100644
|
||||
--- a/src/win/fs.c
|
||||
+++ b/src/win/fs.c
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#include <wincrypt.h>
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "handle-inl.h"
|
||||
#include "fs-fd-hash-inl.h"
|
||||
|
||||
+#pragma comment(lib, "Advapi32.lib")
|
||||
|
||||
#define UV_FS_FREE_PATHS 0x0002
|
||||
#define UV_FS_FREE_PTR 0x0008
|
||||
diff --git a/src/win/tty.c b/src/win/tty.c
|
||||
index deec66fe..e4d7ac96 100644
|
||||
index f6131d45..54c6c290 100644
|
||||
--- a/src/win/tty.c
|
||||
+++ b/src/win/tty.c
|
||||
@@ -42,6 +42,8 @@
|
||||
@@ -169,10 +141,18 @@ index deec66fe..e4d7ac96 100644
|
||||
# define InterlockedOr _InterlockedOr
|
||||
#endif
|
||||
diff --git a/src/win/util.c b/src/win/util.c
|
||||
index d1cd19ba..b5afb1d8 100644
|
||||
index c655f532..7a5dd2ef 100644
|
||||
--- a/src/win/util.c
|
||||
+++ b/src/win/util.c
|
||||
@@ -67,6 +67,12 @@
|
||||
@@ -63,12 +63,20 @@
|
||||
|
||||
|
||||
/* A RtlGenRandom() by any other name... */
|
||||
+extern "C" {
|
||||
extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
|
||||
+}
|
||||
|
||||
/* Cached copy of the process title, plus a mutex guarding it. */
|
||||
static char *process_title;
|
||||
static CRITICAL_SECTION process_title_lock;
|
||||
|
||||
@@ -182,11 +162,11 @@ index d1cd19ba..b5afb1d8 100644
|
||||
+#pragma comment(lib, "Userenv.lib")
|
||||
+#pragma comment(lib, "kernel32.lib")
|
||||
+
|
||||
/* Interval (in seconds) of the high-resolution clock. */
|
||||
static double hrtime_interval_ = 0;
|
||||
/* Frequency of the high-resolution clock. */
|
||||
static uint64_t hrtime_frequency_ = 0;
|
||||
|
||||
diff --git a/src/win/winsock.c b/src/win/winsock.c
|
||||
index 5820ba9c..918acaf5 100644
|
||||
index a68b0953..7843e9f1 100644
|
||||
--- a/src/win/winsock.c
|
||||
+++ b/src/win/winsock.c
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From ea00b73593e7146c01df4320e3e2e345665fd1c3 Mon Sep 17 00:00:00 2001
|
||||
From 644521f5d44152e0196cb630864d37ba79c8a39e Mon Sep 17 00:00:00 2001
|
||||
From: PJ Reiniger <pj.reiniger@gmail.com>
|
||||
Date: Tue, 26 Apr 2022 15:24:47 -0400
|
||||
Subject: [PATCH 4/7] Cleanup problematic language
|
||||
@@ -8,10 +8,10 @@ Subject: [PATCH 4/7] Cleanup problematic language
|
||||
1 file changed, 11 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/unix/tty.c b/src/unix/tty.c
|
||||
index 74d3d75d..5f681406 100644
|
||||
index 9442cf16..89766884 100644
|
||||
--- a/src/unix/tty.c
|
||||
+++ b/src/unix/tty.c
|
||||
@@ -38,7 +38,7 @@ static int orig_termios_fd = -1;
|
||||
@@ -66,7 +66,7 @@ static int orig_termios_fd = -1;
|
||||
static struct termios orig_termios;
|
||||
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
|
||||
|
||||
@@ -20,7 +20,7 @@ index 74d3d75d..5f681406 100644
|
||||
int result;
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
int dummy;
|
||||
@@ -50,15 +50,16 @@ static int uv__tty_is_slave(const int fd) {
|
||||
@@ -78,15 +78,16 @@ static int uv__tty_is_slave(const int fd) {
|
||||
result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
|
||||
#elif defined(__NetBSD__)
|
||||
/*
|
||||
@@ -41,7 +41,7 @@ index 74d3d75d..5f681406 100644
|
||||
*/
|
||||
|
||||
struct stat sb;
|
||||
@@ -133,12 +134,12 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
|
||||
@@ -161,12 +162,12 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
|
||||
* other processes.
|
||||
*/
|
||||
if (type == UV_TTY) {
|
||||
@@ -56,7 +56,7 @@ index 74d3d75d..5f681406 100644
|
||||
*/
|
||||
- if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
|
||||
+ if (uv__tty_is_peripheral(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
|
||||
r = uv__open_cloexec(path, mode);
|
||||
r = uv__open_cloexec(path, mode | O_NOCTTY);
|
||||
else
|
||||
r = -1;
|
||||
--
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From a033a549b944b5ea9d9b2d8c7e73bbf8165232ec Mon Sep 17 00:00:00 2001
|
||||
From 6ad2de945c69a58fbe092f549d5a6c7c02952cef Mon Sep 17 00:00:00 2001
|
||||
From: PJ Reiniger <pj.reiniger@gmail.com>
|
||||
Date: Tue, 26 Apr 2022 15:26:03 -0400
|
||||
Subject: [PATCH 5/7] Use roborio time
|
||||
@@ -8,7 +8,7 @@ Subject: [PATCH 5/7] Use roborio time
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c
|
||||
index a66bb535..8a267823 100644
|
||||
index 85f3fc01..12ed7ff1 100644
|
||||
--- a/src/unix/linux-core.c
|
||||
+++ b/src/unix/linux-core.c
|
||||
@@ -67,6 +67,10 @@
|
||||
@@ -22,7 +22,7 @@ index a66bb535..8a267823 100644
|
||||
/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
|
||||
* include that file because it conflicts with <time.h>. We'll just have to
|
||||
* define it ourselves.
|
||||
@@ -424,6 +428,9 @@ update_timeout:
|
||||
@@ -118,6 +122,9 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
@@ -32,7 +32,7 @@ index a66bb535..8a267823 100644
|
||||
static clock_t fast_clock_id = -1;
|
||||
struct timespec t;
|
||||
clock_t clock_id;
|
||||
@@ -453,6 +460,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
@@ -151,6 +158,7 @@ done:
|
||||
return 0; /* Not really possible. */
|
||||
|
||||
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 88a584f62e18a04a70336027062141739e1591bf Mon Sep 17 00:00:00 2001
|
||||
From 6399ee267f6cc4cafda478b277c8888ee0b08632 Mon Sep 17 00:00:00 2001
|
||||
From: PJ Reiniger <pj.reiniger@gmail.com>
|
||||
Date: Tue, 26 Apr 2022 15:28:52 -0400
|
||||
Subject: [PATCH 6/7] Style / comments cleanup
|
||||
@@ -13,7 +13,7 @@ Subject: [PATCH 6/7] Style / comments cleanup
|
||||
6 files changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/fs-poll.c b/src/fs-poll.c
|
||||
index f605bcea..14d64de8 100644
|
||||
index 5a39daed..1a7ca70d 100644
|
||||
--- a/src/fs-poll.c
|
||||
+++ b/src/fs-poll.c
|
||||
@@ -34,6 +34,7 @@
|
||||
@@ -25,11 +25,11 @@ index f605bcea..14d64de8 100644
|
||||
uv_fs_poll_t* parent_handle;
|
||||
int busy_polling;
|
||||
diff --git a/src/unix/core.c b/src/unix/core.c
|
||||
index adb278bc..77bb337c 100644
|
||||
index be2ad1fc..fde43d40 100644
|
||||
--- a/src/unix/core.c
|
||||
+++ b/src/unix/core.c
|
||||
@@ -513,6 +513,7 @@ skip:
|
||||
}
|
||||
@@ -524,6 +524,7 @@ int uv__accept(int sockfd) {
|
||||
return peerfd;
|
||||
}
|
||||
|
||||
+
|
||||
@@ -37,7 +37,7 @@ index adb278bc..77bb337c 100644
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
|
||||
diff --git a/src/unix/thread.c b/src/unix/thread.c
|
||||
index c753be9b..012cd6a1 100644
|
||||
index 64726bd6..392a0715 100644
|
||||
--- a/src/unix/thread.c
|
||||
+++ b/src/unix/thread.c
|
||||
@@ -85,7 +85,6 @@ error2:
|
||||
@@ -56,7 +56,7 @@ index c753be9b..012cd6a1 100644
|
||||
uv_mutex_lock(&b->mutex);
|
||||
|
||||
if (++b->in == b->threshold) {
|
||||
@@ -114,7 +114,6 @@ int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
@@ -113,7 +113,6 @@ int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
return last;
|
||||
}
|
||||
|
||||
@@ -65,10 +65,10 @@ index c753be9b..012cd6a1 100644
|
||||
struct _uv_barrier* b;
|
||||
|
||||
diff --git a/src/uv-common.c b/src/uv-common.c
|
||||
index b61a703d..3c65476a 100644
|
||||
index c287246f..534119c0 100644
|
||||
--- a/src/uv-common.c
|
||||
+++ b/src/uv-common.c
|
||||
@@ -698,6 +698,7 @@ void uv__fs_readdir_cleanup(uv_fs_t* req) {
|
||||
@@ -756,6 +756,7 @@ void uv__fs_readdir_cleanup(uv_fs_t* req) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ index b61a703d..3c65476a 100644
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wvarargs"
|
||||
diff --git a/src/win/process.c b/src/win/process.c
|
||||
index 15f3b65e..3b8675a6 100644
|
||||
index a49016f6..8e7835a5 100644
|
||||
--- a/src/win/process.c
|
||||
+++ b/src/win/process.c
|
||||
@@ -35,7 +35,6 @@
|
||||
@@ -89,7 +89,7 @@ index 15f3b65e..3b8675a6 100644
|
||||
|
||||
|
||||
diff --git a/src/win/winsock.c b/src/win/winsock.c
|
||||
index 918acaf5..668e3b64 100644
|
||||
index 7843e9f1..cda82bc3 100644
|
||||
--- a/src/win/winsock.c
|
||||
+++ b/src/win/winsock.c
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From aca70965b0a80000cb8281d097c78a3e3e0feb16 Mon Sep 17 00:00:00 2001
|
||||
From aa760b0bb41c8052f47f9d49eb100340c1c76634 Mon Sep 17 00:00:00 2001
|
||||
From: Tyler Veness <calcmogul@gmail.com>
|
||||
Date: Tue, 17 May 2022 21:36:57 -0700
|
||||
Subject: [PATCH 7/7] Squelch GCC 12.1 warnings
|
||||
@@ -9,10 +9,10 @@ Subject: [PATCH 7/7] Squelch GCC 12.1 warnings
|
||||
2 files changed, 18 insertions(+)
|
||||
|
||||
diff --git a/src/unix/stream.c b/src/unix/stream.c
|
||||
index f3a8e66d..8aeca159 100644
|
||||
index 41763959..779e8ff8 100644
|
||||
--- a/src/unix/stream.c
|
||||
+++ b/src/unix/stream.c
|
||||
@@ -932,7 +932,16 @@ static void uv__write_callbacks(uv_stream_t* stream) {
|
||||
@@ -941,7 +941,16 @@ static void uv__write_callbacks(uv_stream_t* stream) {
|
||||
if (QUEUE_EMPTY(&stream->write_completed_queue))
|
||||
return;
|
||||
|
||||
@@ -30,10 +30,10 @@ index f3a8e66d..8aeca159 100644
|
||||
while (!QUEUE_EMPTY(&pq)) {
|
||||
/* Pop a req off write_completed_queue. */
|
||||
diff --git a/src/uv-common.c b/src/uv-common.c
|
||||
index 3c65476a..fd56b013 100644
|
||||
index 534119c0..00d03320 100644
|
||||
--- a/src/uv-common.c
|
||||
+++ b/src/uv-common.c
|
||||
@@ -444,7 +444,16 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
|
||||
@@ -502,7 +502,16 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
|
||||
QUEUE* q;
|
||||
uv_handle_t* h;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from upstream_utils import setup_upstream_repo, comment_out_invalid_includes, wa
|
||||
|
||||
def main():
|
||||
root, repo = setup_upstream_repo("https://github.com/libuv/libuv",
|
||||
"v1.30.1")
|
||||
"v1.44.1")
|
||||
wpinet = os.path.join(root, "wpinet")
|
||||
|
||||
# Apply patches to original git repo
|
||||
@@ -43,11 +43,16 @@ def main():
|
||||
"aix-common.c",
|
||||
"aix.c",
|
||||
"bsd-proctitle.c",
|
||||
"darwin-stub.c",
|
||||
"haiku.c",
|
||||
"hurd.c",
|
||||
"os390-proctitle.c",
|
||||
"os390-syscalls.c",
|
||||
"os390-syscalls.h",
|
||||
"os390.c",
|
||||
"qnx.c",
|
||||
"sunos.c",
|
||||
"sysinfo-loadavg.c",
|
||||
"sysinfo-memory.c",
|
||||
]
|
||||
src_files = walk_cwd_and_copy_if(
|
||||
|
||||
@@ -87,6 +87,9 @@ set(uv_unix_src
|
||||
src/main/native/thirdparty/libuv/src/unix/pipe.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/poll.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/process.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/random-devurandom.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/random-getentropy.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/random-getrandom.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/signal.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/stream.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/tcp.cpp
|
||||
@@ -105,12 +108,13 @@ set(uv_darwin_src
|
||||
)
|
||||
|
||||
set(uv_linux_src
|
||||
src/main/native/thirdparty/libuv/src/unix/epoll.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/linux-core.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/linux-inotify.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/linux-syscalls.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/procfs-exepath.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/proctitle.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/sysinfo-loadavg.cpp
|
||||
src/main/native/thirdparty/libuv/src/unix/random-sysctl-linux.cpp
|
||||
)
|
||||
|
||||
add_library(wpinet ${wpinet_native_src} ${wpinet_resources_src})
|
||||
|
||||
@@ -51,6 +51,9 @@ ext {
|
||||
'pipe.cpp',
|
||||
'poll.cpp',
|
||||
'process.cpp',
|
||||
'random-devurandom.cpp',
|
||||
'random-getentropy.cpp',
|
||||
'random-getrandom.cpp',
|
||||
'signal.cpp',
|
||||
'stream.cpp',
|
||||
'tcp.cpp',
|
||||
@@ -136,12 +139,13 @@ ext {
|
||||
source {
|
||||
srcDirs 'src/main/native/thirdparty/libuv/src/unix'
|
||||
includes = [
|
||||
'epoll.cpp',
|
||||
'linux-core.cpp',
|
||||
'linux-inotify.cpp',
|
||||
'linux-syscalls.cpp',
|
||||
'procfs-exepath.cpp',
|
||||
'proctitle.cpp',
|
||||
'sysinfo-loadavg.cpp',
|
||||
'random-sysctl-linux.cpp',
|
||||
]
|
||||
}
|
||||
exportedHeaders {
|
||||
|
||||
191
wpinet/src/main/native/thirdparty/libuv/include/uv.h
vendored
191
wpinet/src/main/native/thirdparty/libuv/include/uv.h
vendored
@@ -24,6 +24,10 @@
|
||||
#ifndef UV_H
|
||||
#define UV_H
|
||||
|
||||
#if defined(BUILDING_UV_SHARED) && defined(USING_UV_SHARED)
|
||||
#error "Define either BUILDING_UV_SHARED or USING_UV_SHARED, not both."
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Windows - set up dll import/export decorators. */
|
||||
# if defined(BUILDING_UV_SHARED)
|
||||
@@ -38,6 +42,8 @@
|
||||
# endif
|
||||
#elif __GNUC__ >= 4
|
||||
# define UV_EXTERN __attribute__((visibility("default")))
|
||||
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) /* Sun Studio >= 8 */
|
||||
# define UV_EXTERN __global
|
||||
#else
|
||||
# define UV_EXTERN /* nothing */
|
||||
#endif
|
||||
@@ -115,6 +121,7 @@
|
||||
XX(ENOTEMPTY, "directory not empty") \
|
||||
XX(ENOTSOCK, "socket operation on non-socket") \
|
||||
XX(ENOTSUP, "operation not supported on socket") \
|
||||
XX(EOVERFLOW, "value too large for defined data type") \
|
||||
XX(EPERM, "operation not permitted") \
|
||||
XX(EPIPE, "broken pipe") \
|
||||
XX(EPROTO, "protocol error") \
|
||||
@@ -136,6 +143,8 @@
|
||||
XX(EREMOTEIO, "remote I/O error") \
|
||||
XX(ENOTTY, "inappropriate ioctl for device") \
|
||||
XX(EFTYPE, "inappropriate file type or format") \
|
||||
XX(EILSEQ, "illegal byte sequence") \
|
||||
XX(ESOCKTNOSUPPORT, "socket type not supported") \
|
||||
|
||||
#define UV_HANDLE_TYPE_MAP(XX) \
|
||||
XX(ASYNC, async) \
|
||||
@@ -165,6 +174,7 @@
|
||||
XX(WORK, work) \
|
||||
XX(GETADDRINFO, getaddrinfo) \
|
||||
XX(GETNAMEINFO, getnameinfo) \
|
||||
XX(RANDOM, random) \
|
||||
|
||||
typedef enum {
|
||||
#define XX(code, _) UV_ ## code = UV__ ## code,
|
||||
@@ -222,16 +232,20 @@ typedef struct uv_connect_s uv_connect_t;
|
||||
typedef struct uv_udp_send_s uv_udp_send_t;
|
||||
typedef struct uv_fs_s uv_fs_t;
|
||||
typedef struct uv_work_s uv_work_t;
|
||||
typedef struct uv_random_s uv_random_t;
|
||||
|
||||
/* None of the above. */
|
||||
typedef struct uv_env_item_s uv_env_item_t;
|
||||
typedef struct uv_cpu_info_s uv_cpu_info_t;
|
||||
typedef struct uv_interface_address_s uv_interface_address_t;
|
||||
typedef struct uv_dirent_s uv_dirent_t;
|
||||
typedef struct uv_passwd_s uv_passwd_t;
|
||||
typedef struct uv_utsname_s uv_utsname_t;
|
||||
typedef struct uv_statfs_s uv_statfs_t;
|
||||
|
||||
typedef enum {
|
||||
UV_LOOP_BLOCK_SIGNAL
|
||||
UV_LOOP_BLOCK_SIGNAL = 0,
|
||||
UV_METRICS_IDLE_TIME
|
||||
} uv_loop_option;
|
||||
|
||||
typedef enum {
|
||||
@@ -249,6 +263,8 @@ typedef void* (*uv_realloc_func)(void* ptr, size_t size);
|
||||
typedef void* (*uv_calloc_func)(size_t count, size_t size);
|
||||
typedef void (*uv_free_func)(void* ptr);
|
||||
|
||||
UV_EXTERN void uv_library_shutdown(void);
|
||||
|
||||
UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func,
|
||||
uv_realloc_func realloc_func,
|
||||
uv_calloc_func calloc_func,
|
||||
@@ -316,6 +332,10 @@ typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
|
||||
int status,
|
||||
const char* hostname,
|
||||
const char* service);
|
||||
typedef void (*uv_random_cb)(uv_random_t* req,
|
||||
int status,
|
||||
void* buf,
|
||||
size_t buflen);
|
||||
|
||||
typedef struct {
|
||||
long tv_sec;
|
||||
@@ -452,6 +472,12 @@ UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
|
||||
|
||||
UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
|
||||
|
||||
UV_EXTERN int uv_pipe(uv_file fds[2], int read_flags, int write_flags);
|
||||
UV_EXTERN int uv_socketpair(int type,
|
||||
int protocol,
|
||||
uv_os_sock_t socket_vector[2],
|
||||
int flags0,
|
||||
int flags1);
|
||||
|
||||
#define UV_STREAM_FIELDS \
|
||||
/* number of bytes queued for writing */ \
|
||||
@@ -497,6 +523,10 @@ UV_EXTERN int uv_write2(uv_write_t* req,
|
||||
UV_EXTERN int uv_try_write(uv_stream_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs);
|
||||
UV_EXTERN int uv_try_write2(uv_stream_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
uv_stream_t* send_handle);
|
||||
|
||||
/* uv_write_t is a subclass of uv_req_t. */
|
||||
struct uv_write_s {
|
||||
@@ -550,6 +580,7 @@ UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle,
|
||||
UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen);
|
||||
UV_EXTERN int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb);
|
||||
UV_EXTERN int uv_tcp_connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
@@ -584,7 +615,30 @@ enum uv_udp_flags {
|
||||
* (provided they all set the flag) but only the last one to bind will receive
|
||||
* any traffic, in effect "stealing" the port from the previous listener.
|
||||
*/
|
||||
UV_UDP_REUSEADDR = 4
|
||||
UV_UDP_REUSEADDR = 4,
|
||||
/*
|
||||
* Indicates that the message was received by recvmmsg, so the buffer provided
|
||||
* must not be freed by the recv_cb callback.
|
||||
*/
|
||||
UV_UDP_MMSG_CHUNK = 8,
|
||||
/*
|
||||
* Indicates that the buffer provided has been fully utilized by recvmmsg and
|
||||
* that it should now be freed by the recv_cb callback. When this flag is set
|
||||
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
|
||||
*/
|
||||
UV_UDP_MMSG_FREE = 16,
|
||||
/*
|
||||
* Indicates if IP_RECVERR/IPV6_RECVERR will be set when binding the handle.
|
||||
* This sets IP_RECVERR for IPv4 and IPV6_RECVERR for IPv6 UDP sockets on
|
||||
* Linux. This stops the Linux kernel from suppressing some ICMP error
|
||||
* messages and enables full ICMP error reporting for faster failover.
|
||||
* This flag is no-op on platforms other than Linux.
|
||||
*/
|
||||
UV_UDP_LINUX_RECVERR = 32,
|
||||
/*
|
||||
* Indicates that recvmmsg should be used, if available.
|
||||
*/
|
||||
UV_UDP_RECVMMSG = 256
|
||||
};
|
||||
|
||||
typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
|
||||
@@ -636,6 +690,11 @@ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
uv_membership membership);
|
||||
UV_EXTERN int uv_udp_set_source_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const char* source_addr,
|
||||
uv_membership membership);
|
||||
UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on);
|
||||
UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl);
|
||||
UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle,
|
||||
@@ -655,6 +714,7 @@ UV_EXTERN int uv_udp_try_send(uv_udp_t* handle,
|
||||
UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_udp_recv_cb recv_cb);
|
||||
UV_EXTERN int uv_udp_using_recvmmsg(const uv_udp_t* handle);
|
||||
UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
|
||||
UV_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle);
|
||||
UV_EXTERN size_t uv_udp_get_send_queue_count(const uv_udp_t* handle);
|
||||
@@ -680,10 +740,25 @@ typedef enum {
|
||||
UV_TTY_MODE_IO
|
||||
} uv_tty_mode_t;
|
||||
|
||||
typedef enum {
|
||||
/*
|
||||
* The console supports handling of virtual terminal sequences
|
||||
* (Windows10 new console, ConEmu)
|
||||
*/
|
||||
UV_TTY_SUPPORTED,
|
||||
/* The console cannot process the virtual terminal sequence. (Legacy
|
||||
* console)
|
||||
*/
|
||||
UV_TTY_UNSUPPORTED
|
||||
} uv_tty_vtermstate_t;
|
||||
|
||||
|
||||
UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable);
|
||||
UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode);
|
||||
UV_EXTERN int uv_tty_reset_mode(void);
|
||||
UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
|
||||
UV_EXTERN void uv_tty_set_vterm_state(uv_tty_vtermstate_t state);
|
||||
UV_EXTERN int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state);
|
||||
|
||||
inline int uv_tty_set_mode(uv_tty_t* handle, int mode) {
|
||||
return uv_tty_set_mode(handle, static_cast<uv_tty_mode_t>(mode));
|
||||
@@ -804,6 +879,7 @@ UV_EXTERN int uv_timer_stop(uv_timer_t* handle);
|
||||
UV_EXTERN int uv_timer_again(uv_timer_t* handle);
|
||||
UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat);
|
||||
UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle);
|
||||
UV_EXTERN uint64_t uv_timer_get_due_in(const uv_timer_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
@@ -865,10 +941,13 @@ typedef enum {
|
||||
UV_WRITABLE_PIPE = 0x20,
|
||||
|
||||
/*
|
||||
* Open the child pipe handle in overlapped mode on Windows.
|
||||
* On Unix it is silently ignored.
|
||||
* When UV_CREATE_PIPE is specified, specifying UV_NONBLOCK_PIPE opens the
|
||||
* handle in non-blocking mode in the child. This may cause loss of data,
|
||||
* if the child is not designed to handle to encounter this mode,
|
||||
* but can also be significantly more efficient.
|
||||
*/
|
||||
UV_OVERLAPPED_PIPE = 0x40
|
||||
UV_NONBLOCK_PIPE = 0x40,
|
||||
UV_OVERLAPPED_PIPE = 0x40 /* old name, for compatibility */
|
||||
} uv_stdio_flags;
|
||||
|
||||
typedef struct uv_stdio_container_s {
|
||||
@@ -1012,11 +1091,11 @@ UV_EXTERN int uv_cancel(uv_req_t* req);
|
||||
|
||||
|
||||
struct uv_cpu_times_s {
|
||||
uint64_t user;
|
||||
uint64_t nice;
|
||||
uint64_t sys;
|
||||
uint64_t idle;
|
||||
uint64_t irq;
|
||||
uint64_t user; /* milliseconds */
|
||||
uint64_t nice; /* milliseconds */
|
||||
uint64_t sys; /* milliseconds */
|
||||
uint64_t idle; /* milliseconds */
|
||||
uint64_t irq; /* milliseconds */
|
||||
};
|
||||
|
||||
struct uv_cpu_info_s {
|
||||
@@ -1041,8 +1120,8 @@ struct uv_interface_address_s {
|
||||
|
||||
struct uv_passwd_s {
|
||||
char* username;
|
||||
long uid;
|
||||
long gid;
|
||||
unsigned long uid;
|
||||
unsigned long gid;
|
||||
char* shell;
|
||||
char* homedir;
|
||||
};
|
||||
@@ -1057,6 +1136,17 @@ struct uv_utsname_s {
|
||||
to as meaningless in the docs. */
|
||||
};
|
||||
|
||||
struct uv_statfs_s {
|
||||
uint64_t f_type;
|
||||
uint64_t f_bsize;
|
||||
uint64_t f_blocks;
|
||||
uint64_t f_bfree;
|
||||
uint64_t f_bavail;
|
||||
uint64_t f_files;
|
||||
uint64_t f_ffree;
|
||||
uint64_t f_spare[4];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UV_DIRENT_UNKNOWN,
|
||||
UV_DIRENT_FILE,
|
||||
@@ -1119,16 +1209,27 @@ UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
|
||||
UV_EXTERN uv_pid_t uv_os_getpid(void);
|
||||
UV_EXTERN uv_pid_t uv_os_getppid(void);
|
||||
|
||||
#define UV_PRIORITY_LOW 19
|
||||
#define UV_PRIORITY_BELOW_NORMAL 10
|
||||
#define UV_PRIORITY_NORMAL 0
|
||||
#define UV_PRIORITY_ABOVE_NORMAL -7
|
||||
#define UV_PRIORITY_HIGH -14
|
||||
#define UV_PRIORITY_HIGHEST -20
|
||||
#if defined(__PASE__)
|
||||
/* On IBM i PASE, the highest process priority is -10 */
|
||||
# define UV_PRIORITY_LOW 39 /* RUNPTY(99) */
|
||||
# define UV_PRIORITY_BELOW_NORMAL 15 /* RUNPTY(50) */
|
||||
# define UV_PRIORITY_NORMAL 0 /* RUNPTY(20) */
|
||||
# define UV_PRIORITY_ABOVE_NORMAL -4 /* RUNTY(12) */
|
||||
# define UV_PRIORITY_HIGH -7 /* RUNPTY(6) */
|
||||
# define UV_PRIORITY_HIGHEST -10 /* RUNPTY(1) */
|
||||
#else
|
||||
# define UV_PRIORITY_LOW 19
|
||||
# define UV_PRIORITY_BELOW_NORMAL 10
|
||||
# define UV_PRIORITY_NORMAL 0
|
||||
# define UV_PRIORITY_ABOVE_NORMAL -7
|
||||
# define UV_PRIORITY_HIGH -14
|
||||
# define UV_PRIORITY_HIGHEST -20
|
||||
#endif
|
||||
|
||||
UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
|
||||
UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
|
||||
|
||||
UV_EXTERN unsigned int uv_available_parallelism(void);
|
||||
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
|
||||
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
|
||||
|
||||
@@ -1137,6 +1238,13 @@ UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count);
|
||||
|
||||
struct uv_env_item_s {
|
||||
char* name;
|
||||
char* value;
|
||||
};
|
||||
|
||||
UV_EXTERN int uv_os_environ(uv_env_item_t** envitems, int* count);
|
||||
UV_EXTERN void uv_os_free_environ(uv_env_item_t* envitems, int count);
|
||||
UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size);
|
||||
UV_EXTERN int uv_os_setenv(const char* name, const char* value);
|
||||
UV_EXTERN int uv_os_unsetenv(const char* name);
|
||||
@@ -1156,6 +1264,7 @@ UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size);
|
||||
|
||||
UV_EXTERN int uv_os_uname(uv_utsname_t* buffer);
|
||||
|
||||
UV_EXTERN uint64_t uv_metrics_idle_time(uv_loop_t* loop);
|
||||
|
||||
typedef enum {
|
||||
UV_FS_UNKNOWN = -1,
|
||||
@@ -1192,7 +1301,10 @@ typedef enum {
|
||||
UV_FS_LCHOWN,
|
||||
UV_FS_OPENDIR,
|
||||
UV_FS_READDIR,
|
||||
UV_FS_CLOSEDIR
|
||||
UV_FS_CLOSEDIR,
|
||||
UV_FS_STATFS,
|
||||
UV_FS_MKSTEMP,
|
||||
UV_FS_LUTIME
|
||||
} uv_fs_type;
|
||||
|
||||
struct uv_dir_s {
|
||||
@@ -1217,6 +1329,7 @@ struct uv_fs_s {
|
||||
|
||||
UV_EXTERN uv_fs_type uv_fs_get_type(const uv_fs_t*);
|
||||
UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*);
|
||||
UV_EXTERN int uv_fs_get_system_error(const uv_fs_t*);
|
||||
UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*);
|
||||
UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*);
|
||||
UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*);
|
||||
@@ -1283,6 +1396,10 @@ UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_mkstemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
@@ -1361,6 +1478,12 @@ UV_EXTERN int uv_fs_futime(uv_loop_t* loop,
|
||||
double atime,
|
||||
double mtime,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_lutime(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
double atime,
|
||||
double mtime,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_lstat(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
@@ -1420,6 +1543,10 @@ UV_EXTERN int uv_fs_lchown(uv_loop_t* loop,
|
||||
uv_uid_t uid,
|
||||
uv_gid_t gid,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb);
|
||||
|
||||
|
||||
enum uv_fs_event {
|
||||
@@ -1521,10 +1648,31 @@ UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr);
|
||||
|
||||
UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size);
|
||||
UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size);
|
||||
UV_EXTERN int uv_ip_name(const struct sockaddr* src, char* dst, size_t size);
|
||||
|
||||
UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
|
||||
UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
|
||||
|
||||
|
||||
struct uv_random_s {
|
||||
UV_REQ_FIELDS
|
||||
/* read-only */
|
||||
uv_loop_t* loop;
|
||||
/* private */
|
||||
int status;
|
||||
void* buf;
|
||||
size_t buflen;
|
||||
uv_random_cb cb;
|
||||
struct uv__work work_req;
|
||||
};
|
||||
|
||||
UV_EXTERN int uv_random(uv_loop_t* loop,
|
||||
uv_random_t* req,
|
||||
void *buf,
|
||||
size_t buflen,
|
||||
unsigned flags, /* For future extension; must be 0. */
|
||||
uv_random_cb cb);
|
||||
|
||||
#if defined(IF_NAMESIZE)
|
||||
# define UV_IF_NAMESIZE (IF_NAMESIZE + 1)
|
||||
#elif defined(IFNAMSIZ)
|
||||
@@ -1551,6 +1699,7 @@ UV_EXTERN uint64_t uv_get_total_memory(void);
|
||||
UV_EXTERN uint64_t uv_get_constrained_memory(void);
|
||||
|
||||
UV_EXTERN uint64_t uv_hrtime(void);
|
||||
UV_EXTERN void uv_sleep(unsigned int msec);
|
||||
|
||||
UV_EXTERN void uv_disable_stdio_inheritance(void);
|
||||
|
||||
@@ -1648,9 +1797,11 @@ struct uv_loop_s {
|
||||
unsigned int active_handles;
|
||||
void* handle_queue[2];
|
||||
union {
|
||||
void* unused[2];
|
||||
void* unused;
|
||||
unsigned int count;
|
||||
} active_reqs;
|
||||
/* Internal storage for future extensions. */
|
||||
void* internal_fields;
|
||||
/* Internal flag to signal loop stop. */
|
||||
unsigned int stop_flag;
|
||||
UV_LOOP_PRIVATE_FIELDS
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 1999
|
||||
* Berkeley Software Design, 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:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
|
||||
*
|
||||
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
|
||||
*/
|
||||
|
||||
#ifndef _IFADDRS_H_
|
||||
#define _IFADDRS_H_
|
||||
|
||||
struct ifaddrs {
|
||||
struct ifaddrs *ifa_next;
|
||||
char *ifa_name;
|
||||
unsigned int ifa_flags;
|
||||
struct sockaddr *ifa_addr;
|
||||
struct sockaddr *ifa_netmask;
|
||||
struct sockaddr *ifa_dstaddr;
|
||||
void *ifa_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
|
||||
* to be included it must be included before this header file.
|
||||
*/
|
||||
#ifndef ifa_broadaddr
|
||||
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
extern int getifaddrs(struct ifaddrs **ifap);
|
||||
extern void freeifaddrs(struct ifaddrs *ifa);
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -317,7 +317,7 @@
|
||||
#if defined(EPROTO) && !defined(_WIN32)
|
||||
# define UV__EPROTO UV__ERR(EPROTO)
|
||||
#else
|
||||
# define UV__EPROTO UV__ERR(4046)
|
||||
# define UV__EPROTO (-4046)
|
||||
#endif
|
||||
|
||||
#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
|
||||
@@ -439,5 +439,22 @@
|
||||
# define UV__EFTYPE (-4028)
|
||||
#endif
|
||||
|
||||
#if defined(EILSEQ) && !defined(_WIN32)
|
||||
# define UV__EILSEQ UV__ERR(EILSEQ)
|
||||
#else
|
||||
# define UV__EILSEQ (-4027)
|
||||
#endif
|
||||
|
||||
#if defined(EOVERFLOW) && !defined(_WIN32)
|
||||
# define UV__EOVERFLOW UV__ERR(EOVERFLOW)
|
||||
#else
|
||||
# define UV__EOVERFLOW (-4026)
|
||||
#endif
|
||||
|
||||
#if defined(ESOCKTNOSUPPORT) && !defined(_WIN32)
|
||||
# define UV__ESOCKTNOSUPPORT UV__ERR(ESOCKTNOSUPPORT)
|
||||
#else
|
||||
# define UV__ESOCKTNOSUPPORT (-4025)
|
||||
#endif
|
||||
|
||||
#endif /* UV_ERRNO_H_ */
|
||||
|
||||
@@ -251,7 +251,7 @@ void name##_SPLAY_MINMAX(struct name *head, int __comp) \
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
while (1) { \
|
||||
for (;;) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
|
||||
@@ -55,13 +55,12 @@
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include "uv/bsd.h"
|
||||
#elif defined(__PASE__) || \
|
||||
defined(__CYGWIN__) || \
|
||||
#elif defined(__CYGWIN__) || \
|
||||
defined(__MSYS__) || \
|
||||
defined(__HAIKU__) || \
|
||||
defined(__QNX__) || \
|
||||
defined(__GNU__)
|
||||
# include "uv/posix.h"
|
||||
#elif defined(__HAIKU__)
|
||||
# include "uv/posix.h"
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXHOST
|
||||
@@ -398,11 +397,25 @@ typedef struct {
|
||||
#else
|
||||
# define UV_FS_O_CREAT 0
|
||||
#endif
|
||||
#if defined(O_DIRECT)
|
||||
|
||||
#if defined(__linux__) && defined(__arm__)
|
||||
# define UV_FS_O_DIRECT 0x10000
|
||||
#elif defined(__linux__) && defined(__m68k__)
|
||||
# define UV_FS_O_DIRECT 0x10000
|
||||
#elif defined(__linux__) && defined(__mips__)
|
||||
# define UV_FS_O_DIRECT 0x08000
|
||||
#elif defined(__linux__) && defined(__powerpc__)
|
||||
# define UV_FS_O_DIRECT 0x20000
|
||||
#elif defined(__linux__) && defined(__s390x__)
|
||||
# define UV_FS_O_DIRECT 0x04000
|
||||
#elif defined(__linux__) && defined(__x86_64__)
|
||||
# define UV_FS_O_DIRECT 0x04000
|
||||
#elif defined(O_DIRECT)
|
||||
# define UV_FS_O_DIRECT O_DIRECT
|
||||
#else
|
||||
# define UV_FS_O_DIRECT 0
|
||||
#endif
|
||||
|
||||
#if defined(O_DIRECTORY)
|
||||
# define UV_FS_O_DIRECTORY O_DIRECTORY
|
||||
#else
|
||||
@@ -475,6 +488,7 @@ typedef struct {
|
||||
#endif
|
||||
|
||||
/* fs open() flags supported on other platforms: */
|
||||
#define UV_FS_O_FILEMAP 0
|
||||
#define UV_FS_O_RANDOM 0
|
||||
#define UV_FS_O_SHORT_LIVED 0
|
||||
#define UV_FS_O_SEQUENTIAL 0
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
* Versions with the same major number are ABI stable. API is allowed to
|
||||
* evolve between minor releases, but only in a backwards compatible way.
|
||||
* Make sure you update the -soname directives in configure.ac
|
||||
* and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
|
||||
* whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
|
||||
* not UV_VERSION_PATCH.)
|
||||
*/
|
||||
|
||||
#define UV_VERSION_MAJOR 1
|
||||
#define UV_VERSION_MINOR 30
|
||||
#define UV_VERSION_MINOR 44
|
||||
#define UV_VERSION_PATCH 1
|
||||
#define UV_VERSION_IS_RELEASE 1
|
||||
#define UV_VERSION_SUFFIX ""
|
||||
|
||||
@@ -45,7 +45,14 @@ typedef struct pollfd {
|
||||
#endif
|
||||
|
||||
#include <mswsock.h>
|
||||
// Disable the typedef in mstcpip.h of MinGW.
|
||||
#define _TCP_INITIAL_RTO_PARAMETERS _TCP_INITIAL_RTO_PARAMETERS__AVOID
|
||||
#define TCP_INITIAL_RTO_PARAMETERS TCP_INITIAL_RTO_PARAMETERS__AVOID
|
||||
#define PTCP_INITIAL_RTO_PARAMETERS PTCP_INITIAL_RTO_PARAMETERS__AVOID
|
||||
#include <ws2tcpip.h>
|
||||
#undef _TCP_INITIAL_RTO_PARAMETERS
|
||||
#undef TCP_INITIAL_RTO_PARAMETERS
|
||||
#undef PTCP_INITIAL_RTO_PARAMETERS
|
||||
#include <windows.h>
|
||||
|
||||
#include <process.h>
|
||||
@@ -217,7 +224,7 @@ typedef struct _AFD_POLL_INFO {
|
||||
AFD_POLL_HANDLE_INFO Handles[1];
|
||||
} AFD_POLL_INFO, *PAFD_POLL_INFO;
|
||||
|
||||
#define UV_MSAFD_PROVIDER_COUNT 3
|
||||
#define UV_MSAFD_PROVIDER_COUNT 4
|
||||
|
||||
|
||||
/**
|
||||
@@ -257,21 +264,14 @@ typedef union {
|
||||
} unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */
|
||||
} uv_cond_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
unsigned int num_readers_;
|
||||
CRITICAL_SECTION num_readers_lock_;
|
||||
HANDLE write_semaphore_;
|
||||
} state_;
|
||||
/* TODO: remove me in v2.x. */
|
||||
struct {
|
||||
SRWLOCK unused_;
|
||||
} unused1_;
|
||||
/* TODO: remove me in v2.x. */
|
||||
struct {
|
||||
uv_mutex_t unused1_;
|
||||
uv_mutex_t unused2_;
|
||||
} unused2_;
|
||||
typedef struct {
|
||||
SRWLOCK read_write_lock_;
|
||||
/* TODO: retained for ABI compatibility; remove me in v2.x */
|
||||
#ifdef _WIN64
|
||||
unsigned char padding_[72];
|
||||
#else
|
||||
unsigned char padding_[44];
|
||||
#endif
|
||||
} uv_rwlock_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -518,7 +518,7 @@ typedef struct {
|
||||
/* eol conversion state */ \
|
||||
unsigned char previous_eol; \
|
||||
/* ansi parser state */ \
|
||||
unsigned char ansi_parser_state; \
|
||||
unsigned short ansi_parser_state; \
|
||||
unsigned char ansi_csi_argc; \
|
||||
unsigned short ansi_csi_argv[4]; \
|
||||
COORD saved_position; \
|
||||
@@ -669,6 +669,7 @@ typedef struct {
|
||||
#define UV_FS_O_APPEND _O_APPEND
|
||||
#define UV_FS_O_CREAT _O_CREAT
|
||||
#define UV_FS_O_EXCL _O_EXCL
|
||||
#define UV_FS_O_FILEMAP 0x20000000
|
||||
#define UV_FS_O_RANDOM _O_RANDOM
|
||||
#define UV_FS_O_RDONLY _O_RDONLY
|
||||
#define UV_FS_O_RDWR _O_RDWR
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#ifdef _WIN32
|
||||
#include "win/internal.h"
|
||||
#include "win/handle-inl.h"
|
||||
#define uv__make_close_pending(h) uv_want_endgame((h)->loop, (h))
|
||||
#define uv__make_close_pending(h) uv__want_endgame((h)->loop, (h))
|
||||
#else
|
||||
#include "unix/internal.h"
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
#include "uv.h"
|
||||
#include "idna.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <limits.h> /* UINT_MAX */
|
||||
|
||||
static unsigned uv__utf8_decode1_slow(const char** p,
|
||||
const char* pe,
|
||||
@@ -32,7 +34,7 @@ static unsigned uv__utf8_decode1_slow(const char** p,
|
||||
if (a > 0xF7)
|
||||
return -1;
|
||||
|
||||
switch (*p - pe) {
|
||||
switch (pe - *p) {
|
||||
default:
|
||||
if (a > 0xEF) {
|
||||
min = 0x10000;
|
||||
@@ -62,6 +64,8 @@ static unsigned uv__utf8_decode1_slow(const char** p,
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
case 0:
|
||||
return -1; /* Invalid continuation byte. */
|
||||
}
|
||||
|
||||
@@ -88,6 +92,8 @@ static unsigned uv__utf8_decode1_slow(const char** p,
|
||||
unsigned uv__utf8_decode1(const char** p, const char* pe) {
|
||||
unsigned a;
|
||||
|
||||
assert(*p < pe);
|
||||
|
||||
a = (unsigned char) *(*p)++;
|
||||
|
||||
if (a < 128)
|
||||
@@ -96,9 +102,6 @@ unsigned uv__utf8_decode1(const char** p, const char* pe) {
|
||||
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";
|
||||
@@ -121,15 +124,22 @@ static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
ss = s;
|
||||
todo = 0;
|
||||
|
||||
foreach_codepoint(c, &s, se) {
|
||||
/* Note: after this loop we've visited all UTF-8 characters and know
|
||||
* they're legal so we no longer need to check for decode errors.
|
||||
*/
|
||||
while (s < se) {
|
||||
c = uv__utf8_decode1(&s, se);
|
||||
|
||||
if (c == UINT_MAX)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (c < 128)
|
||||
h++;
|
||||
else if (c == (unsigned) -1)
|
||||
return UV_EINVAL;
|
||||
else
|
||||
todo++;
|
||||
}
|
||||
|
||||
/* Only write "xn--" when there are non-ASCII characters. */
|
||||
if (todo > 0) {
|
||||
if (*d < de) *(*d)++ = 'x';
|
||||
if (*d < de) *(*d)++ = 'n';
|
||||
@@ -137,9 +147,13 @@ static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
if (*d < de) *(*d)++ = '-';
|
||||
}
|
||||
|
||||
/* Write ASCII characters. */
|
||||
x = 0;
|
||||
s = ss;
|
||||
foreach_codepoint(c, &s, se) {
|
||||
while (s < se) {
|
||||
c = uv__utf8_decode1(&s, se);
|
||||
assert(c != UINT_MAX);
|
||||
|
||||
if (c > 127)
|
||||
continue;
|
||||
|
||||
@@ -166,10 +180,15 @@ static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
while (todo > 0) {
|
||||
m = -1;
|
||||
s = ss;
|
||||
foreach_codepoint(c, &s, se)
|
||||
|
||||
while (s < se) {
|
||||
c = uv__utf8_decode1(&s, se);
|
||||
assert(c != UINT_MAX);
|
||||
|
||||
if (c >= n)
|
||||
if (c < m)
|
||||
m = c;
|
||||
}
|
||||
|
||||
x = m - n;
|
||||
y = h + 1;
|
||||
@@ -181,7 +200,10 @@ static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
n = m;
|
||||
|
||||
s = ss;
|
||||
foreach_codepoint(c, &s, se) {
|
||||
while (s < se) {
|
||||
c = uv__utf8_decode1(&s, se);
|
||||
assert(c != UINT_MAX);
|
||||
|
||||
if (c < n)
|
||||
if (++delta == 0)
|
||||
return UV_E2BIG; /* Overflow. */
|
||||
@@ -245,8 +267,6 @@ static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
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;
|
||||
@@ -256,10 +276,14 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
|
||||
|
||||
ds = d;
|
||||
|
||||
for (si = s; si < se; /* empty */) {
|
||||
si = s;
|
||||
while (si < se) {
|
||||
st = si;
|
||||
c = uv__utf8_decode1(&si, se);
|
||||
|
||||
if (c == UINT_MAX)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (c != '.')
|
||||
if (c != 0x3002) /* 。 */
|
||||
if (c != 0xFF0E) /* . */
|
||||
|
||||
@@ -145,8 +145,9 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
|
||||
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
|
||||
*tp++ = ':';
|
||||
*tp++ = '\0';
|
||||
if (UV_E2BIG == uv__strscpy(dst, tmp, size))
|
||||
if ((size_t) (tp - tmp) > size)
|
||||
return UV_ENOSPC;
|
||||
uv__strscpy(dst, tmp, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
123
wpinet/src/main/native/thirdparty/libuv/src/random.cpp
vendored
Normal file
123
wpinet/src/main/native/thirdparty/libuv/src/random.cpp
vendored
Normal 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;
|
||||
}
|
||||
@@ -1,3 +1,24 @@
|
||||
/* 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 */
|
||||
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/* 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_
|
||||
|
||||
@@ -7,7 +28,7 @@
|
||||
*/
|
||||
#include "uv.h"
|
||||
|
||||
/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates
|
||||
/* Copies up to |n-1| bytes from |s| to |d| and always zero-terminates
|
||||
* the result, except when |n==0|. Returns the number of bytes copied
|
||||
* or UV_E2BIG if |d| is too small.
|
||||
*
|
||||
|
||||
@@ -164,14 +164,20 @@ static void post(QUEUE* q, enum uv__work_kind kind) {
|
||||
}
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
UV_DESTRUCTOR(static void cleanup(void)) {
|
||||
#ifdef __MVS__
|
||||
/* TODO(itodorov) - zos: revisit when Woz compiler is available. */
|
||||
__attribute__((destructor))
|
||||
#endif
|
||||
void uv__threadpool_cleanup(void) {
|
||||
unsigned int i;
|
||||
|
||||
if (nthreads == 0)
|
||||
return;
|
||||
|
||||
#ifndef __MVS__
|
||||
/* TODO(gabylb) - zos: revisit when Woz compiler is available. */
|
||||
post(&exit_message, UV__WORK_CPU);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
if (uv_thread_join(threads + i))
|
||||
@@ -186,7 +192,6 @@ UV_DESTRUCTOR(static void cleanup(void)) {
|
||||
threads = NULL;
|
||||
nthreads = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void init_threads(void) {
|
||||
@@ -376,6 +381,10 @@ int uv_cancel(uv_req_t* req) {
|
||||
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;
|
||||
|
||||
@@ -51,18 +51,14 @@ static int timer_less_than(const struct heap_node* ha,
|
||||
/* Compare start_id when both have the same timeout. start_id is
|
||||
* allocated with loop->timer_counter in uv_timer_start().
|
||||
*/
|
||||
if (a->start_id < b->start_id)
|
||||
return 1;
|
||||
if (b->start_id < a->start_id)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
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->timeout = 0;
|
||||
handle->repeat = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -74,7 +70,7 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
uint64_t repeat) {
|
||||
uint64_t clamped_timeout;
|
||||
|
||||
if (cb == NULL)
|
||||
if (uv__is_closing(handle) || cb == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
@@ -87,7 +83,7 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
handle->timer_cb = cb;
|
||||
handle->timeout = clamped_timeout;
|
||||
handle->repeat = repeat;
|
||||
/* start_id is the second index to be compared in uv__timer_cmp() */
|
||||
/* 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),
|
||||
@@ -135,6 +131,14 @@ uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
@@ -1,710 +0,0 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
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 = (NetlinkList*)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 = (struct ifaddrs*)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:
|
||||
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;
|
||||
}
|
||||
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 = (struct ifaddrs*)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);
|
||||
}
|
||||
}
|
||||
@@ -32,10 +32,14 @@
|
||||
#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);
|
||||
static int uv__async_eventfd(void);
|
||||
|
||||
|
||||
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
|
||||
@@ -78,20 +82,32 @@ int uv_async_send(uv_async_t* handle) {
|
||||
|
||||
/* Only call this from the event loop thread. */
|
||||
static int uv__async_spin(uv_async_t* handle) {
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
for (;;) {
|
||||
/* 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.
|
||||
/* 997 is not completely chosen at random. It's a prime number, acyclical
|
||||
* by nature, and should therefore hopefully dampen sympathetic resonance.
|
||||
*/
|
||||
rc = cmpxchgi(&handle->pending, 2, 0);
|
||||
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;
|
||||
if (rc != 1)
|
||||
return rc;
|
||||
|
||||
/* Other thread is busy with this handle, spin until it's done. */
|
||||
cpu_relax();
|
||||
/* 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,36 +206,18 @@ static int uv__async_start(uv_loop_t* loop) {
|
||||
if (loop->async_io_watcher.fd != -1)
|
||||
return 0;
|
||||
|
||||
err = uv__async_eventfd();
|
||||
if (err >= 0) {
|
||||
pipefd[0] = err;
|
||||
pipefd[1] = -1;
|
||||
}
|
||||
else if (err == UV_ENOSYS) {
|
||||
err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
|
||||
#if defined(__linux__)
|
||||
/* Save a file descriptor by opening one of the pipe descriptors as
|
||||
* read/write through the procfs. That file descriptor can then
|
||||
* function as both ends of the pipe.
|
||||
*/
|
||||
if (err == 0) {
|
||||
char buf[32];
|
||||
int fd;
|
||||
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
|
||||
fd = uv__open_cloexec(buf, O_RDWR);
|
||||
if (fd >= 0) {
|
||||
uv__close(pipefd[0]);
|
||||
uv__close(pipefd[1]);
|
||||
pipefd[0] = fd;
|
||||
pipefd[1] = fd;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#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_NONBLOCK_PIPE);
|
||||
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);
|
||||
@@ -253,46 +251,3 @@ void uv__async_stop(uv_loop_t* loop) {
|
||||
uv__close(loop->async_io_watcher.fd);
|
||||
loop->async_io_watcher.fd = -1;
|
||||
}
|
||||
|
||||
|
||||
static int uv__async_eventfd(void) {
|
||||
#if defined(__linux__)
|
||||
static int no_eventfd2;
|
||||
static int no_eventfd;
|
||||
int fd;
|
||||
|
||||
if (no_eventfd2)
|
||||
goto skip_eventfd2;
|
||||
|
||||
fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
|
||||
no_eventfd2 = 1;
|
||||
|
||||
skip_eventfd2:
|
||||
|
||||
if (no_eventfd)
|
||||
goto skip_eventfd;
|
||||
|
||||
fd = uv__eventfd(0);
|
||||
if (fd != -1) {
|
||||
uv__cloexec(fd, 1);
|
||||
uv__nonblock(fd, 1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
|
||||
no_eventfd = 1;
|
||||
|
||||
skip_eventfd:
|
||||
|
||||
#endif
|
||||
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
@@ -36,10 +36,6 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
||||
: "r" (newval), "0" (oldval)
|
||||
: "memory");
|
||||
return out;
|
||||
#elif defined(_AIX) && defined(__xlC__)
|
||||
const int out = (*(volatile int*) ptr);
|
||||
__compare_and_swap(ptr, &oldval, newval);
|
||||
return out;
|
||||
#elif defined(__MVS__)
|
||||
unsigned int op4;
|
||||
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
|
||||
@@ -56,7 +52,11 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
||||
|
||||
UV_UNUSED(static void cpu_relax(void)) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
__asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
|
||||
__asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */
|
||||
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
|
||||
__asm__ __volatile__ ("yield" ::: "memory");
|
||||
#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)
|
||||
__asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#if !defined(__CYGWIN__) && !defined(__MSYS__)
|
||||
#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__)
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
@@ -40,10 +40,10 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
return 1;
|
||||
if (ent->ifa_addr == NULL)
|
||||
return 1;
|
||||
#if !defined(__CYGWIN__) && !defined(__MSYS__)
|
||||
#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__)
|
||||
/*
|
||||
* 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
|
||||
* If `exclude_type` is `UV__EXCLUDE_IFPHYS`, return whether `sa_family`
|
||||
* equals `AF_LINK`. Otherwise, the result depends on the operating
|
||||
* system with `AF_LINK` or `PF_INET`.
|
||||
*/
|
||||
if (exclude_type == UV__EXCLUDE_IFPHYS)
|
||||
@@ -53,7 +53,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
defined(__HAIKU__)
|
||||
/*
|
||||
* On BSD getifaddrs returns information related to the raw underlying
|
||||
* devices. We're not interested in this information.
|
||||
* devices. We're not interested in this information.
|
||||
*/
|
||||
if (ent->ifa_addr->sa_family == AF_LINK)
|
||||
return 1;
|
||||
@@ -69,7 +69,9 @@ 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__)) && !defined(__GNU__)
|
||||
int i;
|
||||
#endif
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
@@ -111,7 +113,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
|
||||
}
|
||||
|
||||
if (ent->ifa_netmask->sa_family == AF_INET6) {
|
||||
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);
|
||||
@@ -122,7 +126,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
address++;
|
||||
}
|
||||
|
||||
#if !(defined(__CYGWIN__) || defined(__MSYS__))
|
||||
#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <fcntl.h> /* O_CLOEXEC */
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -49,39 +49,34 @@
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
#if defined(__APPLE__)
|
||||
# include <sys/filio.h>
|
||||
# if defined(O_CLOEXEC)
|
||||
# define UV__O_CLOEXEC O_CLOEXEC
|
||||
# endif
|
||||
#endif
|
||||
# endif /* defined(__APPLE__) */
|
||||
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
# include <crt_externs.h>
|
||||
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
# define environ (*_NSGetEnviron())
|
||||
#else /* defined(__APPLE__) && !TARGET_OS_IPHONE */
|
||||
extern char** environ;
|
||||
#endif /* !(defined(__APPLE__) && !TARGET_OS_IPHONE) */
|
||||
|
||||
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__)
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
# include <sys/sysctl.h>
|
||||
# include <sys/filio.h>
|
||||
# include <sys/wait.h>
|
||||
# define UV__O_CLOEXEC O_CLOEXEC
|
||||
# if defined(__FreeBSD__) && __FreeBSD__ >= 10
|
||||
# if defined(__FreeBSD__)
|
||||
# define uv__accept4 accept4
|
||||
# endif
|
||||
# if defined(__NetBSD__)
|
||||
# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d))
|
||||
# endif
|
||||
# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
|
||||
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
|
||||
# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
|
||||
# endif
|
||||
# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
|
||||
# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
# include <dlfcn.h> /* for dlsym */
|
||||
#endif
|
||||
|
||||
#if defined(__MVS__)
|
||||
@@ -89,16 +84,22 @@
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/syscall.h>
|
||||
# include <sched.h>
|
||||
# include <sys/syscall.h>
|
||||
# define uv__accept4 accept4
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
|
||||
# include <sanitizer/linux_syscall_hooks.h>
|
||||
#endif
|
||||
|
||||
static int uv__run_pending(uv_loop_t* loop);
|
||||
|
||||
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
|
||||
STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
|
||||
STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) ==
|
||||
STATIC_ASSERT(sizeof(((uv_buf_t*) 0)->base) ==
|
||||
sizeof(((struct iovec*) 0)->iov_base));
|
||||
STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) ==
|
||||
STATIC_ASSERT(sizeof(((uv_buf_t*) 0)->len) ==
|
||||
sizeof(((struct iovec*) 0)->iov_len));
|
||||
STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base));
|
||||
STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
|
||||
@@ -172,9 +173,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
||||
|
||||
case UV_SIGNAL:
|
||||
uv__signal_close((uv_signal_t*) handle);
|
||||
/* Signal handles may not be closed immediately. The signal code will
|
||||
* itself close uv__make_close_pending whenever appropriate. */
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
@@ -222,15 +221,23 @@ int uv__getiovmax(void) {
|
||||
#if defined(IOV_MAX)
|
||||
return IOV_MAX;
|
||||
#elif defined(_SC_IOV_MAX)
|
||||
static int iovmax = -1;
|
||||
if (iovmax == -1) {
|
||||
iovmax = sysconf(_SC_IOV_MAX);
|
||||
/* On some embedded devices (arm-linux-uclibc based ip camera),
|
||||
* sysconf(_SC_IOV_MAX) can not get the correct value. The return
|
||||
* value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
|
||||
*/
|
||||
if (iovmax == -1) iovmax = 1;
|
||||
}
|
||||
static int iovmax_cached = -1;
|
||||
int iovmax;
|
||||
|
||||
iovmax = uv__load_relaxed(&iovmax_cached);
|
||||
if (iovmax != -1)
|
||||
return iovmax;
|
||||
|
||||
/* On some embedded devices (arm-linux-uclibc based ip camera),
|
||||
* sysconf(_SC_IOV_MAX) can not get the correct value. The return
|
||||
* value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
|
||||
*/
|
||||
iovmax = sysconf(_SC_IOV_MAX);
|
||||
if (iovmax == -1)
|
||||
iovmax = 1;
|
||||
|
||||
uv__store_relaxed(&iovmax_cached, iovmax);
|
||||
|
||||
return iovmax;
|
||||
#else
|
||||
return 1024;
|
||||
@@ -239,6 +246,8 @@ int uv__getiovmax(void) {
|
||||
|
||||
|
||||
static void uv__finish_close(uv_handle_t* handle) {
|
||||
uv_signal_t* sh;
|
||||
|
||||
/* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
|
||||
* possible for it to be active in the sense that uv__is_active() returns
|
||||
* true.
|
||||
@@ -261,7 +270,20 @@ static void uv__finish_close(uv_handle_t* handle) {
|
||||
case UV_FS_EVENT:
|
||||
case UV_FS_POLL:
|
||||
case UV_POLL:
|
||||
break;
|
||||
|
||||
case UV_SIGNAL:
|
||||
/* If there are any caught signals "trapped" in the signal pipe,
|
||||
* we can't call the close callback yet. Reinserting the handle
|
||||
* into the closing queue makes the event loop spin but that's
|
||||
* okay because we only need to deliver the pending events.
|
||||
*/
|
||||
sh = (uv_signal_t*) handle;
|
||||
if (sh->caught_signals > sh->dispatched_signals) {
|
||||
handle->flags ^= UV_HANDLE_CLOSED;
|
||||
uv__make_close_pending(handle); /* Back into the queue. */
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
@@ -313,35 +335,36 @@ int uv_backend_fd(const uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
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 (!QUEUE_EMPTY(&loop->idle_handles))
|
||||
return 0;
|
||||
|
||||
if (!QUEUE_EMPTY(&loop->pending_queue))
|
||||
return 0;
|
||||
|
||||
if (loop->closing_handles)
|
||||
return 0;
|
||||
|
||||
return uv__next_timeout(loop);
|
||||
}
|
||||
|
||||
|
||||
static int uv__loop_alive(const uv_loop_t* loop) {
|
||||
return uv__has_active_handles(loop) ||
|
||||
uv__has_active_reqs(loop) ||
|
||||
!QUEUE_EMPTY(&loop->pending_queue) ||
|
||||
loop->closing_handles != NULL;
|
||||
}
|
||||
|
||||
|
||||
static int uv__backend_timeout(const uv_loop_t* loop) {
|
||||
if (loop->stop_flag == 0 &&
|
||||
/* uv__loop_alive(loop) && */
|
||||
(uv__has_active_handles(loop) || uv__has_active_reqs(loop)) &&
|
||||
QUEUE_EMPTY(&loop->pending_queue) &&
|
||||
QUEUE_EMPTY(&loop->idle_handles) &&
|
||||
loop->closing_handles == NULL)
|
||||
return uv__next_timeout(loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_backend_timeout(const uv_loop_t* loop) {
|
||||
if (QUEUE_EMPTY(&loop->watcher_queue))
|
||||
return uv__backend_timeout(loop);
|
||||
/* Need to call uv_run to update the backend fd state. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_loop_alive(const uv_loop_t* loop) {
|
||||
return uv__loop_alive(loop);
|
||||
return uv__loop_alive(loop);
|
||||
}
|
||||
|
||||
|
||||
@@ -363,9 +386,17 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
|
||||
|
||||
timeout = 0;
|
||||
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
|
||||
timeout = uv_backend_timeout(loop);
|
||||
timeout = uv__backend_timeout(loop);
|
||||
|
||||
uv__io_poll(loop, timeout);
|
||||
|
||||
/* Run one final update on the provider_idle_time in case uv__io_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__run_check(loop);
|
||||
uv__run_closing_handles(loop);
|
||||
|
||||
@@ -465,52 +496,32 @@ int uv__accept(int sockfd) {
|
||||
int peerfd;
|
||||
int err;
|
||||
|
||||
(void) &err;
|
||||
assert(sockfd >= 0);
|
||||
|
||||
while (1) {
|
||||
#if defined(__linux__) || \
|
||||
(defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
|
||||
defined(__NetBSD__)
|
||||
static int no_accept4;
|
||||
do
|
||||
#ifdef uv__accept4
|
||||
peerfd = uv__accept4(sockfd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
#else
|
||||
peerfd = accept(sockfd, NULL, NULL);
|
||||
#endif
|
||||
while (peerfd == -1 && errno == EINTR);
|
||||
|
||||
if (no_accept4)
|
||||
goto skip;
|
||||
if (peerfd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
peerfd = uv__accept4(sockfd,
|
||||
NULL,
|
||||
NULL,
|
||||
UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC);
|
||||
if (peerfd != -1)
|
||||
return peerfd;
|
||||
#ifndef uv__accept4
|
||||
err = uv__cloexec(peerfd, 1);
|
||||
if (err == 0)
|
||||
err = uv__nonblock(peerfd, 1);
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
|
||||
no_accept4 = 1;
|
||||
skip:
|
||||
if (err != 0) {
|
||||
uv__close(peerfd);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
peerfd = accept(sockfd, NULL, NULL);
|
||||
if (peerfd == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
err = uv__cloexec(peerfd, 1);
|
||||
if (err == 0)
|
||||
err = uv__nonblock(peerfd, 1);
|
||||
|
||||
if (err) {
|
||||
uv__close(peerfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return peerfd;
|
||||
}
|
||||
return peerfd;
|
||||
}
|
||||
|
||||
|
||||
@@ -537,13 +548,19 @@ int uv__close_nocancel(int fd) {
|
||||
#if defined(__APPLE__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
|
||||
#if defined(__LP64__)
|
||||
#if defined(__LP64__) || TARGET_OS_IPHONE
|
||||
return close$NOCANCEL(fd);
|
||||
#else
|
||||
return close$NOCANCEL$UNIX2003(fd);
|
||||
#endif
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(__linux__)
|
||||
#elif defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
|
||||
long rc;
|
||||
__sanitizer_syscall_pre_close(fd);
|
||||
rc = syscall(SYS_close, fd);
|
||||
__sanitizer_syscall_post_close(rc, fd);
|
||||
return rc;
|
||||
#elif defined(__linux__) && !defined(__SANITIZE_THREAD__)
|
||||
return syscall(SYS_close, fd);
|
||||
#else
|
||||
return close(fd);
|
||||
@@ -578,7 +595,7 @@ int uv__close(int fd) {
|
||||
return uv__close_nocheckstdio(fd);
|
||||
}
|
||||
|
||||
|
||||
#if UV__NONBLOCK_IS_IOCTL
|
||||
int uv__nonblock_ioctl(int fd, int set) {
|
||||
int r;
|
||||
|
||||
@@ -591,21 +608,6 @@ int uv__nonblock_ioctl(int fd, int set) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__HAIKU__)
|
||||
int uv__cloexec_ioctl(int fd, int set) {
|
||||
int r;
|
||||
|
||||
do
|
||||
r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -640,25 +642,13 @@ int uv__nonblock_fcntl(int fd, int set) {
|
||||
}
|
||||
|
||||
|
||||
int uv__cloexec_fcntl(int fd, int set) {
|
||||
int uv__cloexec(int fd, int set) {
|
||||
int flags;
|
||||
int r;
|
||||
|
||||
do
|
||||
r = fcntl(fd, F_GETFD);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Bail out now if already set/clear. */
|
||||
if (!!(r & FD_CLOEXEC) == !!set)
|
||||
return 0;
|
||||
|
||||
flags = 0;
|
||||
if (set)
|
||||
flags = r | FD_CLOEXEC;
|
||||
else
|
||||
flags = r & ~FD_CLOEXEC;
|
||||
flags = FD_CLOEXEC;
|
||||
|
||||
do
|
||||
r = fcntl(fd, F_SETFD, flags);
|
||||
@@ -678,7 +668,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
||||
int* end;
|
||||
#if defined(__linux__)
|
||||
static int no_msg_cmsg_cloexec;
|
||||
if (no_msg_cmsg_cloexec == 0) {
|
||||
if (0 == uv__load_relaxed(&no_msg_cmsg_cloexec)) {
|
||||
rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
|
||||
if (rc != -1)
|
||||
return rc;
|
||||
@@ -687,7 +677,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
||||
rc = recvmsg(fd, msg, flags);
|
||||
if (rc == -1)
|
||||
return UV__ERR(errno);
|
||||
no_msg_cmsg_cloexec = 1;
|
||||
uv__store_relaxed(&no_msg_cmsg_cloexec, 1);
|
||||
} else {
|
||||
rc = recvmsg(fd, msg, flags);
|
||||
}
|
||||
@@ -852,7 +842,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) {
|
||||
|
||||
nwatchers = next_power_of_two(len + 2) - 2;
|
||||
watchers = (void**)
|
||||
uv__realloc(loop->watchers, (nwatchers + 2) * sizeof(loop->watchers[0]));
|
||||
uv__reallocf(loop->watchers, (nwatchers + 2) * sizeof(loop->watchers[0]));
|
||||
|
||||
if (watchers == NULL)
|
||||
abort();
|
||||
@@ -929,13 +919,12 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
if (w->pevents == 0) {
|
||||
QUEUE_REMOVE(&w->watcher_queue);
|
||||
QUEUE_INIT(&w->watcher_queue);
|
||||
w->events = 0;
|
||||
|
||||
if (loop->watchers[w->fd] != NULL) {
|
||||
assert(loop->watchers[w->fd] == w);
|
||||
if (w == loop->watchers[w->fd]) {
|
||||
assert(loop->nfds > 0);
|
||||
loop->watchers[w->fd] = NULL;
|
||||
loop->nfds--;
|
||||
w->events = 0;
|
||||
}
|
||||
}
|
||||
else if (QUEUE_EMPTY(&w->watcher_queue))
|
||||
@@ -1005,24 +994,17 @@ int uv_getrusage(uv_rusage_t* rusage) {
|
||||
|
||||
|
||||
int uv__open_cloexec(const char* path, int flags) {
|
||||
int err;
|
||||
#if defined(O_CLOEXEC)
|
||||
int fd;
|
||||
|
||||
#if defined(UV__O_CLOEXEC)
|
||||
static int no_cloexec;
|
||||
fd = open(path, flags | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (!no_cloexec) {
|
||||
fd = open(path, flags | UV__O_CLOEXEC);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != EINVAL)
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* O_CLOEXEC not supported. */
|
||||
no_cloexec = 1;
|
||||
}
|
||||
#endif
|
||||
return fd;
|
||||
#else /* O_CLOEXEC */
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
fd = open(path, flags);
|
||||
if (fd == -1)
|
||||
@@ -1035,58 +1017,61 @@ int uv__open_cloexec(const char* path, int flags) {
|
||||
}
|
||||
|
||||
return fd;
|
||||
#endif /* O_CLOEXEC */
|
||||
}
|
||||
|
||||
|
||||
int uv__slurp(const char* filename, char* buf, size_t len) {
|
||||
ssize_t n;
|
||||
int fd;
|
||||
|
||||
assert(len > 0);
|
||||
|
||||
fd = uv__open_cloexec(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
do
|
||||
n = read(fd, buf, len - 1);
|
||||
while (n == -1 && errno == EINTR);
|
||||
|
||||
if (uv__close_nocheckstdio(fd))
|
||||
abort();
|
||||
|
||||
if (n < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
buf[n] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__dup2_cloexec(int oldfd, int newfd) {
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__)
|
||||
int r;
|
||||
#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
|
||||
|
||||
r = dup3(oldfd, newfd, O_CLOEXEC);
|
||||
if (r == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return r;
|
||||
#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
|
||||
r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
|
||||
if (r != -1)
|
||||
return r;
|
||||
if (errno != EINVAL)
|
||||
return UV__ERR(errno);
|
||||
/* Fall through. */
|
||||
#elif defined(__linux__)
|
||||
static int no_dup3;
|
||||
if (!no_dup3) {
|
||||
do
|
||||
r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
|
||||
while (r == -1 && errno == EBUSY);
|
||||
if (r != -1)
|
||||
return r;
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
/* Fall through. */
|
||||
no_dup3 = 1;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
int err;
|
||||
do
|
||||
r = dup2(oldfd, newfd);
|
||||
#if defined(__linux__)
|
||||
while (r == -1 && errno == EBUSY);
|
||||
#else
|
||||
while (0); /* Never retry. */
|
||||
#endif
|
||||
int err;
|
||||
int r;
|
||||
|
||||
if (r == -1)
|
||||
return UV__ERR(errno);
|
||||
r = dup2(oldfd, newfd); /* Never retry. */
|
||||
if (r == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
err = uv__cloexec(newfd, 1);
|
||||
if (err) {
|
||||
uv__close(newfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return r;
|
||||
err = uv__cloexec(newfd, 1);
|
||||
if (err != 0) {
|
||||
uv__close(newfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1188,13 +1173,6 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
size_t shell_size;
|
||||
long initsize;
|
||||
int r;
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
|
||||
|
||||
getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
|
||||
if (getpwuid_r == NULL)
|
||||
return UV_ENOSYS;
|
||||
#endif
|
||||
|
||||
if (pwd == NULL)
|
||||
return UV_EINVAL;
|
||||
@@ -1216,7 +1194,9 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
if (buf == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
r = getpwuid_r(uid, &pw, buf, bufsize, &result);
|
||||
do
|
||||
r = getpwuid_r(uid, &pw, buf, bufsize, &result);
|
||||
while (r == EINTR);
|
||||
|
||||
if (r != ERANGE)
|
||||
break;
|
||||
@@ -1226,7 +1206,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
|
||||
if (r != 0) {
|
||||
uv__free(buf);
|
||||
return -r;
|
||||
return UV__ERR(r);
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
@@ -1293,6 +1273,62 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
}
|
||||
|
||||
|
||||
int uv_os_environ(uv_env_item_t** envitems, int* count) {
|
||||
int i, j, cnt;
|
||||
uv_env_item_t* envitem;
|
||||
|
||||
*envitems = NULL;
|
||||
*count = 0;
|
||||
|
||||
for (i = 0; environ[i] != NULL; i++);
|
||||
|
||||
*envitems = (uv_env_item_s*)uv__calloc(i, sizeof(**envitems));
|
||||
|
||||
if (*envitems == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
for (j = 0, cnt = 0; j < i; j++) {
|
||||
char* buf;
|
||||
char* ptr;
|
||||
|
||||
if (environ[j] == NULL)
|
||||
break;
|
||||
|
||||
buf = uv__strdup(environ[j]);
|
||||
if (buf == NULL)
|
||||
goto fail;
|
||||
|
||||
ptr = strchr(buf, '=');
|
||||
if (ptr == NULL) {
|
||||
uv__free(buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
envitem = &(*envitems)[cnt];
|
||||
envitem->name = buf;
|
||||
envitem->value = ptr + 1;
|
||||
|
||||
cnt++;
|
||||
}
|
||||
|
||||
*count = cnt;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for (i = 0; i < cnt; i++) {
|
||||
envitem = &(*envitems)[cnt];
|
||||
uv__free(envitem->name);
|
||||
}
|
||||
uv__free(*envitems);
|
||||
|
||||
*envitems = NULL;
|
||||
*count = 0;
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
char* var;
|
||||
size_t len;
|
||||
@@ -1507,3 +1543,126 @@ int uv_gettimeofday(uv_timeval64_t* tv) {
|
||||
tv->tv_usec = (int32_t) time.tv_usec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv_sleep(unsigned int msec) {
|
||||
struct timespec timeout;
|
||||
int rc;
|
||||
|
||||
timeout.tv_sec = msec / 1000;
|
||||
timeout.tv_nsec = (msec % 1000) * 1000 * 1000;
|
||||
|
||||
do
|
||||
rc = nanosleep(&timeout, &timeout);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
int uv__search_path(const char* prog, char* buf, size_t* buflen) {
|
||||
char abspath[UV__PATH_MAX];
|
||||
size_t abspath_size;
|
||||
char trypath[UV__PATH_MAX];
|
||||
char* cloned_path;
|
||||
char* path_env;
|
||||
char* token;
|
||||
|
||||
if (buf == NULL || buflen == NULL || *buflen == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
/*
|
||||
* Possibilities for prog:
|
||||
* i) an absolute path such as: /home/user/myprojects/nodejs/node
|
||||
* ii) a relative path such as: ./node or ../myprojects/nodejs/node
|
||||
* iii) a bare filename such as "node", after exporting PATH variable
|
||||
* to its location.
|
||||
*/
|
||||
|
||||
/* Case i) and ii) absolute or relative paths */
|
||||
if (strchr(prog, '/') != NULL) {
|
||||
if (realpath(prog, abspath) != abspath)
|
||||
return UV__ERR(errno);
|
||||
|
||||
abspath_size = strlen(abspath);
|
||||
|
||||
*buflen -= 1;
|
||||
if (*buflen > abspath_size)
|
||||
*buflen = abspath_size;
|
||||
|
||||
memcpy(buf, abspath, *buflen);
|
||||
buf[*buflen] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Case iii). Search PATH environment variable */
|
||||
cloned_path = NULL;
|
||||
token = NULL;
|
||||
path_env = getenv("PATH");
|
||||
|
||||
if (path_env == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
cloned_path = uv__strdup(path_env);
|
||||
if (cloned_path == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
token = strtok(cloned_path, ":");
|
||||
while (token != NULL) {
|
||||
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog);
|
||||
if (realpath(trypath, abspath) == abspath) {
|
||||
/* Check the match is executable */
|
||||
if (access(abspath, X_OK) == 0) {
|
||||
abspath_size = strlen(abspath);
|
||||
|
||||
*buflen -= 1;
|
||||
if (*buflen > abspath_size)
|
||||
*buflen = abspath_size;
|
||||
|
||||
memcpy(buf, abspath, *buflen);
|
||||
buf[*buflen] = '\0';
|
||||
|
||||
uv__free(cloned_path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
token = strtok(NULL, ":");
|
||||
}
|
||||
uv__free(cloned_path);
|
||||
|
||||
/* Out of tokens (path entries), and no match found */
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
|
||||
unsigned int uv_available_parallelism(void) {
|
||||
#ifdef __linux__
|
||||
cpu_set_t set;
|
||||
long rc;
|
||||
|
||||
memset(&set, 0, sizeof(set));
|
||||
|
||||
/* sysconf(_SC_NPROCESSORS_ONLN) in musl calls sched_getaffinity() but in
|
||||
* glibc it's... complicated... so for consistency try sched_getaffinity()
|
||||
* before falling back to sysconf(_SC_NPROCESSORS_ONLN).
|
||||
*/
|
||||
if (0 == sched_getaffinity(0, sizeof(set), &set))
|
||||
rc = CPU_COUNT(&set);
|
||||
else
|
||||
rc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
|
||||
return (unsigned) rc;
|
||||
#elif defined(__MVS__)
|
||||
return 1; /* TODO(bnoordhuis) Read from CSD_NUMBER_ONLINE_CPUS? */
|
||||
#else /* __linux__ */
|
||||
long rc;
|
||||
|
||||
rc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
|
||||
return (unsigned) rc;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
@@ -48,11 +48,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
(void)cpu_infos;
|
||||
(void)count;
|
||||
}
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
@@ -23,66 +23,61 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
# include <CoreFoundation/CoreFoundation.h>
|
||||
# include <ApplicationServices/ApplicationServices.h>
|
||||
#include "darwin-stub.h"
|
||||
#endif
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
static int uv__pthread_setname_np(const char* name) {
|
||||
char namebuf[64]; /* MAXTHREADNAMESIZE */
|
||||
int err;
|
||||
|
||||
static int (*dynamic_pthread_setname_np)(const char* name);
|
||||
#if !TARGET_OS_IPHONE
|
||||
static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||
const char*,
|
||||
CFStringEncoding);
|
||||
static CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
|
||||
static void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
|
||||
static void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
|
||||
static CFTypeRef (*pLSGetCurrentApplicationASN)(void);
|
||||
static OSStatus (*pLSSetApplicationInformationItem)(int,
|
||||
CFTypeRef,
|
||||
CFStringRef,
|
||||
CFStringRef,
|
||||
CFDictionaryRef*);
|
||||
static void* application_services_handle;
|
||||
static void* core_foundation_handle;
|
||||
static CFBundleRef launch_services_bundle;
|
||||
static CFStringRef* display_name_key;
|
||||
static CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
|
||||
static CFBundleRef (*pCFBundleGetMainBundle)(void);
|
||||
static CFBundleRef hi_services_bundle;
|
||||
static OSStatus (*pSetApplicationIsDaemon)(int);
|
||||
static CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
|
||||
static void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
|
||||
void*);
|
||||
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||
|
||||
err = pthread_setname_np(namebuf);
|
||||
if (err)
|
||||
return UV__ERR(err);
|
||||
|
||||
UV_DESTRUCTOR(static void uv__set_process_title_platform_fini(void)) {
|
||||
if (core_foundation_handle != NULL) {
|
||||
dlclose(core_foundation_handle);
|
||||
core_foundation_handle = NULL;
|
||||
}
|
||||
|
||||
if (application_services_handle != NULL) {
|
||||
dlclose(application_services_handle);
|
||||
application_services_handle = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
|
||||
|
||||
void uv__set_process_title_platform_init(void) {
|
||||
/* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
|
||||
*(void **)(&dynamic_pthread_setname_np) =
|
||||
dlsym(RTLD_DEFAULT, "pthread_setname_np");
|
||||
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;
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
err = UV_ENOENT;
|
||||
application_services_handle = dlopen("/System/Library/Frameworks/"
|
||||
"ApplicationServices.framework/"
|
||||
"Versions/A/ApplicationServices",
|
||||
@@ -111,6 +106,8 @@ void uv__set_process_title_platform_init(void) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
launch_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
|
||||
|
||||
@@ -142,58 +139,55 @@ void uv__set_process_title_platform_init(void) {
|
||||
"CFBundleGetInfoDictionary");
|
||||
*(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
|
||||
"CFBundleGetMainBundle");
|
||||
|
||||
if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
|
||||
goto out;
|
||||
|
||||
/* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
|
||||
hi_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
|
||||
|
||||
if (hi_services_bundle == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName(
|
||||
hi_services_bundle,
|
||||
S("SetApplicationIsDaemon"));
|
||||
*(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSApplicationCheckIn"));
|
||||
|
||||
if (pLSApplicationCheckIn == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
|
||||
pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
|
||||
|
||||
if (pSetApplicationIsDaemon == NULL ||
|
||||
pLSApplicationCheckIn == NULL ||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
return;
|
||||
uv__pthread_setname_np(title); /* Don't care if it fails. */
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
uv__set_process_title_platform_fini();
|
||||
if (core_foundation_handle != NULL)
|
||||
dlclose(core_foundation_handle);
|
||||
|
||||
if (application_services_handle != NULL)
|
||||
dlclose(application_services_handle);
|
||||
|
||||
return err;
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
}
|
||||
|
||||
|
||||
void uv__set_process_title(const char* title) {
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (core_foundation_handle != NULL && pSetApplicationIsDaemon(1) != noErr) {
|
||||
CFTypeRef asn;
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
|
||||
pLSApplicationCheckIn(/* Magic value */ -2,
|
||||
pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
|
||||
asn = pLSGetCurrentApplicationASN();
|
||||
pLSSetApplicationInformationItem(/* Magic value */ -2, asn,
|
||||
*display_name_key, S(title), NULL);
|
||||
}
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
|
||||
if (dynamic_pthread_setname_np != NULL) {
|
||||
char namebuf[64]; /* MAXTHREADNAMESIZE */
|
||||
uv__strscpy(namebuf, title, sizeof(namebuf));
|
||||
dynamic_pthread_setname_np(namebuf);
|
||||
}
|
||||
}
|
||||
|
||||
113
wpinet/src/main/native/thirdparty/libuv/src/unix/darwin-stub.h
vendored
Normal file
113
wpinet/src/main/native/thirdparty/libuv/src/unix/darwin-stub.h
vendored
Normal 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_ */
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
@@ -32,6 +33,13 @@
|
||||
#include <sys/sysctl.h>
|
||||
#include <unistd.h> /* sysconf */
|
||||
|
||||
#include "darwin-stub.h"
|
||||
|
||||
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;
|
||||
@@ -48,15 +56,19 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
static mach_timebase_info_data_t info;
|
||||
|
||||
if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
|
||||
ACCESS_ONCE(uint32_t, info.denom) == 0) &&
|
||||
mach_timebase_info(&info) != KERN_SUCCESS)
|
||||
static void uv__hrtime_init_once(void) {
|
||||
if (KERN_SUCCESS != mach_timebase_info(&timebase))
|
||||
abort();
|
||||
|
||||
return mach_absolute_time() * info.numer / info.denom;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +122,7 @@ uint64_t uv_get_total_memory(void) {
|
||||
int which[] = {CTL_HW, HW_MEMSIZE};
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
@@ -127,7 +139,7 @@ void uv_loadavg(double avg[3]) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
|
||||
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;
|
||||
@@ -162,7 +174,7 @@ int uv_uptime(double* uptime) {
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
now = time(NULL);
|
||||
@@ -171,17 +183,163 @@ int uv_uptime(double* uptime) {
|
||||
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/"
|
||||
"CoreFoundation",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/"
|
||||
"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)
|
||||
|
||||
// Braces ensure goto doesn't jump into device_type_str's and
|
||||
// clock_frequency_str's lifetimes after their initialization
|
||||
{
|
||||
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) {
|
||||
const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref);
|
||||
CFIndex len = pCFDataGetLength(freq_ref);
|
||||
if (len == 8)
|
||||
memcpy(speed, freq_ref_ptr, 8);
|
||||
else if (len == 4) {
|
||||
uint32_t v;
|
||||
memcpy(&v, freq_ref_ptr, 4);
|
||||
*speed = v;
|
||||
} else {
|
||||
*speed = 0;
|
||||
}
|
||||
|
||||
pCFRelease(freq_ref);
|
||||
pCFRelease(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pCFRelease(data);
|
||||
}
|
||||
|
||||
service = pIOIteratorNext(it);
|
||||
}
|
||||
|
||||
pIOObjectRelease(it);
|
||||
|
||||
err = 0;
|
||||
|
||||
if (device_type_str != NULL)
|
||||
pCFRelease(device_type_str);
|
||||
if (clock_frequency_str != NULL)
|
||||
pCFRelease(clock_frequency_str);
|
||||
}
|
||||
|
||||
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];
|
||||
uint64_t cpuspeed;
|
||||
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) &&
|
||||
@@ -189,9 +347,9 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctlbyname("hw.cpufrequency", &cpuspeed, &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,
|
||||
@@ -223,14 +381,3 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ void uv_dlclose(uv_lib_t* lib) {
|
||||
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);
|
||||
return *ptr ? 0 : uv__dlerror(lib);
|
||||
}
|
||||
|
||||
|
||||
|
||||
422
wpinet/src/main/native/thirdparty/libuv/src/unix/epoll.cpp
vendored
Normal file
422
wpinet/src/main/native/thirdparty/libuv/src/unix/epoll.cpp
vendored
Normal file
@@ -0,0 +1,422 @@
|
||||
/* 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 <sys/epoll.h>
|
||||
|
||||
int uv__epoll_init(uv_loop_t* loop) {
|
||||
int fd;
|
||||
fd = epoll_create1(O_CLOEXEC);
|
||||
|
||||
/* epoll_create1() can fail either because it's not implemented (old kernel)
|
||||
* or because it doesn't understand the O_CLOEXEC flag.
|
||||
*/
|
||||
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
|
||||
fd = epoll_create(256);
|
||||
|
||||
if (fd != -1)
|
||||
uv__cloexec(fd, 1);
|
||||
}
|
||||
|
||||
loop->backend_fd = fd;
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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 (events[i].data.fd == fd)
|
||||
events[i].data.fd = -1;
|
||||
|
||||
/* Remove the file descriptor from the epoll.
|
||||
* This avoids a problem where the same file description remains open
|
||||
* in another process, causing repeated junk epoll events.
|
||||
*
|
||||
* We pass in a dummy epoll_event, to work around a bug in old kernels.
|
||||
*/
|
||||
if (loop->backend_fd >= 0) {
|
||||
/* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
|
||||
* has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
|
||||
*/
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct epoll_event e;
|
||||
int rc;
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
e.events = POLLIN;
|
||||
e.data.fd = -1;
|
||||
|
||||
rc = 0;
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
|
||||
if (errno != EEXIST)
|
||||
rc = UV__ERR(errno);
|
||||
|
||||
if (rc == 0)
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
/* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
|
||||
* effectively infinite on 32 bits architectures. To avoid blocking
|
||||
* indefinitely, we cap the timeout and poll again if necessary.
|
||||
*
|
||||
* Note that "30 minutes" is a simplification because it depends on
|
||||
* the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
|
||||
* that being the largest value I have seen in the wild (and only once.)
|
||||
*/
|
||||
static const int max_safe_timeout = 1789569;
|
||||
static int no_epoll_pwait_cached;
|
||||
static int no_epoll_wait_cached;
|
||||
int no_epoll_pwait;
|
||||
int no_epoll_wait;
|
||||
struct epoll_event events[1024];
|
||||
struct epoll_event* pe;
|
||||
struct epoll_event e;
|
||||
int real_timeout;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t sigset;
|
||||
uint64_t sigmask;
|
||||
uint64_t base;
|
||||
int have_signals;
|
||||
int nevents;
|
||||
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;
|
||||
}
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
|
||||
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);
|
||||
|
||||
e.events = w->pevents;
|
||||
e.data.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->backend_fd, 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->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
|
||||
abort();
|
||||
}
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
sigmask = 0;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGPROF);
|
||||
sigmask |= 1 << (SIGPROF - 1);
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
base = loop->time;
|
||||
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
||||
real_timeout = timeout;
|
||||
|
||||
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
|
||||
reset_timeout = 1;
|
||||
user_timeout = timeout;
|
||||
timeout = 0;
|
||||
} else {
|
||||
reset_timeout = 0;
|
||||
user_timeout = 0;
|
||||
}
|
||||
|
||||
/* You could argue there is a dependency between these two but
|
||||
* ultimately we don't care about their ordering with respect
|
||||
* to one another. Worst case, we make a few system calls that
|
||||
* could have been avoided because another thread already knows
|
||||
* they fail with ENOSYS. Hardly the end of the world.
|
||||
*/
|
||||
no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached);
|
||||
no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached);
|
||||
|
||||
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);
|
||||
|
||||
/* See the comment for max_safe_timeout for an explanation of why
|
||||
* this is necessary. Executive summary: kernel bug workaround.
|
||||
*/
|
||||
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
|
||||
timeout = max_safe_timeout;
|
||||
|
||||
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
|
||||
abort();
|
||||
|
||||
if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
|
||||
nfds = epoll_pwait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout,
|
||||
&sigset);
|
||||
if (nfds == -1 && errno == ENOSYS) {
|
||||
uv__store_relaxed(&no_epoll_pwait_cached, 1);
|
||||
no_epoll_pwait = 1;
|
||||
}
|
||||
} else {
|
||||
nfds = epoll_wait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout);
|
||||
if (nfds == -1 && errno == ENOSYS) {
|
||||
uv__store_relaxed(&no_epoll_wait_cached, 1);
|
||||
no_epoll_wait = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||
if (pthread_sigmask(SIG_UNBLOCK, &sigset, 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) {
|
||||
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 == ENOSYS) {
|
||||
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
|
||||
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
have_signals = 0;
|
||||
nevents = 0;
|
||||
|
||||
{
|
||||
/* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */
|
||||
union {
|
||||
struct epoll_event* events;
|
||||
uv__io_t* watchers;
|
||||
} x;
|
||||
|
||||
x.events = events;
|
||||
assert(loop->watchers != NULL);
|
||||
loop->watchers[loop->nwatchers] = x.watchers;
|
||||
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
||||
}
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
pe = events + i;
|
||||
fd = pe->data.fd;
|
||||
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert((unsigned) fd < loop->nwatchers);
|
||||
|
||||
w = (uv__io_t*)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->backend_fd, 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;
|
||||
|
||||
/* Work around an epoll quirk where it sometimes reports just the
|
||||
* EPOLLERR or EPOLLHUP event. In order to force the event loop to
|
||||
* move forward, we merge in the read/write events that the watcher
|
||||
* is interested in; uv__read() and uv__write() will then deal with
|
||||
* the error or hangup in the usual fashion.
|
||||
*
|
||||
* Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
|
||||
* reads the available data, calls uv_read_stop(), then sometime later
|
||||
* calls uv_read_start() again. By then, libuv has forgotten about the
|
||||
* hangup and the kernel won't report EPOLLIN again because there's
|
||||
* nothing left to read. If anything, libuv is to blame here. The
|
||||
* current hack is just a quick bandaid; to properly fix it, libuv
|
||||
* needs to remember the error/hangup event. We should get that for
|
||||
* free when we switch over to edge-triggered I/O.
|
||||
*/
|
||||
if (pe->events == POLLERR || pe->events == POLLHUP)
|
||||
pe->events |=
|
||||
w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
|
||||
|
||||
if (pe->events != 0) {
|
||||
/* 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->events);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
real_timeout -= (loop->time - base);
|
||||
if (real_timeout <= 0)
|
||||
return;
|
||||
|
||||
timeout = real_timeout;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,31 +56,6 @@ int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef __DragonFly__
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
char abspath[PATH_MAX * 2 + 1];
|
||||
ssize_t abspath_size;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
|
||||
if (abspath_size < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
assert(abspath_size > 0);
|
||||
*size -= 1;
|
||||
|
||||
if (*size > abspath_size)
|
||||
*size = abspath_size;
|
||||
|
||||
memcpy(buffer, abspath, *size);
|
||||
buffer[*size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
char abspath[PATH_MAX * 2 + 1];
|
||||
int mib[4];
|
||||
@@ -95,7 +70,7 @@ int uv_exepath(char* buffer, size_t* size) {
|
||||
mib[3] = -1;
|
||||
|
||||
abspath_size = sizeof abspath;
|
||||
if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0))
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), abspath, &abspath_size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
assert(abspath_size > 0);
|
||||
@@ -110,7 +85,6 @@ int uv_exepath(char* buffer, size_t* size) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
int freecount;
|
||||
@@ -130,7 +104,7 @@ uint64_t uv_get_total_memory(void) {
|
||||
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
@@ -147,7 +121,7 @@ void uv_loadavg(double avg[3]) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
|
||||
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;
|
||||
@@ -168,7 +142,7 @@ int uv_resident_set_memory(size_t* rss) {
|
||||
|
||||
kinfo_size = sizeof(kinfo);
|
||||
|
||||
if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0))
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &kinfo_size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
page_size = getpagesize();
|
||||
@@ -290,12 +264,41 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
|
||||
#if __FreeBSD__ >= 11 && !defined(__DragonFly__)
|
||||
return sendmmsg(fd,
|
||||
(struct mmsghdr*) mmsg,
|
||||
vlen,
|
||||
0 /* flags */);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
|
||||
#if __FreeBSD__ >= 11 && !defined(__DragonFly__)
|
||||
return recvmmsg(fd,
|
||||
(struct mmsghdr*) mmsg,
|
||||
vlen,
|
||||
0 /* flags */,
|
||||
NULL /* timeout */);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t
|
||||
uv__fs_copy_file_range(int fd_in,
|
||||
off_t* off_in,
|
||||
int fd_out,
|
||||
off_t* off_out,
|
||||
size_t len,
|
||||
unsigned int flags)
|
||||
{
|
||||
#if __FreeBSD__ >= 13 && !defined(__DragonFly__)
|
||||
return copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -55,8 +56,13 @@
|
||||
# define HAVE_PREADV 0
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
# include "sys/utsname.h"
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__sun)
|
||||
# include <sys/sendfile.h>
|
||||
# include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -70,6 +76,24 @@
|
||||
# include <utime.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include <sys/param.h>
|
||||
# include <sys/mount.h>
|
||||
#elif defined(__sun) || \
|
||||
defined(__MVS__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__HAIKU__) || \
|
||||
defined(__QNX__)
|
||||
# include <sys/statvfs.h>
|
||||
#else
|
||||
# include <sys/statfs.h>
|
||||
#endif
|
||||
|
||||
#if defined(_AIX) && _XOPEN_SOURCE <= 600
|
||||
extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
|
||||
#endif
|
||||
@@ -190,18 +214,44 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = time;
|
||||
ts.tv_nsec = (time - ts.tv_sec) * 1e9;
|
||||
|
||||
/* TODO(bnoordhuis) Remove this. utimesat() has nanosecond resolution but we
|
||||
* stick to microsecond resolution for the sake of consistency with other
|
||||
* platforms. I'm the original author of this compatibility hack but I'm
|
||||
* less convinced it's useful nowadays.
|
||||
*/
|
||||
ts.tv_nsec -= ts.tv_nsec % 1000;
|
||||
|
||||
if (ts.tv_nsec < 0) {
|
||||
ts.tv_nsec += 1e9;
|
||||
ts.tv_sec -= 1;
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = time;
|
||||
tv.tv_usec = (time - tv.tv_sec) * 1e6;
|
||||
if (tv.tv_usec < 0) {
|
||||
tv.tv_usec += 1e6;
|
||||
tv.tv_sec -= 1;
|
||||
}
|
||||
return tv;
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_futime(uv_fs_t* req) {
|
||||
#if defined(__linux__) \
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__HAIKU__)
|
||||
/* utimesat() has nanosecond resolution but we stick to microseconds
|
||||
* for the sake of consistency with other platforms.
|
||||
*/
|
||||
|| defined(__HAIKU__) \
|
||||
|| defined(__GNU__)
|
||||
struct timespec ts[2];
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
ts[0] = uv__fs_to_timespec(req->atime);
|
||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||
return futimens(req->file, ts);
|
||||
#elif defined(__APPLE__) \
|
||||
|| defined(__DragonFly__) \
|
||||
@@ -211,10 +261,8 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
|
||||
|| defined(__OpenBSD__) \
|
||||
|| defined(__sun)
|
||||
struct timeval tv[2];
|
||||
tv[0].tv_sec = req->atime;
|
||||
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
|
||||
tv[1].tv_sec = req->mtime;
|
||||
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
|
||||
tv[0] = uv__fs_to_timeval(req->atime);
|
||||
tv[1] = uv__fs_to_timeval(req->mtime);
|
||||
# if defined(__sun)
|
||||
return futimesat(req->file, NULL, tv);
|
||||
# else
|
||||
@@ -240,21 +288,101 @@ static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_open(uv_fs_t* req) {
|
||||
static int no_cloexec_support;
|
||||
int r;
|
||||
static int (*uv__mkostemp)(char*, int);
|
||||
|
||||
/* Try O_CLOEXEC before entering locks */
|
||||
if (no_cloexec_support == 0) {
|
||||
|
||||
static void uv__mkostemp_initonce(void) {
|
||||
/* z/os doesn't have RTLD_DEFAULT but that's okay
|
||||
* because it doesn't have mkostemp(O_CLOEXEC) either.
|
||||
*/
|
||||
#ifdef RTLD_DEFAULT
|
||||
uv__mkostemp = (int (*)(char*, int)) dlsym(RTLD_DEFAULT, "mkostemp");
|
||||
|
||||
/* We don't care about errors, but we do want to clean them up.
|
||||
* If there has been no error, then dlerror() will just return
|
||||
* NULL.
|
||||
*/
|
||||
dlerror();
|
||||
#endif /* RTLD_DEFAULT */
|
||||
}
|
||||
|
||||
|
||||
static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
int r;
|
||||
#ifdef O_CLOEXEC
|
||||
r = open(req->path, req->flags | O_CLOEXEC, req->mode);
|
||||
static int no_cloexec_support;
|
||||
#endif
|
||||
static const char pattern[] = "XXXXXX";
|
||||
static const size_t pattern_size = sizeof(pattern) - 1;
|
||||
char* path;
|
||||
size_t path_length;
|
||||
|
||||
path = (char*) req->path;
|
||||
path_length = strlen(path);
|
||||
|
||||
/* EINVAL can be returned for 2 reasons:
|
||||
1. The template's last 6 characters were not XXXXXX
|
||||
2. open() didn't support O_CLOEXEC
|
||||
We want to avoid going to the fallback path in case
|
||||
of 1, so it's manually checked before. */
|
||||
if (path_length < pattern_size ||
|
||||
strcmp(path + path_length - pattern_size, pattern)) {
|
||||
errno = EINVAL;
|
||||
r = -1;
|
||||
goto clobber;
|
||||
}
|
||||
|
||||
uv_once(&once, uv__mkostemp_initonce);
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
if (uv__load_relaxed(&no_cloexec_support) == 0 && uv__mkostemp != NULL) {
|
||||
r = uv__mkostemp(path, O_CLOEXEC);
|
||||
|
||||
if (r >= 0)
|
||||
return r;
|
||||
|
||||
/* If mkostemp() returns EINVAL, it means the kernel doesn't
|
||||
support O_CLOEXEC, so we just fallback to mkstemp() below. */
|
||||
if (errno != EINVAL)
|
||||
return r;
|
||||
no_cloexec_support = 1;
|
||||
#endif /* O_CLOEXEC */
|
||||
goto clobber;
|
||||
|
||||
/* We set the static variable so that next calls don't even
|
||||
try to use mkostemp. */
|
||||
uv__store_relaxed(&no_cloexec_support, 1);
|
||||
}
|
||||
#endif /* O_CLOEXEC */
|
||||
|
||||
if (req->cb != NULL)
|
||||
uv_rwlock_rdlock(&req->loop->cloexec_lock);
|
||||
|
||||
r = mkstemp(path);
|
||||
|
||||
/* In case of failure `uv__cloexec` will leave error in `errno`,
|
||||
* so it is enough to just set `r` to `-1`.
|
||||
*/
|
||||
if (r >= 0 && uv__cloexec(r, 1) != 0) {
|
||||
r = uv__close(r);
|
||||
if (r != 0)
|
||||
abort();
|
||||
r = -1;
|
||||
}
|
||||
|
||||
if (req->cb != NULL)
|
||||
uv_rwlock_rdunlock(&req->loop->cloexec_lock);
|
||||
|
||||
clobber:
|
||||
if (r < 0)
|
||||
path[0] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_open(uv_fs_t* req) {
|
||||
#ifdef O_CLOEXEC
|
||||
return open(req->path, req->flags | O_CLOEXEC, req->mode);
|
||||
#else /* O_CLOEXEC */
|
||||
int r;
|
||||
|
||||
if (req->cb != NULL)
|
||||
uv_rwlock_rdlock(&req->loop->cloexec_lock);
|
||||
@@ -275,9 +403,11 @@ static ssize_t uv__fs_open(uv_fs_t* req) {
|
||||
uv_rwlock_rdunlock(&req->loop->cloexec_lock);
|
||||
|
||||
return r;
|
||||
#endif /* O_CLOEXEC */
|
||||
}
|
||||
|
||||
|
||||
#if !HAVE_PREADV
|
||||
static ssize_t uv__fs_preadv(uv_file fd,
|
||||
uv_buf_t* bufs,
|
||||
unsigned int nbufs,
|
||||
@@ -324,6 +454,7 @@ static ssize_t uv__fs_preadv(uv_file fd,
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
@@ -352,7 +483,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
|
||||
#else
|
||||
# if defined(__linux__)
|
||||
if (no_preadv) retry:
|
||||
if (uv__load_relaxed(&no_preadv)) retry:
|
||||
# endif
|
||||
{
|
||||
result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
|
||||
@@ -364,7 +495,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
req->nbufs,
|
||||
req->off);
|
||||
if (result == -1 && errno == ENOSYS) {
|
||||
no_preadv = 1;
|
||||
uv__store_relaxed(&no_preadv, 1);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
@@ -519,6 +650,49 @@ static int uv__fs_closedir(uv_fs_t* req) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uv__fs_statfs(uv_fs_t* req) {
|
||||
uv_statfs_t* stat_fs;
|
||||
#if defined(__sun) || \
|
||||
defined(__MVS__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__HAIKU__) || \
|
||||
defined(__QNX__)
|
||||
struct statvfs buf;
|
||||
|
||||
if (0 != statvfs(req->path, &buf))
|
||||
#else
|
||||
struct statfs buf;
|
||||
|
||||
if (0 != statfs(req->path, &buf))
|
||||
#endif /* defined(__sun) */
|
||||
return -1;
|
||||
|
||||
stat_fs = (uv_statfs_t*)uv__malloc(sizeof(*stat_fs));
|
||||
if (stat_fs == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__sun) || \
|
||||
defined(__MVS__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__HAIKU__) || \
|
||||
defined(__QNX__)
|
||||
stat_fs->f_type = 0; /* f_type is not supported. */
|
||||
#else
|
||||
stat_fs->f_type = buf.f_type;
|
||||
#endif
|
||||
stat_fs->f_bsize = buf.f_bsize;
|
||||
stat_fs->f_blocks = buf.f_blocks;
|
||||
stat_fs->f_bfree = buf.f_bfree;
|
||||
stat_fs->f_bavail = buf.f_bavail;
|
||||
stat_fs->f_files = buf.f_files;
|
||||
stat_fs->f_ffree = buf.f_ffree;
|
||||
req->ptr = stat_fs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_pathmax_size(const char* path) {
|
||||
ssize_t pathmax;
|
||||
|
||||
@@ -534,7 +708,6 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
ssize_t maxlen;
|
||||
ssize_t len;
|
||||
char* buf;
|
||||
char* newbuf;
|
||||
|
||||
#if defined(_POSIX_PATH_MAX) || defined(PATH_MAX)
|
||||
maxlen = uv__fs_pathmax_size(req->path);
|
||||
@@ -578,14 +751,10 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
|
||||
/* Uncommon case: resize to make room for the trailing nul byte. */
|
||||
if (len == maxlen) {
|
||||
newbuf = (char*)uv__realloc(buf, len + 1);
|
||||
buf = (char*)uv__reallocf(buf, len + 1);
|
||||
|
||||
if (newbuf == NULL) {
|
||||
uv__free(buf);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = newbuf;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
@@ -737,6 +906,115 @@ out:
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
static unsigned uv__kernel_version(void) {
|
||||
static unsigned cached_version;
|
||||
struct utsname u;
|
||||
unsigned version;
|
||||
unsigned major;
|
||||
unsigned minor;
|
||||
unsigned patch;
|
||||
|
||||
version = uv__load_relaxed(&cached_version);
|
||||
if (version != 0)
|
||||
return version;
|
||||
|
||||
if (-1 == uname(&u))
|
||||
return 0;
|
||||
|
||||
if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch))
|
||||
return 0;
|
||||
|
||||
version = major * 65536 + minor * 256 + patch;
|
||||
uv__store_relaxed(&cached_version, version);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
/* Pre-4.20 kernels have a bug where CephFS uses the RADOS copy-from command
|
||||
* in copy_file_range() when it shouldn't. There is no workaround except to
|
||||
* fall back to a regular copy.
|
||||
*/
|
||||
static int uv__is_buggy_cephfs(int fd) {
|
||||
struct statfs s;
|
||||
|
||||
if (-1 == fstatfs(fd, &s))
|
||||
return 0;
|
||||
|
||||
if (s.f_type != /* CephFS */ 0xC36400)
|
||||
return 0;
|
||||
|
||||
return uv__kernel_version() < /* 4.20.0 */ 0x041400;
|
||||
}
|
||||
|
||||
|
||||
static int uv__is_cifs_or_smb(int fd) {
|
||||
struct statfs s;
|
||||
|
||||
if (-1 == fstatfs(fd, &s))
|
||||
return 0;
|
||||
|
||||
switch ((unsigned) s.f_type) {
|
||||
case 0x0000517Bu: /* SMB */
|
||||
case 0xFE534D42u: /* SMB2 */
|
||||
case 0xFF534D42u: /* CIFS */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
|
||||
int out_fd, size_t len) {
|
||||
static int no_copy_file_range_support;
|
||||
ssize_t r;
|
||||
|
||||
if (uv__load_relaxed(&no_copy_file_range_support)) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = uv__fs_copy_file_range(in_fd, off, out_fd, NULL, len, 0);
|
||||
|
||||
if (r != -1)
|
||||
return r;
|
||||
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
/* Pre-4.20 kernels have a bug where CephFS uses the RADOS
|
||||
* copy-from command when it shouldn't.
|
||||
*/
|
||||
if (uv__is_buggy_cephfs(in_fd))
|
||||
errno = ENOSYS; /* Use fallback. */
|
||||
break;
|
||||
case ENOSYS:
|
||||
uv__store_relaxed(&no_copy_file_range_support, 1);
|
||||
break;
|
||||
case EPERM:
|
||||
/* It's been reported that CIFS spuriously fails.
|
||||
* Consider it a transient error.
|
||||
*/
|
||||
if (uv__is_cifs_or_smb(out_fd))
|
||||
errno = ENOSYS; /* Use fallback. */
|
||||
break;
|
||||
case ENOTSUP:
|
||||
case EXDEV:
|
||||
/* ENOTSUP - it could work on another file system type.
|
||||
* EXDEV - it will not work when in_fd and out_fd are not on the same
|
||||
* mounted filesystem (pre Linux 5.3)
|
||||
*/
|
||||
errno = ENOSYS; /* Use fallback. */
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
|
||||
static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
||||
int in_fd;
|
||||
int out_fd;
|
||||
@@ -748,9 +1026,20 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
||||
{
|
||||
off_t off;
|
||||
ssize_t r;
|
||||
size_t len;
|
||||
int try_sendfile;
|
||||
|
||||
off = req->off;
|
||||
r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len);
|
||||
len = req->bufsml[0].len;
|
||||
try_sendfile = 1;
|
||||
|
||||
#ifdef __linux__
|
||||
r = uv__fs_try_copy_file_range(in_fd, &off, out_fd, len);
|
||||
try_sendfile = (r == -1 && errno == ENOSYS);
|
||||
#endif
|
||||
|
||||
if (try_sendfile)
|
||||
r = sendfile(out_fd, in_fd, &off, len);
|
||||
|
||||
/* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
|
||||
* it still writes out data. Fortunately, we can detect it by checking if
|
||||
@@ -786,6 +1075,17 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
||||
*/
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#if defined(__FreeBSD__)
|
||||
off_t off;
|
||||
|
||||
off = req->off;
|
||||
r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0);
|
||||
if (r >= 0) {
|
||||
r = off - req->off;
|
||||
req->off = off;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
len = 0;
|
||||
r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
|
||||
#elif defined(__FreeBSD_kernel__)
|
||||
@@ -841,14 +1141,9 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__sun) \
|
||||
|| defined(__HAIKU__)
|
||||
/* utimesat() has nanosecond resolution but we stick to microseconds
|
||||
* for the sake of consistency with other platforms.
|
||||
*/
|
||||
struct timespec ts[2];
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
ts[0] = uv__fs_to_timespec(req->atime);
|
||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||
return utimensat(AT_FDCWD, req->path, ts, 0);
|
||||
#elif defined(__APPLE__) \
|
||||
|| defined(__DragonFly__) \
|
||||
@@ -857,10 +1152,8 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|
||||
|| defined(__NetBSD__) \
|
||||
|| defined(__OpenBSD__)
|
||||
struct timeval tv[2];
|
||||
tv[0].tv_sec = req->atime;
|
||||
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
|
||||
tv[1].tv_sec = req->mtime;
|
||||
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
|
||||
tv[0] = uv__fs_to_timeval(req->atime);
|
||||
tv[1] = uv__fs_to_timeval(req->mtime);
|
||||
return utimes(req->path, tv);
|
||||
#elif defined(_AIX) \
|
||||
&& !defined(_AIX71)
|
||||
@@ -883,6 +1176,32 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_lutime(uv_fs_t* req) {
|
||||
#if defined(__linux__) || \
|
||||
defined(_AIX71) || \
|
||||
defined(__sun) || \
|
||||
defined(__HAIKU__) || \
|
||||
defined(__GNU__)
|
||||
struct timespec ts[2];
|
||||
ts[0] = uv__fs_to_timespec(req->atime);
|
||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||
return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW);
|
||||
#elif defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__)
|
||||
struct timeval tv[2];
|
||||
tv[0] = uv__fs_to_timeval(req->atime);
|
||||
tv[1] = uv__fs_to_timeval(req->mtime);
|
||||
return lutimes(req->path, tv);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_write(uv_fs_t* req) {
|
||||
#if defined(__linux__)
|
||||
static int no_pwritev;
|
||||
@@ -952,8 +1271,10 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
int dst_flags;
|
||||
int result;
|
||||
int err;
|
||||
size_t bytes_to_send;
|
||||
int64_t in_offset;
|
||||
off_t bytes_to_send;
|
||||
off_t in_offset;
|
||||
off_t bytes_written;
|
||||
size_t bytes_chunk;
|
||||
|
||||
dstfd = -1;
|
||||
err = 0;
|
||||
@@ -971,7 +1292,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
dst_flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
dst_flags = O_WRONLY | O_CREAT;
|
||||
|
||||
if (req->flags & UV_FS_COPYFILE_EXCL)
|
||||
dst_flags |= O_EXCL;
|
||||
@@ -990,38 +1311,58 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get the destination file's mode. */
|
||||
if (fstat(dstfd, &dst_statsbuf)) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
/* If the file is not being opened exclusively, verify that the source and
|
||||
destination are not the same file. If they are the same, bail out early. */
|
||||
if ((req->flags & UV_FS_COPYFILE_EXCL) == 0) {
|
||||
/* Get the destination file's mode. */
|
||||
if (fstat(dstfd, &dst_statsbuf)) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check if srcfd and dstfd refer to the same file */
|
||||
if (src_statsbuf.st_dev == dst_statsbuf.st_dev &&
|
||||
src_statsbuf.st_ino == dst_statsbuf.st_ino) {
|
||||
goto out;
|
||||
/* Check if srcfd and dstfd refer to the same file */
|
||||
if (src_statsbuf.st_dev == dst_statsbuf.st_dev &&
|
||||
src_statsbuf.st_ino == dst_statsbuf.st_ino) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Truncate the file in case the destination already existed. */
|
||||
if (ftruncate(dstfd, 0) != 0) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
|
||||
err = UV__ERR(errno);
|
||||
#ifdef __linux__
|
||||
/* fchmod() on CIFS shares always fails with EPERM unless the share is
|
||||
* mounted with "noperm". As fchmod() is a meaningless operation on such
|
||||
* shares anyway, detect that condition and squelch the error.
|
||||
*/
|
||||
if (err != UV_EPERM)
|
||||
goto out;
|
||||
|
||||
if (!uv__is_cifs_or_smb(dstfd))
|
||||
goto out;
|
||||
|
||||
err = 0;
|
||||
#else /* !__linux__ */
|
||||
goto out;
|
||||
#endif /* !__linux__ */
|
||||
}
|
||||
|
||||
#ifdef FICLONE
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE ||
|
||||
req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
if (ioctl(dstfd, FICLONE, srcfd) == -1) {
|
||||
/* If an error occurred that the sendfile fallback also won't handle, or
|
||||
this is a force clone then exit. Otherwise, fall through to try using
|
||||
sendfile(). */
|
||||
if (errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
} else if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
err = UV_ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (ioctl(dstfd, FICLONE, srcfd) == 0) {
|
||||
/* ioctl() with FICLONE succeeded. */
|
||||
goto out;
|
||||
}
|
||||
/* If an error occurred and force was set, return the error to the caller;
|
||||
* fall back to sendfile() when force was not set. */
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1035,18 +1376,20 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
bytes_to_send = src_statsbuf.st_size;
|
||||
in_offset = 0;
|
||||
while (bytes_to_send != 0) {
|
||||
err = uv_fs_sendfile(NULL,
|
||||
&fs_req,
|
||||
dstfd,
|
||||
srcfd,
|
||||
in_offset,
|
||||
bytes_to_send,
|
||||
NULL);
|
||||
bytes_chunk = SSIZE_MAX;
|
||||
if (bytes_to_send < (off_t) bytes_chunk)
|
||||
bytes_chunk = bytes_to_send;
|
||||
uv_fs_sendfile(NULL, &fs_req, dstfd, srcfd, in_offset, bytes_chunk, NULL);
|
||||
bytes_written = fs_req.result;
|
||||
uv_fs_req_cleanup(&fs_req);
|
||||
if (err < 0)
|
||||
|
||||
if (bytes_written < 0) {
|
||||
err = bytes_written;
|
||||
break;
|
||||
bytes_to_send -= fs_req.result;
|
||||
in_offset += fs_req.result;
|
||||
}
|
||||
|
||||
bytes_to_send -= bytes_written;
|
||||
in_offset += bytes_written;
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -1119,7 +1462,8 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
|
||||
dst->st_birthtim.tv_nsec = src->st_ctimensec;
|
||||
dst->st_flags = 0;
|
||||
dst->st_gen = 0;
|
||||
#elif !defined(_AIX) && ( \
|
||||
#elif !defined(_AIX) && \
|
||||
!defined(__MVS__) && ( \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
@@ -1176,7 +1520,7 @@ static int uv__fs_statx(int fd,
|
||||
int mode;
|
||||
int rc;
|
||||
|
||||
if (no_statx)
|
||||
if (uv__load_relaxed(&no_statx))
|
||||
return UV_ENOSYS;
|
||||
|
||||
dirfd = AT_FDCWD;
|
||||
@@ -1193,23 +1537,33 @@ static int uv__fs_statx(int fd,
|
||||
|
||||
rc = uv__statx(dirfd, path, flags, mode, &statxbuf);
|
||||
|
||||
if (rc == -1) {
|
||||
switch (rc) {
|
||||
case 0:
|
||||
break;
|
||||
case -1:
|
||||
/* EPERM happens when a seccomp filter rejects the system call.
|
||||
* Has been observed with libseccomp < 2.3.3 and docker < 18.04.
|
||||
* EOPNOTSUPP is used on DVS exported filesystems
|
||||
*/
|
||||
if (errno != EINVAL && errno != EPERM && errno != ENOSYS)
|
||||
if (errno != EINVAL && errno != EPERM && errno != ENOSYS && errno != EOPNOTSUPP)
|
||||
return -1;
|
||||
|
||||
no_statx = 1;
|
||||
/* Fall through. */
|
||||
default:
|
||||
/* Normally on success, zero is returned and On error, -1 is returned.
|
||||
* Observed on S390 RHEL running in a docker container with statx not
|
||||
* implemented, rc might return 1 with 0 set as the error code in which
|
||||
* case we return ENOSYS.
|
||||
*/
|
||||
uv__store_relaxed(&no_statx, 1);
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
buf->st_dev = 256 * statxbuf.stx_dev_major + statxbuf.stx_dev_minor;
|
||||
buf->st_dev = makedev(statxbuf.stx_dev_major, statxbuf.stx_dev_minor);
|
||||
buf->st_mode = statxbuf.stx_mode;
|
||||
buf->st_nlink = statxbuf.stx_nlink;
|
||||
buf->st_uid = statxbuf.stx_uid;
|
||||
buf->st_gid = statxbuf.stx_gid;
|
||||
buf->st_rdev = statxbuf.stx_rdev_major;
|
||||
buf->st_rdev = makedev(statxbuf.stx_rdev_major, statxbuf.stx_rdev_minor);
|
||||
buf->st_ino = statxbuf.stx_ino;
|
||||
buf->st_size = statxbuf.stx_size;
|
||||
buf->st_blksize = statxbuf.stx_blksize;
|
||||
@@ -1370,10 +1724,12 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(FSYNC, uv__fs_fsync(req));
|
||||
X(FTRUNCATE, ftruncate(req->file, req->off));
|
||||
X(FUTIME, uv__fs_futime(req));
|
||||
X(LUTIME, uv__fs_lutime(req));
|
||||
X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
|
||||
X(LINK, link(req->path, req->new_path));
|
||||
X(MKDIR, mkdir(req->path, req->mode));
|
||||
X(MKDTEMP, uv__fs_mkdtemp(req));
|
||||
X(MKSTEMP, uv__fs_mkstemp(req));
|
||||
X(OPEN, uv__fs_open(req));
|
||||
X(READ, uv__fs_read(req));
|
||||
X(SCANDIR, uv__fs_scandir(req));
|
||||
@@ -1386,6 +1742,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(RMDIR, rmdir(req->path));
|
||||
X(SENDFILE, uv__fs_sendfile(req));
|
||||
X(STAT, uv__fs_stat(req->path, &req->statbuf));
|
||||
X(STATFS, uv__fs_statfs(req));
|
||||
X(SYMLINK, symlink(req->path, req->new_path));
|
||||
X(UNLINK, unlink(req->path));
|
||||
X(UTIME, uv__fs_utime(req));
|
||||
@@ -1554,6 +1911,19 @@ int uv_fs_futime(uv_loop_t* loop,
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_lutime(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
double atime,
|
||||
double mtime,
|
||||
uv_fs_cb cb) {
|
||||
INIT(LUTIME);
|
||||
PATH;
|
||||
req->atime = atime;
|
||||
req->mtime = mtime;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
INIT(LSTAT);
|
||||
@@ -1597,6 +1967,18 @@ int uv_fs_mkdtemp(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_mkstemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb) {
|
||||
INIT(MKSTEMP);
|
||||
req->path = uv__strdup(tpl);
|
||||
if (req->path == NULL)
|
||||
return UV_ENOMEM;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_open(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
@@ -1815,10 +2197,12 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
||||
|
||||
/* Only necessary for asychronous requests, i.e., requests with a callback.
|
||||
* Synchronous ones don't copy their arguments and have req->path and
|
||||
* req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the
|
||||
* exception to the rule, it always allocates memory.
|
||||
* req->new_path pointing to user-owned memory. UV_FS_MKDTEMP and
|
||||
* UV_FS_MKSTEMP are the exception to the rule, they always allocate memory.
|
||||
*/
|
||||
if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP))
|
||||
if (req->path != NULL &&
|
||||
(req->cb != NULL ||
|
||||
req->fs_type == UV_FS_MKDTEMP || req->fs_type == UV_FS_MKSTEMP))
|
||||
uv__free((void*) req->path); /* Memory is shared with req->new_path. */
|
||||
|
||||
req->path = NULL;
|
||||
@@ -1858,3 +2242,17 @@ int uv_fs_copyfile(uv_loop_t* loop,
|
||||
req->flags = flags;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb) {
|
||||
INIT(STATFS);
|
||||
PATH;
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_get_system_error(const uv_fs_t* req) {
|
||||
return -req->result;
|
||||
}
|
||||
|
||||
@@ -41,34 +41,33 @@ 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>
|
||||
|
||||
#include <CoreFoundation/CFRunLoop.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
static const int kFSEventsModified =
|
||||
kFSEventStreamEventFlagItemChangeOwner |
|
||||
kFSEventStreamEventFlagItemFinderInfoMod |
|
||||
kFSEventStreamEventFlagItemInodeMetaMod |
|
||||
kFSEventStreamEventFlagItemModified |
|
||||
kFSEventStreamEventFlagItemXattrMod;
|
||||
|
||||
/* These are macros to avoid "initializer element is not constant" errors
|
||||
* with old versions of gcc.
|
||||
*/
|
||||
#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
|
||||
kFSEventStreamEventFlagItemModified | \
|
||||
kFSEventStreamEventFlagItemInodeMetaMod | \
|
||||
kFSEventStreamEventFlagItemChangeOwner | \
|
||||
kFSEventStreamEventFlagItemXattrMod)
|
||||
static const int kFSEventsRenamed =
|
||||
kFSEventStreamEventFlagItemCreated |
|
||||
kFSEventStreamEventFlagItemRemoved |
|
||||
kFSEventStreamEventFlagItemRenamed;
|
||||
|
||||
#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
|
||||
kFSEventStreamEventFlagItemRemoved | \
|
||||
kFSEventStreamEventFlagItemRenamed)
|
||||
|
||||
#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
|
||||
kFSEventStreamEventFlagKernelDropped | \
|
||||
kFSEventStreamEventFlagEventIdsWrapped | \
|
||||
kFSEventStreamEventFlagHistoryDone | \
|
||||
kFSEventStreamEventFlagMount | \
|
||||
kFSEventStreamEventFlagUnmount | \
|
||||
kFSEventStreamEventFlagRootChanged)
|
||||
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;
|
||||
@@ -148,7 +147,7 @@ static void (*pFSEventStreamRelease)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
|
||||
CFRunLoopRef,
|
||||
CFStringRef);
|
||||
static Boolean (*pFSEventStreamStart)(FSEventStreamRef);
|
||||
static int (*pFSEventStreamStart)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamStop)(FSEventStreamRef);
|
||||
|
||||
#define UV__FSEVENTS_PROCESS(handle, block) \
|
||||
@@ -215,7 +214,7 @@ static void uv__fsevents_push_event(uv_fs_event_t* handle,
|
||||
|
||||
|
||||
/* Runs in CF thread, when there're events in FSEventStream */
|
||||
static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
|
||||
static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
|
||||
void* info,
|
||||
size_t numEvents,
|
||||
void* eventPaths,
|
||||
@@ -263,10 +262,12 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
|
||||
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] != '/')
|
||||
/* Make sure that realpath actually named a directory,
|
||||
* or that we matched the whole string */
|
||||
continue;
|
||||
|
||||
if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
|
||||
@@ -338,11 +339,8 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
|
||||
FSEventStreamCreateFlags flags;
|
||||
|
||||
/* Initialize context */
|
||||
ctx.version = 0;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.info = loop;
|
||||
ctx.retain = NULL;
|
||||
ctx.release = NULL;
|
||||
ctx.copyDescription = NULL;
|
||||
|
||||
latency = 0.05;
|
||||
|
||||
@@ -597,8 +595,7 @@ out:
|
||||
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;
|
||||
pthread_attr_t attr;
|
||||
int err;
|
||||
|
||||
if (loop->cf_state != NULL)
|
||||
@@ -643,25 +640,19 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) {
|
||||
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 (pthread_attr_init(&attr))
|
||||
abort();
|
||||
|
||||
if (attr != NULL)
|
||||
if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
|
||||
abort();
|
||||
if (pthread_attr_setstacksize(&attr, uv__thread_stack_size()))
|
||||
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));
|
||||
err = UV__ERR(pthread_create(&loop->cf_thread, &attr, uv__cf_loop_runner, loop));
|
||||
|
||||
if (attr != NULL)
|
||||
pthread_attr_destroy(attr);
|
||||
if (pthread_attr_destroy(&attr))
|
||||
abort();
|
||||
|
||||
if (err)
|
||||
goto fail_thread_create;
|
||||
@@ -745,6 +736,8 @@ static void* uv__cf_loop_runner(void* arg) {
|
||||
state->signal_source,
|
||||
*pkCFRunLoopDefaultMode);
|
||||
|
||||
state->loop = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -797,13 +790,14 @@ int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
|
||||
uv_mutex_lock(&loop->cf_mutex);
|
||||
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
|
||||
uv_mutex_unlock(&loop->cf_mutex);
|
||||
|
||||
state = (uv__cf_loop_state_t*)loop->cf_state;
|
||||
assert(state != NULL);
|
||||
pCFRunLoopSourceSignal(state->signal_source);
|
||||
pCFRunLoopWakeUp(state->loop);
|
||||
|
||||
uv_mutex_unlock(&loop->cf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,6 @@
|
||||
/* 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"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -56,7 +55,11 @@
|
||||
#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;
|
||||
@@ -98,24 +101,94 @@ typedef struct {
|
||||
} 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)
|
||||
srclen = length;
|
||||
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 ("SSTS0200" in EBCDIC) */
|
||||
unsigned char format[] = {0xE2, 0xE2, 0xE3, 0xE2, 0xF0, 0xF2, 0xF0, 0xF0};
|
||||
|
||||
/* reset_status is input parameter 4 to QWCRSSTS ("*NO " in EBCDIC) */
|
||||
unsigned char reset_status[] = {
|
||||
0x5C, 0xD5, 0xD6, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
|
||||
};
|
||||
/* 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 */
|
||||
struct _errcode {
|
||||
int bytes_provided;
|
||||
int bytes_available;
|
||||
char msgid[7];
|
||||
} errcode;
|
||||
errcode_s errcode;
|
||||
|
||||
/* qwcrssts_pointer is the 16-byte tagged system pointer to QWCRSSTS */
|
||||
ILEpointer __attribute__((aligned(16))) qwcrssts_pointer;
|
||||
@@ -145,7 +218,7 @@ static int get_ibmi_system_status(SSTS0200* rcvr) {
|
||||
qwcrssts_argv[5] = NULL;
|
||||
|
||||
/* Call the IBM i QWCRSSTS API from PASE */
|
||||
rc = _PGMCALL(&qwcrssts_pointer, (void**)&qwcrssts_argv, 0);
|
||||
rc = _PGMCALL(&qwcrssts_pointer, qwcrssts_argv, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -157,19 +230,7 @@ uint64_t uv_get_free_memory(void) {
|
||||
if (get_ibmi_system_status(&rcvr))
|
||||
return 0;
|
||||
|
||||
/* The amount of main storage, in kilobytes, in the system. */
|
||||
uint64_t main_storage_size = rcvr.main_storage_size;
|
||||
|
||||
/* The current amount of storage in use for temporary objects.
|
||||
* in millions (M) of bytes.
|
||||
*/
|
||||
uint64_t current_unprotected_storage_used =
|
||||
rcvr.current_unprotected_storage_used * 1024ULL;
|
||||
|
||||
uint64_t free_storage_size =
|
||||
(main_storage_size - current_unprotected_storage_used) * 1024ULL;
|
||||
|
||||
return free_storage_size < 0 ? 0 : free_storage_size;
|
||||
return (uint64_t)rcvr.main_storage_size * 1024ULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -247,3 +308,230 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
|
||||
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;
|
||||
|
||||
if (err.bytes_available > 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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 = -1;
|
||||
size_t name_len = strlen(address->name);
|
||||
/* To get the associated MAC address, we must convert the address to a
|
||||
* line description. Normally, the name field contains the line
|
||||
* description name, but for VLANs it has the VLAN appended with a
|
||||
* period. Since object names can also contain periods and numbers, there
|
||||
* is no way to know if a returned name is for a VLAN or not. eg.
|
||||
* *LIND ETH1.1 and *LIND ETH1, VLAN 1 both have the same name: ETH1.1
|
||||
*
|
||||
* Instead, we apply the same heuristic used by some of the XPF ioctls:
|
||||
* - names > 10 *must* contain a VLAN
|
||||
* - assume names <= 10 do not contain a VLAN and try directly
|
||||
* - if >10 or QDCRLIND returned an error, try to strip off a VLAN
|
||||
* and try again
|
||||
* - if we still get an error or couldn't find a period, leave the MAC as
|
||||
* 00:00:00:00:00:00
|
||||
*/
|
||||
if (name_len <= 10) {
|
||||
/* Assume name does not contain a VLAN ID */
|
||||
rc = get_ibmi_physical_address(address->name, &address->phys_addr);
|
||||
}
|
||||
|
||||
if (name_len > 10 || rc != 0) {
|
||||
/* The interface name must contain a VLAN ID suffix. Attempt to strip
|
||||
* it off so we can get the line description to pass to QDCRLIND.
|
||||
*/
|
||||
char* temp_name = uv__strdup(address->name);
|
||||
char* dot = strrchr(temp_name, '.');
|
||||
if (dot != NULL) {
|
||||
*dot = '\0';
|
||||
if (strlen(temp_name) <= 10) {
|
||||
rc = get_ibmi_physical_address(temp_name, &address->phys_addr);
|
||||
}
|
||||
}
|
||||
uv__free(temp_name);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
#include <limits.h> /* _POSIX_PATH_MAX, PATH_MAX */
|
||||
#include <stdlib.h> /* abort */
|
||||
#include <string.h> /* strrchr */
|
||||
#include <fcntl.h> /* O_CLOEXEC, may be */
|
||||
#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
|
||||
@@ -61,9 +62,18 @@
|
||||
# include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#if defined(_POSIX_PATH_MAX)
|
||||
# define UV__PATH_MAX _POSIX_PATH_MAX
|
||||
#elif defined(PATH_MAX)
|
||||
/*
|
||||
* Define common detection for active Thread Sanitizer
|
||||
* - clang uses __has_feature(thread_sanitizer)
|
||||
* - gcc-7+ uses __SANITIZE_THREAD__
|
||||
*/
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(thread_sanitizer)
|
||||
# define __SANITIZE_THREAD__ 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(PATH_MAX)
|
||||
# define UV__PATH_MAX PATH_MAX
|
||||
#else
|
||||
# define UV__PATH_MAX 8192
|
||||
@@ -105,10 +115,8 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
#if defined(__clang__) || \
|
||||
defined(__GNUC__) || \
|
||||
defined(__INTEL_COMPILER)
|
||||
# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
|
||||
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
|
||||
#else
|
||||
# define UV_DESTRUCTOR(declaration) declaration
|
||||
# define UV_UNUSED(declaration) declaration
|
||||
#endif
|
||||
|
||||
@@ -137,7 +145,8 @@ typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
|
||||
|
||||
/* loop flags */
|
||||
enum {
|
||||
UV_LOOP_BLOCK_SIGPROF = 1
|
||||
UV_LOOP_BLOCK_SIGPROF = 0x1,
|
||||
UV_LOOP_REAP_CHILDREN = 0x2
|
||||
};
|
||||
|
||||
/* flags of excluding ifaddr */
|
||||
@@ -166,13 +175,11 @@ struct uv__stream_queued_fds_s {
|
||||
defined(__linux__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
#define uv__cloexec uv__cloexec_ioctl
|
||||
#define uv__nonblock uv__nonblock_ioctl
|
||||
#define UV__NONBLOCK_IS_IOCTL
|
||||
#define UV__NONBLOCK_IS_IOCTL 1
|
||||
#else
|
||||
#define uv__cloexec uv__cloexec_fcntl
|
||||
#define uv__nonblock uv__nonblock_fcntl
|
||||
#define UV__NONBLOCK_IS_FCNTL
|
||||
#define UV__NONBLOCK_IS_IOCTL 0
|
||||
#endif
|
||||
|
||||
/* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute
|
||||
@@ -190,8 +197,7 @@ struct uv__stream_queued_fds_s {
|
||||
#endif
|
||||
|
||||
/* core */
|
||||
int uv__cloexec_ioctl(int fd, int set);
|
||||
int uv__cloexec_fcntl(int fd, int set);
|
||||
int uv__cloexec(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 */
|
||||
@@ -235,14 +241,15 @@ 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);
|
||||
int uv__slurp(const char* filename, char* buf, size_t len);
|
||||
|
||||
/* tcp */
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
|
||||
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);
|
||||
int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
|
||||
/* signal */
|
||||
void uv__signal_close(uv_signal_t* handle);
|
||||
@@ -253,6 +260,7 @@ 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__epoll_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);
|
||||
@@ -268,12 +276,21 @@ 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);
|
||||
size_t uv__thread_stack_size(void);
|
||||
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);
|
||||
void uv__wait_children(uv_loop_t* loop);
|
||||
|
||||
/* 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);
|
||||
@@ -282,13 +299,6 @@ int uv___stream_fd(const uv_stream_t* handle);
|
||||
#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
#ifdef UV__O_NONBLOCK
|
||||
# define UV__F_NONBLOCK UV__O_NONBLOCK
|
||||
#else
|
||||
# define UV__F_NONBLOCK 1
|
||||
#endif
|
||||
|
||||
int uv__make_socketpair(int fds[2], int flags);
|
||||
int uv__make_pipe(int fds[2], int flags);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -326,4 +336,37 @@ int uv__getsockpeername(const uv_handle_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen);
|
||||
|
||||
#if defined(__linux__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__DragonFly__)
|
||||
#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
|
||||
|
||||
#if defined(__sun)
|
||||
#if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L
|
||||
size_t strnlen(const char* s, size_t maxlen);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
ssize_t
|
||||
uv__fs_copy_file_range(int fd_in,
|
||||
off_t* off_in,
|
||||
int fd_out,
|
||||
off_t* off_out,
|
||||
size_t len,
|
||||
unsigned int flags);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UV_UNIX_INTERNAL_H_ */
|
||||
|
||||
@@ -82,7 +82,7 @@ int uv__io_fork(uv_loop_t* loop) {
|
||||
process. So we sidestep the issue by pretending like we never
|
||||
started it in the first place.
|
||||
*/
|
||||
uv__has_forked_with_cfrunloop = 1;
|
||||
uv__store_relaxed(&uv__has_forked_with_cfrunloop, 1);
|
||||
uv__free(loop->cf_state);
|
||||
loop->cf_state = NULL;
|
||||
}
|
||||
@@ -117,6 +117,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
unsigned int revents;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
uv_process_t* process;
|
||||
sigset_t* pset;
|
||||
sigset_t set;
|
||||
uint64_t base;
|
||||
@@ -129,6 +130,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
int fd;
|
||||
int op;
|
||||
int i;
|
||||
int user_timeout;
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
@@ -202,7 +205,21 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
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;
|
||||
@@ -228,6 +245,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
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;
|
||||
}
|
||||
@@ -236,6 +262,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
if (errno != EINTR)
|
||||
abort();
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
@@ -255,6 +286,21 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
for (i = 0; i < nfds; i++) {
|
||||
ev = events + i;
|
||||
fd = ev->ident;
|
||||
|
||||
/* Handle kevent NOTE_EXIT results */
|
||||
if (ev->filter == EVFILT_PROC) {
|
||||
QUEUE_FOREACH(q, &loop->process_handles) {
|
||||
process = QUEUE_DATA(q, uv_process_t, queue);
|
||||
if (process->pid == fd) {
|
||||
process->flags |= UV_HANDLE_REAP;
|
||||
loop->flags |= UV_LOOP_REAP_CHILDREN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nevents++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
continue;
|
||||
@@ -276,6 +322,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
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;
|
||||
@@ -295,6 +342,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
if (errno != ENOENT)
|
||||
abort();
|
||||
}
|
||||
if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
|
||||
revents |= UV__POLLRDHUP;
|
||||
}
|
||||
|
||||
if (ev->filter == EV_OOBAND) {
|
||||
@@ -328,25 +377,36 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
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)
|
||||
if (w == &loop->signal_io_watcher) {
|
||||
have_signals = 1;
|
||||
else
|
||||
} else {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
w->cb(loop, w, revents);
|
||||
}
|
||||
|
||||
nevents++;
|
||||
}
|
||||
|
||||
if (have_signals != 0)
|
||||
if (loop->flags & UV_LOOP_REAP_CHILDREN) {
|
||||
loop->flags &= ~UV_LOOP_REAP_CHILDREN;
|
||||
uv__wait_children(loop);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -454,10 +514,26 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
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;
|
||||
@@ -465,14 +541,17 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
handle->realpath_len = 0;
|
||||
handle->cf_flags = flags;
|
||||
|
||||
if (!uv__has_forked_with_cfrunloop) {
|
||||
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 not used */
|
||||
/* The fallback fd is no longer needed */
|
||||
uv__close_nocheckstdio(fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
handle->path = uv__strdup(path);
|
||||
if (handle->path == NULL)
|
||||
return UV_ENOMEM;
|
||||
handle->cb = cb;
|
||||
r = uv__fsevents_init(handle);
|
||||
if (r == 0) {
|
||||
uv__handle_start(handle);
|
||||
@@ -482,20 +561,9 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
}
|
||||
return r;
|
||||
}
|
||||
fallback:
|
||||
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
|
||||
|
||||
/* TODO open asynchronously - but how do we report back errors? */
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
handle->path = uv__strdup(path);
|
||||
if (handle->path == NULL) {
|
||||
uv__close_nocheckstdio(fd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
handle->cb = cb;
|
||||
uv__handle_start(handle);
|
||||
uv__io_init(&handle->event_watcher, uv__fs_event, fd);
|
||||
uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
|
||||
@@ -514,8 +582,9 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
uv__handle_stop(handle);
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (!uv__has_forked_with_cfrunloop)
|
||||
r = uv__fsevents_close(handle);
|
||||
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) {
|
||||
|
||||
@@ -45,6 +45,10 @@
|
||||
|
||||
#define HAVE_IFADDRS_H 1
|
||||
|
||||
# if defined(__ANDROID_API__) && __ANDROID_API__ < 24
|
||||
# undef HAVE_IFADDRS_H
|
||||
#endif
|
||||
|
||||
#ifdef __UCLIBC__
|
||||
# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
|
||||
# undef HAVE_IFADDRS_H
|
||||
@@ -52,11 +56,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
# if defined(__ANDROID__)
|
||||
# include "uv/android-ifaddrs.h"
|
||||
# else
|
||||
# include <ifaddrs.h>
|
||||
# endif
|
||||
# include <ifaddrs.h>
|
||||
# include <sys/socket.h>
|
||||
# include <net/ethernet.h>
|
||||
# include <netpacket/packet.h>
|
||||
@@ -86,34 +86,12 @@ static int read_times(FILE* statfile_fp,
|
||||
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
|
||||
static uint64_t read_cpufreq(unsigned int cpunum);
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
int fd;
|
||||
|
||||
/* It was reported that EPOLL_CLOEXEC is not defined on Android API < 21,
|
||||
* a.k.a. Lollipop. Since EPOLL_CLOEXEC is an alias for O_CLOEXEC on all
|
||||
* architectures, we just use that instead.
|
||||
*/
|
||||
fd = epoll_create1(O_CLOEXEC);
|
||||
|
||||
/* epoll_create1() can fail either because it's not implemented (old kernel)
|
||||
* or because it doesn't understand the O_CLOEXEC flag.
|
||||
*/
|
||||
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
|
||||
fd = epoll_create(256);
|
||||
|
||||
if (fd != -1)
|
||||
uv__cloexec(fd, 1);
|
||||
}
|
||||
|
||||
loop->backend_fd = fd;
|
||||
|
||||
loop->inotify_fd = -1;
|
||||
loop->inotify_watchers = NULL;
|
||||
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
return uv__epoll_init(loop);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,290 +121,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
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 (events[i].data.fd == fd)
|
||||
events[i].data.fd = -1;
|
||||
|
||||
/* Remove the file descriptor from the epoll.
|
||||
* This avoids a problem where the same file description remains open
|
||||
* in another process, causing repeated junk epoll events.
|
||||
*
|
||||
* We pass in a dummy epoll_event, to work around a bug in old kernels.
|
||||
*/
|
||||
if (loop->backend_fd >= 0) {
|
||||
/* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
|
||||
* has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
|
||||
*/
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct epoll_event e;
|
||||
int rc;
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
e.events = POLLIN;
|
||||
e.data.fd = -1;
|
||||
|
||||
rc = 0;
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
|
||||
if (errno != EEXIST)
|
||||
rc = UV__ERR(errno);
|
||||
|
||||
if (rc == 0)
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
/* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
|
||||
* effectively infinite on 32 bits architectures. To avoid blocking
|
||||
* indefinitely, we cap the timeout and poll again if necessary.
|
||||
*
|
||||
* Note that "30 minutes" is a simplification because it depends on
|
||||
* the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
|
||||
* that being the largest value I have seen in the wild (and only once.)
|
||||
*/
|
||||
static const int max_safe_timeout = 1789569;
|
||||
struct epoll_event events[1024];
|
||||
struct epoll_event* pe;
|
||||
struct epoll_event e;
|
||||
int real_timeout;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t sigset;
|
||||
sigset_t* psigset;
|
||||
uint64_t base;
|
||||
int have_signals;
|
||||
int nevents;
|
||||
int count;
|
||||
int nfds;
|
||||
int fd;
|
||||
int op;
|
||||
int i;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
|
||||
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);
|
||||
|
||||
e.events = w->pevents;
|
||||
e.data.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->backend_fd, 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->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
|
||||
abort();
|
||||
}
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
psigset = NULL;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGPROF);
|
||||
psigset = &sigset;
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
base = loop->time;
|
||||
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
||||
real_timeout = timeout;
|
||||
|
||||
for (;;) {
|
||||
/* See the comment for max_safe_timeout for an explanation of why
|
||||
* this is necessary. Executive summary: kernel bug workaround.
|
||||
*/
|
||||
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
|
||||
timeout = max_safe_timeout;
|
||||
|
||||
nfds = epoll_pwait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout,
|
||||
psigset);
|
||||
|
||||
/* 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) {
|
||||
assert(timeout != -1);
|
||||
|
||||
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 (timeout == -1)
|
||||
continue;
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
/* 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] = events;
|
||||
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
pe = events + i;
|
||||
fd = pe->data.fd;
|
||||
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert((unsigned) fd < loop->nwatchers);
|
||||
|
||||
w = (uv__io_t*)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->backend_fd, 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;
|
||||
|
||||
/* Work around an epoll quirk where it sometimes reports just the
|
||||
* EPOLLERR or EPOLLHUP event. In order to force the event loop to
|
||||
* move forward, we merge in the read/write events that the watcher
|
||||
* is interested in; uv__read() and uv__write() will then deal with
|
||||
* the error or hangup in the usual fashion.
|
||||
*
|
||||
* Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
|
||||
* reads the available data, calls uv_read_stop(), then sometime later
|
||||
* calls uv_read_start() again. By then, libuv has forgotten about the
|
||||
* hangup and the kernel won't report EPOLLIN again because there's
|
||||
* nothing left to read. If anything, libuv is to blame here. The
|
||||
* current hack is just a quick bandaid; to properly fix it, libuv
|
||||
* needs to remember the error/hangup event. We should get that for
|
||||
* free when we switch over to edge-triggered I/O.
|
||||
*/
|
||||
if (pe->events == POLLERR || pe->events == POLLHUP)
|
||||
pe->events |=
|
||||
w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
|
||||
|
||||
if (pe->events != 0) {
|
||||
/* 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
|
||||
w->cb(loop, w, pe->events);
|
||||
|
||||
nevents++;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_signals != 0)
|
||||
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);
|
||||
|
||||
real_timeout -= (loop->time - base);
|
||||
if (real_timeout <= 0)
|
||||
return;
|
||||
|
||||
timeout = real_timeout;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
#ifdef __FRC_ROBORIO__
|
||||
return wpi::Now() * 1000u;
|
||||
@@ -443,18 +137,22 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
/* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
|
||||
* when it has microsecond granularity or better (unlikely).
|
||||
*/
|
||||
if (type == UV_CLOCK_FAST && fast_clock_id == -1) {
|
||||
if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 &&
|
||||
t.tv_nsec <= 1 * 1000 * 1000) {
|
||||
fast_clock_id = CLOCK_MONOTONIC_COARSE;
|
||||
} else {
|
||||
fast_clock_id = CLOCK_MONOTONIC;
|
||||
}
|
||||
}
|
||||
clock_id = CLOCK_MONOTONIC;
|
||||
if (type != UV_CLOCK_FAST)
|
||||
goto done;
|
||||
|
||||
clock_id = uv__load_relaxed(&fast_clock_id);
|
||||
if (clock_id != -1)
|
||||
goto done;
|
||||
|
||||
clock_id = CLOCK_MONOTONIC;
|
||||
if (type == UV_CLOCK_FAST)
|
||||
clock_id = fast_clock_id;
|
||||
if (0 == clock_getres(CLOCK_MONOTONIC_COARSE, &t))
|
||||
if (t.tv_nsec <= 1 * 1000 * 1000)
|
||||
clock_id = CLOCK_MONOTONIC_COARSE;
|
||||
|
||||
uv__store_relaxed(&fast_clock_id, clock_id);
|
||||
|
||||
done:
|
||||
|
||||
if (clock_gettime(clock_id, &t))
|
||||
return 0; /* Not really possible. */
|
||||
@@ -520,22 +218,28 @@ err:
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
static volatile int no_clock_boottime;
|
||||
char buf[128];
|
||||
struct timespec now;
|
||||
int r;
|
||||
|
||||
/* Try /proc/uptime first, then fallback to clock_gettime(). */
|
||||
|
||||
if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
|
||||
if (1 == sscanf(buf, "%lf", uptime))
|
||||
return 0;
|
||||
|
||||
/* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
|
||||
* (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
|
||||
* is suspended.
|
||||
*/
|
||||
if (no_clock_boottime) {
|
||||
retry: r = clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
retry_clock_gettime: r = clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
}
|
||||
else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
|
||||
no_clock_boottime = 1;
|
||||
goto retry;
|
||||
goto retry_clock_gettime;
|
||||
}
|
||||
|
||||
if (r)
|
||||
@@ -627,35 +331,47 @@ static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
|
||||
}
|
||||
|
||||
|
||||
/* Also reads the CPU frequency on x86. The other architectures only have
|
||||
* a BogoMIPS field, which may not be very accurate.
|
||||
/* Also reads the CPU frequency on ppc and x86. The other architectures only
|
||||
* have a BogoMIPS field, which may not be very accurate.
|
||||
*
|
||||
* Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
|
||||
*/
|
||||
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
|
||||
#if defined(__PPC__)
|
||||
static const char model_marker[] = "cpu\t\t: ";
|
||||
static const char speed_marker[] = "clock\t\t: ";
|
||||
#else
|
||||
static const char model_marker[] = "model name\t: ";
|
||||
static const char speed_marker[] = "cpu MHz\t\t: ";
|
||||
#endif
|
||||
const char* inferred_model;
|
||||
unsigned int model_idx;
|
||||
unsigned int speed_idx;
|
||||
unsigned int part_idx;
|
||||
char buf[1024];
|
||||
char* model;
|
||||
FILE* fp;
|
||||
int model_id;
|
||||
|
||||
/* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
|
||||
(void) &model_marker;
|
||||
(void) &speed_marker;
|
||||
(void) &speed_idx;
|
||||
(void) &part_idx;
|
||||
(void) &model;
|
||||
(void) &buf;
|
||||
(void) &fp;
|
||||
(void) &model_id;
|
||||
|
||||
model_idx = 0;
|
||||
speed_idx = 0;
|
||||
part_idx = 0;
|
||||
|
||||
#if defined(__arm__) || \
|
||||
defined(__i386__) || \
|
||||
defined(__mips__) || \
|
||||
defined(__aarch64__) || \
|
||||
defined(__PPC__) || \
|
||||
defined(__x86_64__)
|
||||
fp = uv__open_file("/proc/cpuinfo");
|
||||
if (fp == NULL)
|
||||
@@ -674,11 +390,96 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#if defined(__arm__) || defined(__mips__)
|
||||
#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
|
||||
if (model_idx < numcpus) {
|
||||
#if defined(__arm__)
|
||||
/* Fallback for pre-3.8 kernels. */
|
||||
static const char model_marker[] = "Processor\t: ";
|
||||
#elif defined(__aarch64__)
|
||||
static const char part_marker[] = "CPU part\t: ";
|
||||
|
||||
/* Adapted from: https://github.com/karelzak/util-linux */
|
||||
struct vendor_part {
|
||||
const int id;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
static const struct vendor_part arm_chips[] = {
|
||||
{ 0x811, "ARM810" },
|
||||
{ 0x920, "ARM920" },
|
||||
{ 0x922, "ARM922" },
|
||||
{ 0x926, "ARM926" },
|
||||
{ 0x940, "ARM940" },
|
||||
{ 0x946, "ARM946" },
|
||||
{ 0x966, "ARM966" },
|
||||
{ 0xa20, "ARM1020" },
|
||||
{ 0xa22, "ARM1022" },
|
||||
{ 0xa26, "ARM1026" },
|
||||
{ 0xb02, "ARM11 MPCore" },
|
||||
{ 0xb36, "ARM1136" },
|
||||
{ 0xb56, "ARM1156" },
|
||||
{ 0xb76, "ARM1176" },
|
||||
{ 0xc05, "Cortex-A5" },
|
||||
{ 0xc07, "Cortex-A7" },
|
||||
{ 0xc08, "Cortex-A8" },
|
||||
{ 0xc09, "Cortex-A9" },
|
||||
{ 0xc0d, "Cortex-A17" }, /* Originally A12 */
|
||||
{ 0xc0f, "Cortex-A15" },
|
||||
{ 0xc0e, "Cortex-A17" },
|
||||
{ 0xc14, "Cortex-R4" },
|
||||
{ 0xc15, "Cortex-R5" },
|
||||
{ 0xc17, "Cortex-R7" },
|
||||
{ 0xc18, "Cortex-R8" },
|
||||
{ 0xc20, "Cortex-M0" },
|
||||
{ 0xc21, "Cortex-M1" },
|
||||
{ 0xc23, "Cortex-M3" },
|
||||
{ 0xc24, "Cortex-M4" },
|
||||
{ 0xc27, "Cortex-M7" },
|
||||
{ 0xc60, "Cortex-M0+" },
|
||||
{ 0xd01, "Cortex-A32" },
|
||||
{ 0xd03, "Cortex-A53" },
|
||||
{ 0xd04, "Cortex-A35" },
|
||||
{ 0xd05, "Cortex-A55" },
|
||||
{ 0xd06, "Cortex-A65" },
|
||||
{ 0xd07, "Cortex-A57" },
|
||||
{ 0xd08, "Cortex-A72" },
|
||||
{ 0xd09, "Cortex-A73" },
|
||||
{ 0xd0a, "Cortex-A75" },
|
||||
{ 0xd0b, "Cortex-A76" },
|
||||
{ 0xd0c, "Neoverse-N1" },
|
||||
{ 0xd0d, "Cortex-A77" },
|
||||
{ 0xd0e, "Cortex-A76AE" },
|
||||
{ 0xd13, "Cortex-R52" },
|
||||
{ 0xd20, "Cortex-M23" },
|
||||
{ 0xd21, "Cortex-M33" },
|
||||
{ 0xd41, "Cortex-A78" },
|
||||
{ 0xd42, "Cortex-A78AE" },
|
||||
{ 0xd4a, "Neoverse-E1" },
|
||||
{ 0xd4b, "Cortex-A78C" },
|
||||
};
|
||||
|
||||
if (strncmp(buf, part_marker, sizeof(part_marker) - 1) == 0) {
|
||||
model = buf + sizeof(part_marker) - 1;
|
||||
|
||||
errno = 0;
|
||||
model_id = strtol(model, NULL, 16);
|
||||
if ((errno != 0) || model_id < 0) {
|
||||
fclose(fp);
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
for (part_idx = 0; part_idx < ARRAY_SIZE(arm_chips); part_idx++) {
|
||||
if (model_id == arm_chips[part_idx].id) {
|
||||
model = uv__strdup(arm_chips[part_idx].name);
|
||||
if (model == NULL) {
|
||||
fclose(fp);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
ci[model_idx++].model = model;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else /* defined(__mips__) */
|
||||
static const char model_marker[] = "cpu model\t\t: ";
|
||||
#endif
|
||||
@@ -693,18 +494,18 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else /* !__arm__ && !__mips__ */
|
||||
#else /* !__arm__ && !__mips__ && !__aarch64__ */
|
||||
if (speed_idx < numcpus) {
|
||||
if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
|
||||
ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif /* __arm__ || __mips__ */
|
||||
#endif /* __arm__ || __mips__ || __aarch64__ */
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */
|
||||
#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ || __aarch__ */
|
||||
|
||||
/* Now we want to make sure that all the models contain *something* because
|
||||
* it's not safe to leave them as null. Copy the last entry unless there
|
||||
@@ -729,7 +530,8 @@ static int read_times(FILE* statfile_fp,
|
||||
unsigned int numcpus,
|
||||
uv_cpu_info_t* ci) {
|
||||
struct uv_cpu_times_s ts;
|
||||
uint64_t clock_ticks;
|
||||
unsigned int ticks;
|
||||
unsigned int multiplier;
|
||||
uint64_t user;
|
||||
uint64_t nice;
|
||||
uint64_t sys;
|
||||
@@ -740,9 +542,10 @@ static int read_times(FILE* statfile_fp,
|
||||
uint64_t len;
|
||||
char buf[1024];
|
||||
|
||||
clock_ticks = sysconf(_SC_CLK_TCK);
|
||||
assert(clock_ticks != (uint64_t) -1);
|
||||
assert(clock_ticks != 0);
|
||||
ticks = (unsigned int)sysconf(_SC_CLK_TCK);
|
||||
assert(ticks != (unsigned int) -1);
|
||||
assert(ticks != 0);
|
||||
multiplier = ((uint64_t)1000L / ticks);
|
||||
|
||||
rewind(statfile_fp);
|
||||
|
||||
@@ -784,11 +587,11 @@ static int read_times(FILE* statfile_fp,
|
||||
&irq))
|
||||
abort();
|
||||
|
||||
ts.user = clock_ticks * user;
|
||||
ts.nice = clock_ticks * nice;
|
||||
ts.sys = clock_ticks * sys;
|
||||
ts.idle = clock_ticks * idle;
|
||||
ts.irq = clock_ticks * irq;
|
||||
ts.user = user * multiplier;
|
||||
ts.nice = nice * multiplier;
|
||||
ts.sys = sys * multiplier;
|
||||
ts.idle = idle * multiplier;
|
||||
ts.irq = irq * multiplier;
|
||||
ci[num++].cpu_times = ts;
|
||||
}
|
||||
assert(num == numcpus);
|
||||
@@ -820,16 +623,7 @@ static uint64_t read_cpufreq(unsigned int cpunum) {
|
||||
}
|
||||
|
||||
|
||||
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 HAVE_IFADDRS_H
|
||||
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
return 1;
|
||||
@@ -843,6 +637,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
return exclude_type;
|
||||
return !exclude_type;
|
||||
}
|
||||
#endif
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
#ifndef HAVE_IFADDRS_H
|
||||
@@ -953,41 +748,23 @@ void uv__set_process_title(const char* title) {
|
||||
|
||||
static uint64_t uv__read_proc_meminfo(const char* what) {
|
||||
uint64_t rc;
|
||||
ssize_t n;
|
||||
char* p;
|
||||
int fd;
|
||||
char buf[4096]; /* Large enough to hold all of /proc/meminfo. */
|
||||
|
||||
rc = 0;
|
||||
fd = uv__open_cloexec("/proc/meminfo", O_RDONLY);
|
||||
|
||||
if (fd == -1)
|
||||
if (uv__slurp("/proc/meminfo", buf, sizeof(buf)))
|
||||
return 0;
|
||||
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
|
||||
if (n <= 0)
|
||||
goto out;
|
||||
|
||||
buf[n] = '\0';
|
||||
p = strstr(buf, what);
|
||||
|
||||
if (p == NULL)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
p += strlen(what);
|
||||
|
||||
if (1 != sscanf(p, "%" PRIu64 " kB", &rc))
|
||||
goto out;
|
||||
rc = 0;
|
||||
sscanf(p, "%" PRIu64 " kB", &rc);
|
||||
|
||||
rc *= 1024;
|
||||
|
||||
out:
|
||||
|
||||
if (uv__close_nocheckstdio(fd))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
return rc * 1024;
|
||||
}
|
||||
|
||||
|
||||
@@ -995,7 +772,7 @@ uint64_t uv_get_free_memory(void) {
|
||||
struct sysinfo info;
|
||||
uint64_t rc;
|
||||
|
||||
rc = uv__read_proc_meminfo("MemFree:");
|
||||
rc = uv__read_proc_meminfo("MemAvailable:");
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
@@ -1025,28 +802,13 @@ uint64_t uv_get_total_memory(void) {
|
||||
|
||||
static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) {
|
||||
char filename[256];
|
||||
uint64_t rc;
|
||||
int fd;
|
||||
ssize_t n;
|
||||
char buf[32]; /* Large enough to hold an encoded uint64_t. */
|
||||
|
||||
snprintf(filename, 256, "/sys/fs/cgroup/%s/%s", cgroup, param);
|
||||
uint64_t rc;
|
||||
|
||||
rc = 0;
|
||||
fd = uv__open_cloexec(filename, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
|
||||
if (n > 0) {
|
||||
buf[n] = '\0';
|
||||
snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/%s", cgroup, param);
|
||||
if (0 == uv__slurp(filename, buf, sizeof(buf)))
|
||||
sscanf(buf, "%" PRIu64, &rc);
|
||||
}
|
||||
|
||||
if (uv__close_nocheckstdio(fd))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1060,3 +822,20 @@ uint64_t uv_get_constrained_memory(void) {
|
||||
*/
|
||||
return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes");
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct sysinfo info;
|
||||
char buf[128]; /* Large enough to hold all of /proc/loadavg. */
|
||||
|
||||
if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf)))
|
||||
if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2]))
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -64,45 +65,17 @@ static void uv__inotify_read(uv_loop_t* loop,
|
||||
static void maybe_free_watcher_list(struct watcher_list* w,
|
||||
uv_loop_t* loop);
|
||||
|
||||
static int new_inotify_fd(void) {
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
|
||||
fd = uv__inotify_init();
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
err = uv__cloexec(fd, 1);
|
||||
if (err == 0)
|
||||
err = uv__nonblock(fd, 1);
|
||||
|
||||
if (err) {
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
static int init_inotify(uv_loop_t* loop) {
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
if (loop->inotify_fd != -1)
|
||||
return 0;
|
||||
|
||||
err = new_inotify_fd();
|
||||
if (err < 0)
|
||||
return err;
|
||||
fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
loop->inotify_fd = err;
|
||||
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);
|
||||
|
||||
@@ -186,7 +159,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
|
||||
if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
|
||||
/* No watchers left for this path. Clean up. */
|
||||
RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
|
||||
uv__inotify_rm_watch(loop->inotify_fd, w->wd);
|
||||
inotify_rm_watch(loop->inotify_fd, w->wd);
|
||||
uv__free(w);
|
||||
}
|
||||
}
|
||||
@@ -194,7 +167,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
|
||||
static void uv__inotify_read(uv_loop_t* loop,
|
||||
uv__io_t* dummy,
|
||||
unsigned int events) {
|
||||
const struct uv__inotify_event* e;
|
||||
const struct inotify_event* e;
|
||||
struct watcher_list* w;
|
||||
uv_fs_event_t* h;
|
||||
QUEUE queue;
|
||||
@@ -205,7 +178,7 @@ static void uv__inotify_read(uv_loop_t* loop,
|
||||
/* needs to be large enough for sizeof(inotify_event) + strlen(path) */
|
||||
char buf[4096];
|
||||
|
||||
while (1) {
|
||||
for (;;) {
|
||||
do
|
||||
size = read(loop->inotify_fd, buf, sizeof(buf));
|
||||
while (size == -1 && errno == EINTR);
|
||||
@@ -219,12 +192,12 @@ static void uv__inotify_read(uv_loop_t* loop,
|
||||
|
||||
/* Now we have one or more inotify_event structs. */
|
||||
for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
|
||||
e = (const struct uv__inotify_event*)p;
|
||||
e = (const struct inotify_event*) p;
|
||||
|
||||
events = 0;
|
||||
if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY))
|
||||
if (e->mask & (IN_ATTRIB|IN_MODIFY))
|
||||
events |= UV_CHANGE;
|
||||
if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY))
|
||||
if (e->mask & ~(IN_ATTRIB|IN_MODIFY))
|
||||
events |= UV_RENAME;
|
||||
|
||||
w = find_watcher(loop, e->wd);
|
||||
@@ -290,16 +263,16 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
events = UV__IN_ATTRIB
|
||||
| UV__IN_CREATE
|
||||
| UV__IN_MODIFY
|
||||
| UV__IN_DELETE
|
||||
| UV__IN_DELETE_SELF
|
||||
| UV__IN_MOVE_SELF
|
||||
| UV__IN_MOVED_FROM
|
||||
| UV__IN_MOVED_TO;
|
||||
events = IN_ATTRIB
|
||||
| IN_CREATE
|
||||
| IN_MODIFY
|
||||
| IN_DELETE
|
||||
| IN_DELETE_SELF
|
||||
| IN_MOVE_SELF
|
||||
| IN_MOVED_FROM
|
||||
| IN_MOVED_TO;
|
||||
|
||||
wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events);
|
||||
wd = inotify_add_watch(handle->loop->inotify_fd, path, events);
|
||||
if (wd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
|
||||
@@ -26,19 +26,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
# define MSAN_ACTIVE 1
|
||||
# include <sanitizer/msan_interface.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
# ifndef __NR_socketcall
|
||||
# define __NR_socketcall 102
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__arm__)
|
||||
# if defined(__thumb__) || defined(__ARM_EABI__)
|
||||
# define UV_SYSCALL_BASE 0
|
||||
@@ -47,91 +34,9 @@
|
||||
# endif
|
||||
#endif /* __arm__ */
|
||||
|
||||
#ifndef __NR_accept4
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_accept4 288
|
||||
# elif defined(__i386__)
|
||||
/* Nothing. Handled through socketcall(). */
|
||||
# elif defined(__arm__)
|
||||
# define __NR_accept4 (UV_SYSCALL_BASE + 366)
|
||||
# endif
|
||||
#endif /* __NR_accept4 */
|
||||
|
||||
#ifndef __NR_eventfd
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_eventfd 284
|
||||
# elif defined(__i386__)
|
||||
# define __NR_eventfd 323
|
||||
# elif defined(__arm__)
|
||||
# define __NR_eventfd (UV_SYSCALL_BASE + 351)
|
||||
# endif
|
||||
#endif /* __NR_eventfd */
|
||||
|
||||
#ifndef __NR_eventfd2
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_eventfd2 290
|
||||
# elif defined(__i386__)
|
||||
# define __NR_eventfd2 328
|
||||
# elif defined(__arm__)
|
||||
# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
|
||||
# endif
|
||||
#endif /* __NR_eventfd2 */
|
||||
|
||||
#ifndef __NR_inotify_init
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_init 253
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_init 291
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
|
||||
# endif
|
||||
#endif /* __NR_inotify_init */
|
||||
|
||||
#ifndef __NR_inotify_init1
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_init1 294
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_init1 332
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
|
||||
# endif
|
||||
#endif /* __NR_inotify_init1 */
|
||||
|
||||
#ifndef __NR_inotify_add_watch
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_add_watch 254
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_add_watch 292
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
|
||||
# endif
|
||||
#endif /* __NR_inotify_add_watch */
|
||||
|
||||
#ifndef __NR_inotify_rm_watch
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_rm_watch 255
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_rm_watch 293
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
|
||||
# endif
|
||||
#endif /* __NR_inotify_rm_watch */
|
||||
|
||||
#ifndef __NR_pipe2
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_pipe2 293
|
||||
# elif defined(__i386__)
|
||||
# define __NR_pipe2 331
|
||||
# elif defined(__arm__)
|
||||
# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
|
||||
# endif
|
||||
#endif /* __NR_pipe2 */
|
||||
|
||||
#ifndef __NR_recvmmsg
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_recvmmsg 299
|
||||
# elif defined(__i386__)
|
||||
# define __NR_recvmmsg 337
|
||||
# elif defined(__arm__)
|
||||
# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
|
||||
# endif
|
||||
@@ -140,8 +45,6 @@
|
||||
#ifndef __NR_sendmmsg
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_sendmmsg 307
|
||||
# elif defined(__i386__)
|
||||
# define __NR_sendmmsg 345
|
||||
# elif defined(__arm__)
|
||||
# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
|
||||
# endif
|
||||
@@ -187,6 +90,24 @@
|
||||
# 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
|
||||
@@ -203,123 +124,69 @@
|
||||
# endif
|
||||
#endif /* __NR_statx */
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
|
||||
#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 r;
|
||||
int rc;
|
||||
|
||||
args[0] = (unsigned long) fd;
|
||||
args[1] = (unsigned long) addr;
|
||||
args[2] = (unsigned long) addrlen;
|
||||
args[3] = (unsigned long) flags;
|
||||
args[1] = (unsigned long) mmsg;
|
||||
args[2] = (unsigned long) vlen;
|
||||
args[3] = /* flags */ 0;
|
||||
|
||||
r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args);
|
||||
|
||||
/* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does
|
||||
* a bad flags argument. Try to distinguish between the two cases.
|
||||
*/
|
||||
if (r == -1)
|
||||
/* socketcall() raises EINVAL when SYS_SENDMMSG is not supported. */
|
||||
rc = syscall(/* __NR_socketcall */ 102, 20 /* SYS_SENDMMSG */, args);
|
||||
if (rc == -1)
|
||||
if (errno == EINVAL)
|
||||
if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0)
|
||||
errno = ENOSYS;
|
||||
errno = ENOSYS;
|
||||
|
||||
return r;
|
||||
#elif defined(__NR_accept4)
|
||||
return syscall(__NR_accept4, fd, addr, addrlen, flags);
|
||||
return rc;
|
||||
#elif defined(__NR_sendmmsg)
|
||||
return syscall(__NR_sendmmsg, fd, mmsg, vlen, /* flags */ 0);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__eventfd(unsigned int count) {
|
||||
#if defined(__NR_eventfd)
|
||||
return syscall(__NR_eventfd, count);
|
||||
#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;
|
||||
|
||||
int uv__eventfd2(unsigned int count, int flags) {
|
||||
#if defined(__NR_eventfd2)
|
||||
return syscall(__NR_eventfd2, count, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
/* 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;
|
||||
|
||||
|
||||
int uv__inotify_init(void) {
|
||||
#if defined(__NR_inotify_init)
|
||||
return syscall(__NR_inotify_init);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_init1(int flags) {
|
||||
#if defined(__NR_inotify_init1)
|
||||
return syscall(__NR_inotify_init1, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) {
|
||||
#if defined(__NR_inotify_add_watch)
|
||||
return syscall(__NR_inotify_add_watch, fd, path, mask);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_rm_watch(int fd, int32_t wd) {
|
||||
#if defined(__NR_inotify_rm_watch)
|
||||
return syscall(__NR_inotify_rm_watch, fd, wd);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__pipe2(int pipefd[2], int flags) {
|
||||
#if defined(__NR_pipe2)
|
||||
int result;
|
||||
result = syscall(__NR_pipe2, pipefd, flags);
|
||||
#if MSAN_ACTIVE
|
||||
if (!result)
|
||||
__msan_unpoison(pipefd, sizeof(int[2]));
|
||||
#endif
|
||||
return result;
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags) {
|
||||
#if defined(__NR_sendmmsg)
|
||||
return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__recvmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags,
|
||||
struct timespec* timeout) {
|
||||
#if defined(__NR_recvmmsg)
|
||||
return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
|
||||
return rc;
|
||||
#elif defined(__NR_recvmmsg)
|
||||
return syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
@@ -327,26 +194,48 @@ int uv__recvmmsg(int fd,
|
||||
|
||||
|
||||
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
|
||||
#if !defined(__NR_preadv) || defined(__ANDROID_API__) && __ANDROID_API__ < 24
|
||||
return errno = ENOSYS, -1;
|
||||
#else
|
||||
return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
|
||||
#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
|
||||
#if !defined(__NR_pwritev) || defined(__ANDROID_API__) && __ANDROID_API__ < 24
|
||||
return errno = ENOSYS, -1;
|
||||
#else
|
||||
return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__dup3(int oldfd, int newfd, int flags) {
|
||||
#if defined(__NR_dup3)
|
||||
#if !defined(__NR_dup3) || defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
return errno = ENOSYS, -1;
|
||||
#else
|
||||
return syscall(__NR_dup3, oldfd, newfd, flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
uv__fs_copy_file_range(int fd_in,
|
||||
off_t* off_in,
|
||||
int fd_out,
|
||||
off_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
|
||||
@@ -358,12 +247,18 @@ int uv__statx(int dirfd,
|
||||
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
|
||||
#if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30
|
||||
return errno = ENOSYS, -1;
|
||||
#else
|
||||
return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) {
|
||||
#if !defined(__NR_getrandom) || defined(__ANDROID_API__) && __ANDROID_API__ < 28
|
||||
return errno = ENOSYS, -1;
|
||||
#else
|
||||
return syscall(__NR_getrandom, buf, buflen, flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -22,64 +22,12 @@
|
||||
#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>
|
||||
|
||||
#if defined(__alpha__)
|
||||
# define UV__O_CLOEXEC 0x200000
|
||||
#elif defined(__hppa__)
|
||||
# define UV__O_CLOEXEC 0x200000
|
||||
#elif defined(__sparc__)
|
||||
# define UV__O_CLOEXEC 0x400000
|
||||
#else
|
||||
# define UV__O_CLOEXEC 0x80000
|
||||
#endif
|
||||
|
||||
#if defined(__alpha__)
|
||||
# define UV__O_NONBLOCK 0x4
|
||||
#elif defined(__hppa__)
|
||||
# define UV__O_NONBLOCK O_NONBLOCK
|
||||
#elif defined(__mips__)
|
||||
# define UV__O_NONBLOCK 0x80
|
||||
#elif defined(__sparc__)
|
||||
# define UV__O_NONBLOCK 0x4000
|
||||
#else
|
||||
# define UV__O_NONBLOCK 0x800
|
||||
#endif
|
||||
|
||||
#define UV__EFD_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__EFD_NONBLOCK UV__O_NONBLOCK
|
||||
|
||||
#define UV__IN_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__IN_NONBLOCK UV__O_NONBLOCK
|
||||
|
||||
#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
|
||||
#if defined(SOCK_NONBLOCK)
|
||||
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
|
||||
#else
|
||||
# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
|
||||
#endif
|
||||
|
||||
/* inotify flags */
|
||||
#define UV__IN_ACCESS 0x001
|
||||
#define UV__IN_MODIFY 0x002
|
||||
#define UV__IN_ATTRIB 0x004
|
||||
#define UV__IN_CLOSE_WRITE 0x008
|
||||
#define UV__IN_CLOSE_NOWRITE 0x010
|
||||
#define UV__IN_OPEN 0x020
|
||||
#define UV__IN_MOVED_FROM 0x040
|
||||
#define UV__IN_MOVED_TO 0x080
|
||||
#define UV__IN_CREATE 0x100
|
||||
#define UV__IN_DELETE 0x200
|
||||
#define UV__IN_DELETE_SELF 0x400
|
||||
#define UV__IN_MOVE_SELF 0x800
|
||||
|
||||
struct uv__statx_timestamp {
|
||||
int64_t tv_sec;
|
||||
uint32_t tv_nsec;
|
||||
@@ -110,43 +58,21 @@ struct uv__statx {
|
||||
uint64_t unused1[14];
|
||||
};
|
||||
|
||||
struct uv__inotify_event {
|
||||
int32_t wd;
|
||||
uint32_t mask;
|
||||
uint32_t cookie;
|
||||
uint32_t len;
|
||||
/* char name[0]; */
|
||||
};
|
||||
|
||||
struct uv__mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
unsigned int msg_len;
|
||||
};
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
|
||||
int uv__eventfd(unsigned int count);
|
||||
int uv__eventfd2(unsigned int count, int flags);
|
||||
int uv__inotify_init(void);
|
||||
int uv__inotify_init1(int flags);
|
||||
int uv__inotify_add_watch(int fd, const char* path, uint32_t mask);
|
||||
int uv__inotify_rm_watch(int fd, int32_t wd);
|
||||
int uv__pipe2(int pipefd[2], int flags);
|
||||
int uv__recvmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags,
|
||||
struct timespec* timeout);
|
||||
int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags);
|
||||
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,
|
||||
off_t* off_in,
|
||||
int fd_out,
|
||||
off_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_ */
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
void* saved_data;
|
||||
int err;
|
||||
|
||||
@@ -36,6 +37,15 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
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);
|
||||
@@ -66,7 +76,7 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
|
||||
err = uv__platform_loop_init(loop);
|
||||
if (err)
|
||||
return err;
|
||||
goto fail_platform_init;
|
||||
|
||||
uv__signal_global_once_init();
|
||||
err = uv_signal_init(loop, &loop->child_watcher);
|
||||
@@ -106,6 +116,15 @@ fail_rwlock_init:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -144,6 +163,8 @@ int uv_loop_fork(uv_loop_t* loop) {
|
||||
|
||||
|
||||
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);
|
||||
@@ -179,10 +200,23 @@ void uv__loop_close(uv_loop_t* loop) {
|
||||
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;
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ void uv_loadavg(double avg[3]) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return;
|
||||
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;
|
||||
@@ -102,7 +102,7 @@ uint64_t uv_get_free_memory(void) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_UVMEXP};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
|
||||
@@ -119,7 +119,7 @@ uint64_t uv_get_total_memory(void) {
|
||||
#endif
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
@@ -167,7 +167,7 @@ int uv_uptime(double* uptime) {
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
now = time(NULL);
|
||||
@@ -235,13 +235,25 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
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;
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
p = buf;
|
||||
while (len) {
|
||||
req = len < 32 ? len : 32;
|
||||
count = req;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
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;
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ 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;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ void uv_loadavg(double avg[3]) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
|
||||
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;
|
||||
@@ -61,7 +61,6 @@ void uv_loadavg(double avg[3]) {
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
int mib[4];
|
||||
char **argsbuf = NULL;
|
||||
char **argsbuf_tmp;
|
||||
size_t argsbuf_size = 100U;
|
||||
size_t exepath_size;
|
||||
pid_t mypid;
|
||||
@@ -73,15 +72,14 @@ int uv_exepath(char* buffer, size_t* size) {
|
||||
mypid = getpid();
|
||||
for (;;) {
|
||||
err = UV_ENOMEM;
|
||||
argsbuf_tmp = (char**)uv__realloc(argsbuf, argsbuf_size);
|
||||
if (argsbuf_tmp == NULL)
|
||||
argsbuf = (char**)uv__reallocf(argsbuf, argsbuf_size);
|
||||
if (argsbuf == NULL)
|
||||
goto out;
|
||||
argsbuf = argsbuf_tmp;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC_ARGS;
|
||||
mib[2] = mypid;
|
||||
mib[3] = KERN_PROC_ARGV;
|
||||
if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) {
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), argsbuf, &argsbuf_size, NULL, 0) == 0) {
|
||||
break;
|
||||
}
|
||||
if (errno != ENOMEM) {
|
||||
@@ -117,7 +115,7 @@ uint64_t uv_get_free_memory(void) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_UVMEXP};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
|
||||
@@ -129,7 +127,7 @@ uint64_t uv_get_total_memory(void) {
|
||||
int which[] = {CTL_HW, HW_PHYSMEM64};
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
@@ -154,7 +152,7 @@ int uv_resident_set_memory(size_t* rss) {
|
||||
mib[4] = sizeof(struct kinfo_proc);
|
||||
mib[5] = 1;
|
||||
|
||||
if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0)
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &size, NULL, 0) < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*rss = kinfo.p_vm_rssize * page_size;
|
||||
@@ -168,7 +166,7 @@ int uv_uptime(double* uptime) {
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
now = time(NULL);
|
||||
@@ -184,43 +182,38 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
uint64_t info[CPUSTATES];
|
||||
char model[512];
|
||||
int numcpus = 1;
|
||||
int which[] = {CTL_HW,HW_MODEL,0};
|
||||
int which[] = {CTL_HW,HW_MODEL};
|
||||
int percpu[] = {CTL_KERN,KERN_CPTIME2,0};
|
||||
size_t size;
|
||||
int i;
|
||||
int i, j;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctl(which, 2, &model, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &model, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
which[1] = HW_NCPU;
|
||||
which[1] = HW_NCPUONLINE;
|
||||
size = sizeof(numcpus);
|
||||
if (sysctl(which, 2, &numcpus, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &numcpus, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*cpu_infos = (uv_cpu_info_t*)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, 2, &cpuspeed, &size, NULL, 0)) {
|
||||
uv__free(*cpu_infos);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0))
|
||||
goto error;
|
||||
|
||||
size = sizeof(info);
|
||||
which[0] = CTL_KERN;
|
||||
which[1] = KERN_CPTIME2;
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
which[2] = i;
|
||||
size = sizeof(info);
|
||||
if (sysctl(which, 3, &info, &size, NULL, 0)) {
|
||||
uv__free(*cpu_infos);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
percpu[2] = i;
|
||||
if (sysctl(percpu, ARRAY_SIZE(percpu), &info, &size, NULL, 0))
|
||||
goto error;
|
||||
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
|
||||
@@ -235,15 +228,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -91,12 +91,16 @@ err_socket:
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
if (uv__stream_fd(handle) == -1)
|
||||
return UV_EINVAL;
|
||||
|
||||
#if defined(__MVS__)
|
||||
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)
|
||||
@@ -261,7 +265,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
addrlen = strlen(sa.sun_path);
|
||||
|
||||
|
||||
if (addrlen >= *size) {
|
||||
if ((size_t)addrlen >= *size) {
|
||||
*size = addrlen + 1;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
@@ -375,3 +379,57 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||
|
||||
return r != -1 ? 0 : UV__ERR(errno);
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) {
|
||||
uv_os_fd_t temp[2];
|
||||
int err;
|
||||
#if defined(__FreeBSD__) || defined(__linux__)
|
||||
int flags = O_CLOEXEC;
|
||||
|
||||
if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE))
|
||||
flags |= UV_FS_O_NONBLOCK;
|
||||
|
||||
if (pipe2(temp, flags))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (flags & UV_FS_O_NONBLOCK) {
|
||||
fds[0] = temp[0];
|
||||
fds[1] = temp[1];
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if (pipe(temp))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if ((err = uv__cloexec(temp[0], 1)))
|
||||
goto fail;
|
||||
|
||||
if ((err = uv__cloexec(temp[1], 1)))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
if (read_flags & UV_NONBLOCK_PIPE)
|
||||
if ((err = uv__nonblock(temp[0], 1)))
|
||||
goto fail;
|
||||
|
||||
if (write_flags & UV_NONBLOCK_PIPE)
|
||||
if ((err = uv__nonblock(temp[1], 1)))
|
||||
goto fail;
|
||||
|
||||
fds[0] = temp[0];
|
||||
fds[1] = temp[1];
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
uv__close(temp[0]);
|
||||
uv__close(temp[1]);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int uv__make_pipe(int fds[2], int flags) {
|
||||
return uv_pipe(fds,
|
||||
flags & UV_NONBLOCK_PIPE,
|
||||
flags & UV_NONBLOCK_PIPE);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
||||
* Workaround for e.g. kqueue fds not supporting ioctls.
|
||||
*/
|
||||
err = uv__nonblock(fd, 1);
|
||||
#ifdef UV__NONBLOCK_IS_IOCTL
|
||||
#if UV__NONBLOCK_IS_IOCTL
|
||||
if (err == UV_ENOTTY)
|
||||
err = uv__nonblock_fcntl(fd, 1);
|
||||
#endif
|
||||
@@ -117,12 +117,21 @@ int uv_poll_stop(uv_poll_t* handle) {
|
||||
|
||||
|
||||
int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
|
||||
void** watchers;
|
||||
uv__io_t* w;
|
||||
int events;
|
||||
|
||||
assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
|
||||
UV_PRIORITIZED)) == 0);
|
||||
assert(!uv__is_closing(handle));
|
||||
|
||||
watchers = handle->loop->watchers;
|
||||
w = &handle->io_watcher;
|
||||
|
||||
if (uv__fd_exists(handle->loop, w->fd))
|
||||
if (watchers[w->fd] != w)
|
||||
return UV_EEXIST;
|
||||
|
||||
uv__poll_stop(handle);
|
||||
|
||||
if (pevents == 0)
|
||||
|
||||
@@ -61,7 +61,7 @@ static void uv__pollfds_maybe_resize(uv_loop_t* loop) {
|
||||
return;
|
||||
|
||||
n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;
|
||||
p = (struct pollfd*)uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds));
|
||||
p = (struct pollfd*)uv__reallocf(loop->poll_fds, n * sizeof(*loop->poll_fds));
|
||||
if (p == NULL)
|
||||
abort();
|
||||
|
||||
@@ -144,6 +144,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
int have_signals;
|
||||
struct pollfd* pe;
|
||||
int fd;
|
||||
int user_timeout;
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
@@ -177,11 +179,25 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
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();
|
||||
@@ -197,6 +213,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
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;
|
||||
}
|
||||
@@ -205,6 +230,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
if (errno != EINTR)
|
||||
abort();
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
@@ -254,6 +284,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
if (w == &loop->signal_io_watcher) {
|
||||
have_signals = 1;
|
||||
} else {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
w->cb(loop, w, pe->revents);
|
||||
}
|
||||
|
||||
@@ -261,8 +292,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
}
|
||||
}
|
||||
|
||||
if (have_signals != 0)
|
||||
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;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,28 +24,27 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void uv__set_process_title_platform_init(void);
|
||||
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 struct {
|
||||
char* str;
|
||||
size_t len;
|
||||
} process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
#ifdef __APPLE__
|
||||
uv__set_process_title_platform_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
struct uv__process_title pt;
|
||||
char** new_argv;
|
||||
size_t size;
|
||||
char* s;
|
||||
@@ -54,20 +53,14 @@ char** uv_setup_args(int argc, char** argv) {
|
||||
if (argc <= 0)
|
||||
return argv;
|
||||
|
||||
/* Calculate how much memory we need for the argv strings. */
|
||||
size = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
size += strlen(argv[i]) + 1;
|
||||
pt.str = argv[0];
|
||||
pt.len = strlen(argv[0]);
|
||||
pt.cap = pt.len + 1;
|
||||
|
||||
#if defined(__MVS__)
|
||||
/* argv is not adjacent. So just use argv[0] */
|
||||
process_title.str = argv[0];
|
||||
process_title.len = strlen(argv[0]);
|
||||
#else
|
||||
process_title.str = argv[0];
|
||||
process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
|
||||
assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
|
||||
#endif
|
||||
/* 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*);
|
||||
@@ -75,32 +68,56 @@ char** uv_setup_args(int argc, char** argv) {
|
||||
new_argv = (char**)uv__malloc(size);
|
||||
if (new_argv == NULL)
|
||||
return argv;
|
||||
args_mem = new_argv;
|
||||
|
||||
/* Copy over the strings and set up the pointer table. */
|
||||
i = 0;
|
||||
s = (char*) &new_argv[argc + 1];
|
||||
for (i = 0; i < argc; i++) {
|
||||
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;
|
||||
|
||||
pt.cap = argv[i - 1] + size - argv[0];
|
||||
|
||||
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 (process_title.len != 0) {
|
||||
/* No need to terminate, byte after is always '\0'. */
|
||||
strncpy(process_title.str, title, process_title.len);
|
||||
uv__set_process_title(title);
|
||||
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__set_process_title(pt->str);
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
@@ -111,6 +128,10 @@ 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);
|
||||
|
||||
@@ -130,7 +151,7 @@ int uv_get_process_title(char* buffer, size_t size) {
|
||||
}
|
||||
|
||||
|
||||
UV_DESTRUCTOR(static void free_args_mem(void)) {
|
||||
void uv__process_title_cleanup(void) {
|
||||
uv__free(args_mem); /* Keep valgrind happy. */
|
||||
args_mem = NULL;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
*/
|
||||
|
||||
/* Android versions < 4.1 have a broken pthread_sigmask. */
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
@@ -38,13 +40,13 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
|
||||
static int workaround;
|
||||
int err;
|
||||
|
||||
if (workaround) {
|
||||
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) {
|
||||
workaround = 1;
|
||||
uv__store_relaxed(&workaround, 1);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
|
||||
93
wpinet/src/main/native/thirdparty/libuv/src/unix/random-devurandom.cpp
vendored
Normal file
93
wpinet/src/main/native/thirdparty/libuv/src/unix/random-devurandom.cpp
vendored
Normal 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);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright libuv project contributors. All rights reserved.
|
||||
/* 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
|
||||
@@ -22,15 +22,36 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <stddef.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct sysinfo info;
|
||||
typedef int (*uv__getentropy_cb)(void *, size_t);
|
||||
|
||||
if (sysinfo(&info) < 0) return;
|
||||
static uv__getentropy_cb uv__getentropy;
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
|
||||
avg[0] = (double) info.loads[0] / 65536.0;
|
||||
avg[1] = (double) info.loads[1] / 65536.0;
|
||||
avg[2] = (double) info.loads[2] / 65536.0;
|
||||
|
||||
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
wpinet/src/main/native/thirdparty/libuv/src/unix/random-getrandom.cpp
vendored
Normal file
88
wpinet/src/main/native/thirdparty/libuv/src/unix/random-getrandom.cpp
vendored
Normal 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;
|
||||
}
|
||||
99
wpinet/src/main/native/thirdparty/libuv/src/unix/random-sysctl-linux.cpp
vendored
Normal file
99
wpinet/src/main/native/thirdparty/libuv/src/unix/random-sysctl-linux.cpp
vendored
Normal 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 = (char*)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;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ static void uv__signal_global_init(void) {
|
||||
}
|
||||
|
||||
|
||||
UV_DESTRUCTOR(static void uv__signal_global_fini(void)) {
|
||||
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
|
||||
@@ -98,7 +98,7 @@ UV_DESTRUCTOR(static void uv__signal_global_fini(void)) {
|
||||
|
||||
|
||||
static void uv__signal_global_reinit(void) {
|
||||
uv__signal_global_fini();
|
||||
uv__signal_cleanup();
|
||||
|
||||
if (uv__make_pipe(uv__signal_lock_pipefd, 0))
|
||||
abort();
|
||||
@@ -143,6 +143,8 @@ static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
|
||||
if (sigfillset(&new_mask))
|
||||
abort();
|
||||
|
||||
/* to shut up valgrind */
|
||||
sigemptyset(saved_sigmask);
|
||||
if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
|
||||
abort();
|
||||
|
||||
@@ -263,7 +265,7 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
|
||||
if (loop->signal_pipefd[0] != -1)
|
||||
return 0;
|
||||
|
||||
err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
|
||||
err = uv__make_pipe(loop->signal_pipefd, UV_NONBLOCK_PIPE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -331,16 +333,7 @@ int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
|
||||
|
||||
void uv__signal_close(uv_signal_t* handle) {
|
||||
|
||||
uv__signal_stop(handle);
|
||||
|
||||
/* If there are any caught signals "trapped" in the signal pipe, we can't
|
||||
* call the close callback yet. Otherwise, add the handle to the finish_close
|
||||
* queue.
|
||||
*/
|
||||
if (handle->caught_signals == handle->dispatched_signals) {
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -472,15 +465,6 @@ static void uv__signal_event(uv_loop_t* loop,
|
||||
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT)
|
||||
uv__signal_stop(handle);
|
||||
|
||||
/* If uv_close was called while there were caught signals that were not
|
||||
* yet dispatched, the uv__finish_close was deferred. Make close pending
|
||||
* now if this has happened.
|
||||
*/
|
||||
if ((handle->flags & UV_HANDLE_CLOSING) &&
|
||||
(handle->caught_signals == handle->dispatched_signals)) {
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
bytes -= end;
|
||||
@@ -563,7 +547,7 @@ static void uv__signal_stop(uv_signal_t* handle) {
|
||||
if (first_oneshot && !rem_oneshot) {
|
||||
ret = uv__signal_register_handler(handle->signum, 1);
|
||||
assert(ret == 0);
|
||||
(void) ret;
|
||||
(void)ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,20 +58,6 @@ struct uv__stream_select_s {
|
||||
fd_set* swrite;
|
||||
size_t swrite_sz;
|
||||
};
|
||||
|
||||
/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
|
||||
* EPROTOTYPE can be returned while trying to write to a socket that is
|
||||
* shutting down. If we retry the write, we should get the expected EPIPE
|
||||
* instead.
|
||||
*/
|
||||
# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE)
|
||||
# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \
|
||||
(errno == EMSGSIZE && send_handle != NULL))
|
||||
#else
|
||||
# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR)
|
||||
# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
static void uv__stream_connect(uv_stream_t*);
|
||||
@@ -164,7 +150,7 @@ static void uv__stream_osx_select(void* arg) {
|
||||
else
|
||||
max_fd = s->int_fd;
|
||||
|
||||
while (1) {
|
||||
for (;;) {
|
||||
/* Terminate on semaphore */
|
||||
if (uv_sem_trywait(&s->close_sem) == 0)
|
||||
break;
|
||||
@@ -195,7 +181,7 @@ static void uv__stream_osx_select(void* arg) {
|
||||
|
||||
/* Empty socketpair's buffer in case of interruption */
|
||||
if (FD_ISSET(s->int_fd, s->sread))
|
||||
while (1) {
|
||||
for (;;) {
|
||||
r = read(s->int_fd, buf, sizeof(buf));
|
||||
|
||||
if (r == sizeof(buf))
|
||||
@@ -658,11 +644,11 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
|
||||
|
||||
switch (stream->type) {
|
||||
case UV_TCP:
|
||||
err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
|
||||
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);
|
||||
err = uv__pipe_listen((uv_pipe_t*)stream, backlog, cb);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -799,33 +785,21 @@ static int uv__handle_fd(uv_handle_t* handle) {
|
||||
}
|
||||
}
|
||||
|
||||
static void uv__write(uv_stream_t* stream) {
|
||||
static int uv__try_write(uv_stream_t* stream,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
uv_stream_t* send_handle) {
|
||||
struct iovec* iov;
|
||||
QUEUE* q;
|
||||
uv_write_t* req;
|
||||
int iovmax;
|
||||
int iovcnt;
|
||||
ssize_t n;
|
||||
int err;
|
||||
|
||||
start:
|
||||
|
||||
assert(uv__stream_fd(stream) >= 0);
|
||||
|
||||
if (QUEUE_EMPTY(&stream->write_queue))
|
||||
return;
|
||||
|
||||
q = QUEUE_HEAD(&stream->write_queue);
|
||||
req = QUEUE_DATA(q, uv_write_t, queue);
|
||||
assert(req->handle == stream);
|
||||
|
||||
/*
|
||||
* Cast to iovec. We had to have our own uv_buf_t instead of iovec
|
||||
* because Windows's WSABUF is not an iovec.
|
||||
*/
|
||||
assert(sizeof(uv_buf_t) == sizeof(struct iovec));
|
||||
iov = (struct iovec*) &(req->bufs[req->write_index]);
|
||||
iovcnt = req->nbufs - req->write_index;
|
||||
iov = (struct iovec*) bufs;
|
||||
iovcnt = nbufs;
|
||||
|
||||
iovmax = uv__getiovmax();
|
||||
|
||||
@@ -837,8 +811,7 @@ start:
|
||||
* Now do the actual writev. Note that we've been updating the pointers
|
||||
* inside the iov each time we write. So there is no need to offset it.
|
||||
*/
|
||||
|
||||
if (req->send_handle) {
|
||||
if (send_handle != NULL) {
|
||||
int fd_to_send;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
@@ -847,12 +820,10 @@ start:
|
||||
struct cmsghdr alias;
|
||||
} scratch;
|
||||
|
||||
if (uv__is_closing(req->send_handle)) {
|
||||
err = UV_EBADF;
|
||||
goto error;
|
||||
}
|
||||
if (uv__is_closing(send_handle))
|
||||
return UV_EBADF;
|
||||
|
||||
fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
|
||||
fd_to_send = uv__handle_fd((uv_handle_t*) send_handle);
|
||||
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
|
||||
@@ -881,45 +852,83 @@ start:
|
||||
|
||||
do
|
||||
n = sendmsg(uv__stream_fd(stream), &msg, 0);
|
||||
while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
|
||||
|
||||
/* Ensure the handle isn't sent again in case this is a partial write. */
|
||||
if (n >= 0)
|
||||
req->send_handle = NULL;
|
||||
while (n == -1 && errno == EINTR);
|
||||
} else {
|
||||
do
|
||||
n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
|
||||
while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
|
||||
while (n == -1 && errno == EINTR);
|
||||
}
|
||||
|
||||
if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) {
|
||||
err = UV__ERR(errno);
|
||||
goto error;
|
||||
if (n >= 0)
|
||||
return n;
|
||||
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
return UV_EAGAIN;
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* macOS versions 10.10 and 10.15 - and presumbaly 10.11 to 10.14, too -
|
||||
* have a bug where a race condition causes the kernel to return EPROTOTYPE
|
||||
* because the socket isn't fully constructed. It's probably the result of
|
||||
* the peer closing the connection and that is why libuv translates it to
|
||||
* ECONNRESET. Previously, libuv retried until the EPROTOTYPE error went
|
||||
* away but some VPN software causes the same behavior except the error is
|
||||
* permanent, not transient, turning the retry mechanism into an infinite
|
||||
* loop. See https://github.com/libuv/libuv/pull/482.
|
||||
*/
|
||||
if (errno == EPROTOTYPE)
|
||||
return UV_ECONNRESET;
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
static void uv__write(uv_stream_t* stream) {
|
||||
QUEUE* q;
|
||||
uv_write_t* req;
|
||||
ssize_t n;
|
||||
|
||||
assert(uv__stream_fd(stream) >= 0);
|
||||
|
||||
for (;;) {
|
||||
if (QUEUE_EMPTY(&stream->write_queue))
|
||||
return;
|
||||
|
||||
q = QUEUE_HEAD(&stream->write_queue);
|
||||
req = QUEUE_DATA(q, uv_write_t, queue);
|
||||
assert(req->handle == stream);
|
||||
|
||||
n = uv__try_write(stream,
|
||||
&(req->bufs[req->write_index]),
|
||||
req->nbufs - req->write_index,
|
||||
req->send_handle);
|
||||
|
||||
/* Ensure the handle isn't sent again in case this is a partial write. */
|
||||
if (n >= 0) {
|
||||
req->send_handle = NULL;
|
||||
if (uv__write_req_update(stream, req, n)) {
|
||||
uv__write_req_finish(req);
|
||||
return; /* TODO(bnoordhuis) Start trying to write the next request. */
|
||||
}
|
||||
} else if (n != UV_EAGAIN)
|
||||
break;
|
||||
|
||||
/* If this is a blocking stream, try again. */
|
||||
if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
|
||||
continue;
|
||||
|
||||
/* We're not done. */
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
|
||||
/* Notify select() thread about state change */
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (n >= 0 && uv__write_req_update(stream, req, n)) {
|
||||
uv__write_req_finish(req);
|
||||
return; /* TODO(bnoordhuis) Start trying to write the next request. */
|
||||
}
|
||||
|
||||
/* If this is a blocking stream, try again. */
|
||||
if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
|
||||
goto start;
|
||||
|
||||
/* We're not done. */
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
|
||||
/* Notify select() thread about state change */
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
req->error = err;
|
||||
req->error = n;
|
||||
// XXX(jwn): this must call uv__stream_flush_write_queue(stream, n) here, since we won't generate any more events
|
||||
uv__write_req_finish(req);
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLIN))
|
||||
uv__handle_stop(stream);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
}
|
||||
|
||||
@@ -1009,12 +1018,11 @@ uv_handle_type uv__handle_type(int fd) {
|
||||
|
||||
static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
|
||||
stream->flags |= UV_HANDLE_READ_EOF;
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__handle_stop(stream);
|
||||
uv__handle_stop(stream);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
stream->read_cb(stream, UV_EOF, buf);
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
}
|
||||
|
||||
|
||||
@@ -1058,7 +1066,12 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
|
||||
}
|
||||
|
||||
|
||||
#define UV__CMSG_FD_COUNT 64
|
||||
#if defined(__PASE__)
|
||||
/* on IBMi PASE the control message length can not exceed 256. */
|
||||
# define UV__CMSG_FD_COUNT 60
|
||||
#else
|
||||
# define UV__CMSG_FD_COUNT 64
|
||||
#endif
|
||||
#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int))
|
||||
|
||||
|
||||
@@ -1193,12 +1206,12 @@ static void uv__read(uv_stream_t* stream) {
|
||||
#endif
|
||||
} else {
|
||||
/* Error. User should call uv_close(). */
|
||||
stream->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
stream->read_cb(stream, UV__ERR(errno), &buf);
|
||||
if (stream->flags & UV_HANDLE_READING) {
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__handle_stop(stream);
|
||||
uv__handle_stop(stream);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
}
|
||||
}
|
||||
@@ -1281,6 +1294,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
|
||||
req->cb = cb;
|
||||
stream->shutdown_req = req;
|
||||
stream->flags |= UV_HANDLE_SHUTTING;
|
||||
stream->flags &= ~UV_HANDLE_WRITABLE;
|
||||
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
@@ -1395,14 +1409,9 @@ static void uv__stream_connect(uv_stream_t* stream) {
|
||||
}
|
||||
|
||||
|
||||
int uv_write2(uv_write_t* req,
|
||||
uv_stream_t* stream,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
uv_stream_t* send_handle,
|
||||
uv_write_cb cb) {
|
||||
int empty_queue;
|
||||
|
||||
static int uv__check_before_write(uv_stream_t* stream,
|
||||
unsigned int nbufs,
|
||||
uv_stream_t* send_handle) {
|
||||
assert(nbufs > 0);
|
||||
assert((stream->type == UV_TCP ||
|
||||
stream->type == UV_NAMED_PIPE ||
|
||||
@@ -1413,9 +1422,9 @@ int uv_write2(uv_write_t* req,
|
||||
return UV_EBADF;
|
||||
|
||||
if (!(stream->flags & UV_HANDLE_WRITABLE))
|
||||
return -EPIPE;
|
||||
return UV_EPIPE;
|
||||
|
||||
if (send_handle) {
|
||||
if (send_handle != NULL) {
|
||||
if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc)
|
||||
return UV_EINVAL;
|
||||
|
||||
@@ -1435,6 +1444,22 @@ int uv_write2(uv_write_t* req,
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_write2(uv_write_t* req,
|
||||
uv_stream_t* stream,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
uv_stream_t* send_handle,
|
||||
uv_write_cb cb) {
|
||||
int empty_queue;
|
||||
int err;
|
||||
|
||||
err = uv__check_before_write(stream, nbufs, send_handle);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* It's legal for write_queue_size > 0 even when the write_queue is empty;
|
||||
* it means there are error-state requests in the write_completed_queue that
|
||||
* will touch up write_queue_size later, see also uv__write_req_finish().
|
||||
@@ -1503,81 +1528,43 @@ int uv_write(uv_write_t* req,
|
||||
}
|
||||
|
||||
|
||||
void uv_try_write_cb(uv_write_t* req, int status) {
|
||||
/* Should not be called */
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_try_write(uv_stream_t* stream,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs) {
|
||||
int r;
|
||||
int has_pollout;
|
||||
size_t written;
|
||||
size_t req_size;
|
||||
uv_write_t req;
|
||||
return uv_try_write2(stream, bufs, nbufs, NULL);
|
||||
}
|
||||
|
||||
|
||||
int uv_try_write2(uv_stream_t* stream,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
uv_stream_t* send_handle) {
|
||||
int err;
|
||||
|
||||
/* Connecting or already writing some data */
|
||||
if (stream->connect_req != NULL || stream->write_queue_size != 0)
|
||||
return UV_EAGAIN;
|
||||
|
||||
has_pollout = uv__io_active(&stream->io_watcher, POLLOUT);
|
||||
err = uv__check_before_write(stream, nbufs, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Remove not written bytes from write queue size */
|
||||
written = uv__count_bufs(bufs, nbufs);
|
||||
if (req.bufs != NULL)
|
||||
req_size = uv__write_req_size(&req);
|
||||
else
|
||||
req_size = 0;
|
||||
written -= req_size;
|
||||
stream->write_queue_size -= req_size;
|
||||
|
||||
/* Unqueue request, regardless of immediateness */
|
||||
QUEUE_REMOVE(&req.queue);
|
||||
uv__req_unregister(stream->loop, &req);
|
||||
if (req.bufs != req.bufsml)
|
||||
uv__free(req.bufs);
|
||||
req.bufs = NULL;
|
||||
|
||||
/* Do not poll for writable, if we wasn't before calling this */
|
||||
if (!has_pollout) {
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
}
|
||||
|
||||
if (written == 0 && req_size != 0)
|
||||
return req.error < 0 ? req.error : UV_EAGAIN;
|
||||
else
|
||||
return written;
|
||||
return uv__try_write(stream, bufs, nbufs, send_handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_read_start(uv_stream_t* stream,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb) {
|
||||
int uv__read_start(uv_stream_t* stream,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb) {
|
||||
assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
|
||||
stream->type == UV_TTY);
|
||||
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (!(stream->flags & UV_HANDLE_READABLE))
|
||||
return -ENOTCONN;
|
||||
|
||||
/* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
|
||||
* expresses the desired state of the user.
|
||||
*/
|
||||
/* The UV_HANDLE_READING flag is irrelevant of the state of the stream - it
|
||||
* just expresses the desired state of the user. */
|
||||
stream->flags |= UV_HANDLE_READING;
|
||||
stream->flags &= ~UV_HANDLE_READ_EOF;
|
||||
|
||||
/* TODO: try to do the read inline? */
|
||||
/* TODO: keep track of tcp state. If we've gotten a EOF then we should
|
||||
* not start the IO watcher.
|
||||
*/
|
||||
assert(uv__stream_fd(stream) >= 0);
|
||||
assert(alloc_cb);
|
||||
|
||||
@@ -1598,8 +1585,7 @@ int uv_read_stop(uv_stream_t* stream) {
|
||||
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__handle_stop(stream);
|
||||
uv__handle_stop(stream);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
|
||||
stream->read_cb = NULL;
|
||||
|
||||
@@ -214,14 +214,15 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
if (handle->connect_req != NULL)
|
||||
return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
|
||||
|
||||
if (handle->delayed_error != 0)
|
||||
goto out;
|
||||
|
||||
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);
|
||||
@@ -249,6 +250,8 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
uv__req_init(handle->loop, req, UV_CONNECT);
|
||||
req->cb = cb;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
@@ -308,17 +311,37 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
static int single_accept = -1;
|
||||
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)
|
||||
@@ -362,8 +385,16 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
|
||||
return UV__ERR(errno);
|
||||
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
|
||||
return UV__ERR(errno);
|
||||
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,
|
||||
@@ -431,3 +462,49 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
|
||||
void uv__tcp_close(uv_tcp_t* handle) {
|
||||
uv__stream_close((uv_stream_t*)handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
|
||||
uv_os_sock_t temp[2];
|
||||
int err;
|
||||
#if defined(__FreeBSD__) || defined(__linux__)
|
||||
int flags;
|
||||
|
||||
flags = type | SOCK_CLOEXEC;
|
||||
if ((flags0 & UV_NONBLOCK_PIPE) && (flags1 & UV_NONBLOCK_PIPE))
|
||||
flags |= SOCK_NONBLOCK;
|
||||
|
||||
if (socketpair(AF_UNIX, flags, protocol, temp))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (flags & UV_FS_O_NONBLOCK) {
|
||||
fds[0] = temp[0];
|
||||
fds[1] = temp[1];
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if (socketpair(AF_UNIX, type, protocol, temp))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if ((err = uv__cloexec(temp[0], 1)))
|
||||
goto fail;
|
||||
if ((err = uv__cloexec(temp[1], 1)))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
if (flags0 & UV_NONBLOCK_PIPE)
|
||||
if ((err = uv__nonblock(temp[0], 1)))
|
||||
goto fail;
|
||||
if (flags1 & UV_NONBLOCK_PIPE)
|
||||
if ((err = uv__nonblock(temp[1], 1)))
|
||||
goto fail;
|
||||
|
||||
fds[0] = temp[0];
|
||||
fds[1] = temp[1];
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
uv__close(temp[0]);
|
||||
uv__close(temp[1]);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -107,8 +107,7 @@ int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
}
|
||||
|
||||
last = (--b->out == 0);
|
||||
if (!last)
|
||||
uv_cond_signal(&b->cond); /* Not needed for last thread. */
|
||||
uv_cond_signal(&b->cond);
|
||||
|
||||
uv_mutex_unlock(&b->mutex);
|
||||
return last;
|
||||
@@ -121,9 +120,10 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
uv_mutex_lock(&b->mutex);
|
||||
|
||||
assert(b->in == 0);
|
||||
assert(b->out == 0);
|
||||
while (b->out != 0)
|
||||
uv_cond_wait(&b->cond, &b->mutex);
|
||||
|
||||
if (b->in != 0 || b->out != 0)
|
||||
if (b->in != 0)
|
||||
abort();
|
||||
|
||||
uv_mutex_unlock(&b->mutex);
|
||||
@@ -161,40 +161,33 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
#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.
|
||||
/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
|
||||
* too small to safely receive signals on.
|
||||
*
|
||||
* On Linux, threads created by musl have a much smaller stack than threads
|
||||
* 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.
|
||||
*/
|
||||
static size_t uv__min_stack_size(void) {
|
||||
static const size_t min = 8192;
|
||||
|
||||
#ifdef PTHREAD_STACK_MIN /* Not defined on NetBSD. */
|
||||
if (min < (size_t) PTHREAD_STACK_MIN)
|
||||
return PTHREAD_STACK_MIN;
|
||||
#endif /* PTHREAD_STACK_MIN */
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
if (getrlimit(RLIMIT_STACK, &lim))
|
||||
abort();
|
||||
|
||||
if (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 >= (rlim_t) PTHREAD_STACK_MIN)
|
||||
return lim.rlim_cur;
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t uv__default_stack_size(void) {
|
||||
#if !defined(__linux__)
|
||||
return 0;
|
||||
#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
|
||||
@@ -205,6 +198,34 @@ static size_t thread_stack_size(void) {
|
||||
}
|
||||
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
size_t uv__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 (getrlimit(RLIMIT_STACK, &lim))
|
||||
return uv__default_stack_size();
|
||||
|
||||
if (lim.rlim_cur == RLIM_INFINITY)
|
||||
return uv__default_stack_size();
|
||||
|
||||
/* pthread_attr_setstacksize() expects page-aligned values. */
|
||||
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
|
||||
|
||||
if (lim.rlim_cur >= (rlim_t) uv__min_stack_size())
|
||||
return lim.rlim_cur;
|
||||
#endif
|
||||
|
||||
return uv__default_stack_size();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -220,21 +241,21 @@ int uv_thread_create_ex(uv_thread_t* tid,
|
||||
pthread_attr_t attr_storage;
|
||||
size_t pagesize;
|
||||
size_t stack_size;
|
||||
size_t min_stack_size;
|
||||
|
||||
stack_size =
|
||||
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
|
||||
|
||||
attr = NULL;
|
||||
if (stack_size == 0) {
|
||||
stack_size = thread_stack_size();
|
||||
stack_size = uv__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 < (size_t) PTHREAD_STACK_MIN)
|
||||
stack_size = PTHREAD_STACK_MIN;
|
||||
#endif
|
||||
min_stack_size = uv__min_stack_size();
|
||||
if (stack_size < min_stack_size)
|
||||
stack_size = min_stack_size;
|
||||
}
|
||||
|
||||
if (stack_size > 0) {
|
||||
@@ -700,11 +721,9 @@ int uv_cond_init(uv_cond_t* cond) {
|
||||
if (err)
|
||||
return UV__ERR(err);
|
||||
|
||||
#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21)
|
||||
err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
||||
if (err)
|
||||
goto error2;
|
||||
#endif
|
||||
|
||||
err = pthread_cond_init(cond, &attr);
|
||||
if (err)
|
||||
@@ -796,16 +815,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
#endif
|
||||
ts.tv_sec = timeout / NANOSEC;
|
||||
ts.tv_nsec = timeout % NANOSEC;
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
|
||||
/*
|
||||
* The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
|
||||
* but has this alternative function instead.
|
||||
*/
|
||||
r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
|
||||
#else
|
||||
r = pthread_cond_timedwait(cond, mutex, &ts);
|
||||
#endif /* __ANDROID_API__ */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,34 @@
|
||||
#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;
|
||||
@@ -140,7 +168,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
|
||||
* peripheral device.
|
||||
*/
|
||||
if (uv__tty_is_peripheral(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
|
||||
r = uv__open_cloexec(path, mode);
|
||||
r = uv__open_cloexec(path, mode | O_NOCTTY);
|
||||
else
|
||||
r = -1;
|
||||
|
||||
@@ -215,6 +243,24 @@ static void uv__tty_make_raw(struct termios* tio) {
|
||||
tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
tio->c_cflag &= ~(CSIZE | PARENB);
|
||||
tio->c_cflag |= CS8;
|
||||
|
||||
/*
|
||||
* By default, most software expects a pending read to block until at
|
||||
* least one byte becomes available. As per termio(7I), this requires
|
||||
* setting the MIN and TIME parameters appropriately.
|
||||
*
|
||||
* As a somewhat unfortunate artifact of history, the MIN and TIME slots
|
||||
* in the control character array overlap with the EOF and EOL slots used
|
||||
* for canonical mode processing. Because the EOF character needs to be
|
||||
* the ASCII EOT value (aka Control-D), it has the byte value 4. When
|
||||
* switching to raw mode, this is interpreted as a MIN value of 4; i.e.,
|
||||
* reads will block until at least four bytes have been input.
|
||||
*
|
||||
* Other platforms with a distinct MIN slot like Linux and FreeBSD appear
|
||||
* to default to a MIN value of 1, so we'll force that value here:
|
||||
*/
|
||||
tio->c_cc[VMIN] = 1;
|
||||
tio->c_cc[VTIME] = 0;
|
||||
#else
|
||||
cfmakeraw(tio);
|
||||
#endif /* #ifdef __sun */
|
||||
@@ -366,3 +412,10 @@ int uv_tty_reset_mode(void) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@
|
||||
# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
|
||||
#endif
|
||||
|
||||
union uv__sockaddr {
|
||||
struct sockaddr_in6 in6;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr addr;
|
||||
};
|
||||
|
||||
static void uv__udp_run_completed(uv_udp_t* handle);
|
||||
static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
|
||||
@@ -49,6 +54,36 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
|
||||
int domain,
|
||||
unsigned int flags);
|
||||
|
||||
#if HAVE_MMSG
|
||||
|
||||
#define UV__MMSG_MAXWIDTH 20
|
||||
|
||||
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf);
|
||||
static void uv__udp_sendmmsg(uv_udp_t* handle);
|
||||
|
||||
static int uv__recvmmsg_avail;
|
||||
static int uv__sendmmsg_avail;
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
|
||||
static void uv__udp_mmsg_init(void) {
|
||||
int ret;
|
||||
int s;
|
||||
s = uv__socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0)
|
||||
return;
|
||||
ret = uv__sendmmsg(s, NULL, 0);
|
||||
if (ret == 0 || errno != ENOSYS) {
|
||||
uv__sendmmsg_avail = 1;
|
||||
uv__recvmmsg_avail = 1;
|
||||
} else {
|
||||
ret = uv__recvmmsg(s, NULL, 0);
|
||||
if (ret == 0 || errno != ENOSYS)
|
||||
uv__recvmmsg_avail = 1;
|
||||
}
|
||||
uv__close(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void uv__udp_close(uv_udp_t* handle) {
|
||||
uv__io_close(handle->loop, &handle->io_watcher);
|
||||
@@ -148,6 +183,65 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_MMSG
|
||||
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
||||
struct sockaddr_in6 peers[UV__MMSG_MAXWIDTH];
|
||||
struct iovec iov[UV__MMSG_MAXWIDTH];
|
||||
struct uv__mmsghdr msgs[UV__MMSG_MAXWIDTH];
|
||||
ssize_t nread;
|
||||
uv_buf_t chunk_buf;
|
||||
size_t chunks;
|
||||
int flags;
|
||||
size_t k;
|
||||
|
||||
/* prepare structures for recvmmsg */
|
||||
chunks = buf->len / UV__UDP_DGRAM_MAXSIZE;
|
||||
if (chunks > ARRAY_SIZE(iov))
|
||||
chunks = ARRAY_SIZE(iov);
|
||||
for (k = 0; k < chunks; ++k) {
|
||||
iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE;
|
||||
iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE;
|
||||
memset(&msgs[k].msg_hdr, 0, sizeof(msgs[k].msg_hdr));
|
||||
msgs[k].msg_hdr.msg_iov = iov + k;
|
||||
msgs[k].msg_hdr.msg_iovlen = 1;
|
||||
msgs[k].msg_hdr.msg_name = peers + k;
|
||||
msgs[k].msg_hdr.msg_namelen = sizeof(peers[0]);
|
||||
msgs[k].msg_hdr.msg_control = NULL;
|
||||
msgs[k].msg_hdr.msg_controllen = 0;
|
||||
msgs[k].msg_hdr.msg_flags = 0;
|
||||
}
|
||||
|
||||
do
|
||||
nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks);
|
||||
while (nread == -1 && errno == EINTR);
|
||||
|
||||
if (nread < 1) {
|
||||
if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
handle->recv_cb(handle, 0, buf, NULL, 0);
|
||||
else
|
||||
handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0);
|
||||
} else {
|
||||
/* pass each chunk to the application */
|
||||
for (k = 0; k < (size_t) nread && handle->recv_cb != NULL; k++) {
|
||||
flags = UV_UDP_MMSG_CHUNK;
|
||||
if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC)
|
||||
flags |= UV_UDP_PARTIAL;
|
||||
|
||||
chunk_buf = uv_buf_init((char*) iov[k].iov_base, iov[k].iov_len);
|
||||
handle->recv_cb(handle,
|
||||
msgs[k].msg_len,
|
||||
&chunk_buf,
|
||||
(const sockaddr*) msgs[k].msg_hdr.msg_name,
|
||||
flags);
|
||||
}
|
||||
|
||||
/* one last callback so the original buffer is freed */
|
||||
if (handle->recv_cb != NULL)
|
||||
handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE);
|
||||
}
|
||||
return nread;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
struct sockaddr_storage peer;
|
||||
@@ -165,18 +259,27 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
*/
|
||||
count = 32;
|
||||
|
||||
memset(&h, 0, sizeof(h));
|
||||
h.msg_name = &peer;
|
||||
|
||||
do {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
|
||||
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
return;
|
||||
}
|
||||
assert(buf.base != NULL);
|
||||
|
||||
#if HAVE_MMSG
|
||||
if (uv_udp_using_recvmmsg(handle)) {
|
||||
nread = uv__udp_recvmmsg(handle, &buf);
|
||||
if (nread > 0)
|
||||
count -= nread;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&h, 0, sizeof(h));
|
||||
memset(&peer, 0, sizeof(peer));
|
||||
h.msg_name = &peer;
|
||||
h.msg_namelen = sizeof(peer);
|
||||
h.msg_iov = (iovec*) &buf;
|
||||
h.msg_iovlen = 1;
|
||||
@@ -193,33 +296,129 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
handle->recv_cb(handle, UV__ERR(errno), &buf, NULL, 0);
|
||||
}
|
||||
else {
|
||||
const struct sockaddr *addr;
|
||||
if (h.msg_namelen == 0)
|
||||
addr = NULL;
|
||||
else
|
||||
addr = (const struct sockaddr*) &peer;
|
||||
|
||||
flags = 0;
|
||||
if (h.msg_flags & MSG_TRUNC)
|
||||
flags |= UV_UDP_PARTIAL;
|
||||
|
||||
handle->recv_cb(handle, nread, &buf, addr, flags);
|
||||
handle->recv_cb(handle, nread, &buf, (const struct sockaddr*) &peer, flags);
|
||||
}
|
||||
count--;
|
||||
}
|
||||
/* recv_cb callback may decide to pause or close the handle */
|
||||
while (nread != -1
|
||||
&& count-- > 0
|
||||
&& count > 0
|
||||
&& handle->io_watcher.fd != -1
|
||||
&& handle->recv_cb != NULL);
|
||||
}
|
||||
|
||||
#if HAVE_MMSG
|
||||
static void uv__udp_sendmmsg(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
struct uv__mmsghdr h[UV__MMSG_MAXWIDTH];
|
||||
struct uv__mmsghdr *p;
|
||||
QUEUE* q;
|
||||
ssize_t npkts;
|
||||
size_t pkts;
|
||||
size_t i;
|
||||
|
||||
if (QUEUE_EMPTY(&handle->write_queue))
|
||||
return;
|
||||
|
||||
write_queue_drain:
|
||||
for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue);
|
||||
pkts < UV__MMSG_MAXWIDTH && q != &handle->write_queue;
|
||||
++pkts, q = QUEUE_HEAD(q)) {
|
||||
assert(q != NULL);
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
p = &h[pkts];
|
||||
memset(p, 0, sizeof(*p));
|
||||
if (req->addr.ss_family == AF_UNSPEC) {
|
||||
p->msg_hdr.msg_name = NULL;
|
||||
p->msg_hdr.msg_namelen = 0;
|
||||
} else {
|
||||
p->msg_hdr.msg_name = &req->addr;
|
||||
if (req->addr.ss_family == AF_INET6)
|
||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
else if (req->addr.ss_family == AF_INET)
|
||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
|
||||
else if (req->addr.ss_family == AF_UNIX)
|
||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un);
|
||||
else {
|
||||
assert(0 && "unsupported address family");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs;
|
||||
h[pkts].msg_hdr.msg_iovlen = req->nbufs;
|
||||
}
|
||||
|
||||
do
|
||||
npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts);
|
||||
while (npkts == -1 && errno == EINTR);
|
||||
|
||||
if (npkts < 1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
return;
|
||||
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
|
||||
i < pkts && q != &handle->write_queue;
|
||||
++i, q = QUEUE_HEAD(&handle->write_queue)) {
|
||||
assert(q != NULL);
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
req->status = UV__ERR(errno);
|
||||
QUEUE_REMOVE(&req->queue);
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
}
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Safety: npkts known to be >0 below. Hence cast from ssize_t
|
||||
* to size_t safe.
|
||||
*/
|
||||
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
|
||||
i < (size_t)npkts && q != &handle->write_queue;
|
||||
++i, q = QUEUE_HEAD(&handle->write_queue)) {
|
||||
assert(q != NULL);
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
req->status = req->bufs[0].len;
|
||||
|
||||
/* Sending a datagram is an atomic operation: either all data
|
||||
* is written or nothing is (and EMSGSIZE is raised). That is
|
||||
* why we don't handle partial writes. Just pop the request
|
||||
* off the write queue and onto the completed queue, done.
|
||||
*/
|
||||
QUEUE_REMOVE(&req->queue);
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
}
|
||||
|
||||
/* couldn't batch everything, continue sending (jump to avoid stack growth) */
|
||||
if (!QUEUE_EMPTY(&handle->write_queue))
|
||||
goto write_queue_drain;
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
QUEUE* q;
|
||||
struct msghdr h;
|
||||
QUEUE* q;
|
||||
ssize_t size;
|
||||
|
||||
#if HAVE_MMSG
|
||||
uv_once(&once, uv__udp_mmsg_init);
|
||||
if (uv__sendmmsg_avail) {
|
||||
uv__udp_sendmmsg(handle);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_queue);
|
||||
assert(q != NULL);
|
||||
@@ -269,7 +468,6 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
|
||||
* refinements for programs that use multicast.
|
||||
*
|
||||
@@ -297,7 +495,7 @@ static int uv__set_reuse(int fd) {
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#elif defined(SO_REUSEPORT) && !defined(__linux__)
|
||||
#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
@@ -308,6 +506,28 @@ static int uv__set_reuse(int fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Linux kernel suppresses some ICMP error messages by default for UDP
|
||||
* sockets. Setting IP_RECVERR/IPV6_RECVERR on the socket enables full ICMP
|
||||
* error reporting, hopefully resulting in faster failover to working name
|
||||
* servers.
|
||||
*/
|
||||
static int uv__set_recverr(int fd, sa_family_t ss_family) {
|
||||
#if defined(__linux__)
|
||||
int yes;
|
||||
|
||||
yes = 1;
|
||||
if (ss_family == AF_INET) {
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_RECVERR, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
} else if (ss_family == AF_INET6) {
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVERR, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_bind(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
@@ -318,7 +538,7 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
int fd;
|
||||
|
||||
/* Check for bad flags. */
|
||||
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR))
|
||||
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | UV_UDP_LINUX_RECVERR))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Cannot set IPv6-only mode on non-IPv6 socket. */
|
||||
@@ -334,6 +554,12 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
handle->io_watcher.fd = fd;
|
||||
}
|
||||
|
||||
if (flags & UV_UDP_LINUX_RECVERR) {
|
||||
err = uv__set_recverr(fd, addr->sa_family);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & UV_UDP_REUSEADDR) {
|
||||
err = uv__set_reuse(fd);
|
||||
if (err)
|
||||
@@ -373,11 +599,7 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
|
||||
int domain,
|
||||
unsigned int flags) {
|
||||
union {
|
||||
struct sockaddr_in6 in6;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr addr;
|
||||
} taddr;
|
||||
union uv__sockaddr taddr;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (handle->io_watcher.fd != -1)
|
||||
@@ -433,28 +655,71 @@ int uv__udp_connect(uv_udp_t* handle,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html
|
||||
* Any of uv supported UNIXs kernel should be standardized, but the kernel
|
||||
* implementation logic not same, let's use pseudocode to explain the udp
|
||||
* disconnect behaviors:
|
||||
*
|
||||
* Predefined stubs for pseudocode:
|
||||
* 1. sodisconnect: The function to perform the real udp disconnect
|
||||
* 2. pru_connect: The function to perform the real udp connect
|
||||
* 3. so: The kernel object match with socket fd
|
||||
* 4. addr: The sockaddr parameter from user space
|
||||
*
|
||||
* BSDs:
|
||||
* if(sodisconnect(so) == 0) { // udp disconnect succeed
|
||||
* if (addr->sa_len != so->addr->sa_len) return EINVAL;
|
||||
* if (addr->sa_family != so->addr->sa_family) return EAFNOSUPPORT;
|
||||
* pru_connect(so);
|
||||
* }
|
||||
* else return EISCONN;
|
||||
*
|
||||
* z/OS (same with Windows):
|
||||
* if(addr->sa_len < so->addr->sa_len) return EINVAL;
|
||||
* if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
|
||||
*
|
||||
* AIX:
|
||||
* if(addr->sa_len != sizeof(struct sockaddr)) return EINVAL; // ignore ip proto version
|
||||
* if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
|
||||
*
|
||||
* Linux,Others:
|
||||
* if(addr->sa_len < sizeof(struct sockaddr)) return EINVAL;
|
||||
* if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
|
||||
*/
|
||||
int uv__udp_disconnect(uv_udp_t* handle) {
|
||||
int r;
|
||||
#if defined(__MVS__)
|
||||
struct sockaddr_storage addr;
|
||||
#else
|
||||
struct sockaddr addr;
|
||||
#endif
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
#if defined(__MVS__)
|
||||
addr.ss_family = AF_UNSPEC;
|
||||
#else
|
||||
addr.sa_family = AF_UNSPEC;
|
||||
#endif
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
r = connect(handle->io_watcher.fd, &addr, sizeof(addr));
|
||||
r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr));
|
||||
} while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1 && errno != EAFNOSUPPORT)
|
||||
if (r == -1) {
|
||||
#if defined(BSD) /* The macro BSD is from sys/param.h */
|
||||
if (errno != EAFNOSUPPORT && errno != EINVAL)
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_send(uv_udp_send_t* req,
|
||||
uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
@@ -659,26 +924,118 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
|
||||
int domain;
|
||||
#if !defined(__OpenBSD__) && \
|
||||
!defined(__NetBSD__) && \
|
||||
!defined(__ANDROID__) && \
|
||||
!defined(__DragonFly__) && \
|
||||
!defined(__QNX__) && \
|
||||
!defined(__GNU__)
|
||||
static int uv__udp_set_source_membership4(uv_udp_t* handle,
|
||||
const struct sockaddr_in* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const struct sockaddr_in* source_addr,
|
||||
uv_membership membership) {
|
||||
struct ip_mreq_source mreq;
|
||||
int optname;
|
||||
int err;
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
|
||||
if (interface_addr != NULL) {
|
||||
err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
|
||||
mreq.imr_sourceaddr.s_addr = source_addr->sin_addr.s_addr;
|
||||
|
||||
if (membership == UV_JOIN_GROUP)
|
||||
optname = IP_ADD_SOURCE_MEMBERSHIP;
|
||||
else if (membership == UV_LEAVE_GROUP)
|
||||
optname = IP_DROP_SOURCE_MEMBERSHIP;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IP,
|
||||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__udp_set_source_membership6(uv_udp_t* handle,
|
||||
const struct sockaddr_in6* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const struct sockaddr_in6* source_addr,
|
||||
uv_membership membership) {
|
||||
struct group_source_req mreq;
|
||||
struct sockaddr_in6 addr6;
|
||||
int optname;
|
||||
int err;
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
|
||||
if (interface_addr != NULL) {
|
||||
err = uv_ip6_addr(interface_addr, 0, &addr6);
|
||||
if (err)
|
||||
return err;
|
||||
mreq.gsr_interface = addr6.sin6_scope_id;
|
||||
} else {
|
||||
mreq.gsr_interface = 0;
|
||||
}
|
||||
|
||||
STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
|
||||
STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
|
||||
memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
|
||||
memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
|
||||
|
||||
if (membership == UV_JOIN_GROUP)
|
||||
optname = MCAST_JOIN_SOURCE_GROUP;
|
||||
else if (membership == UV_LEAVE_GROUP)
|
||||
optname = MCAST_LEAVE_SOURCE_GROUP;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IPV6,
|
||||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int uv__udp_init_ex(uv_loop_t* loop,
|
||||
uv_udp_t* handle,
|
||||
unsigned flags,
|
||||
int domain) {
|
||||
int fd;
|
||||
|
||||
/* 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;
|
||||
|
||||
fd = -1;
|
||||
if (domain != AF_UNSPEC) {
|
||||
err = uv__socket(domain, SOCK_DGRAM, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
fd = err;
|
||||
} else {
|
||||
fd = -1;
|
||||
fd = uv__socket(domain, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
}
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
|
||||
@@ -694,8 +1051,14 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
|
||||
int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
|
||||
#if HAVE_MMSG
|
||||
if (handle->flags & UV_HANDLE_UDP_RECVMMSG) {
|
||||
uv_once(&once, uv__udp_mmsg_init);
|
||||
return uv__recvmmsg_avail;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -748,11 +1111,56 @@ int uv_udp_set_membership(uv_udp_t* handle,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_source_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const char* source_addr,
|
||||
uv_membership membership) {
|
||||
#if !defined(__OpenBSD__) && \
|
||||
!defined(__NetBSD__) && \
|
||||
!defined(__ANDROID__) && \
|
||||
!defined(__DragonFly__) && \
|
||||
!defined(__QNX__) && \
|
||||
!defined(__GNU__)
|
||||
int err;
|
||||
union uv__sockaddr mcast_addr;
|
||||
union uv__sockaddr src_addr;
|
||||
|
||||
err = uv_ip4_addr(multicast_addr, 0, &mcast_addr.in);
|
||||
if (err) {
|
||||
err = uv_ip6_addr(multicast_addr, 0, &mcast_addr.in6);
|
||||
if (err)
|
||||
return err;
|
||||
err = uv_ip6_addr(source_addr, 0, &src_addr.in6);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_source_membership6(handle,
|
||||
&mcast_addr.in6,
|
||||
interface_addr,
|
||||
&src_addr.in6,
|
||||
membership);
|
||||
}
|
||||
|
||||
err = uv_ip4_addr(source_addr, 0, &src_addr.in);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_source_membership4(handle,
|
||||
&mcast_addr.in,
|
||||
interface_addr,
|
||||
&src_addr.in,
|
||||
membership);
|
||||
#else
|
||||
return UV_ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int uv__setsockopt(uv_udp_t* handle,
|
||||
int option4,
|
||||
int option6,
|
||||
const void* val,
|
||||
size_t size) {
|
||||
socklen_t size) {
|
||||
int r;
|
||||
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
@@ -821,7 +1229,7 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
|
||||
* and use the general uv__setsockopt_maybe_char call on other platforms.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
defined(__MVS__) || defined(__QNX__)
|
||||
|
||||
return uv__setsockopt(handle,
|
||||
IP_TTL,
|
||||
@@ -830,7 +1238,7 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
|
||||
sizeof(ttl));
|
||||
|
||||
#else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
|
||||
defined(__MVS__)) */
|
||||
defined(__MVS__) || defined(__QNX__)) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_TTL,
|
||||
@@ -838,7 +1246,7 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
|
||||
ttl);
|
||||
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
|
||||
defined(__MVS__) */
|
||||
defined(__MVS__) || defined(__QNX__) */
|
||||
}
|
||||
|
||||
|
||||
@@ -850,7 +1258,7 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
defined(__MVS__) || defined(__QNX__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
@@ -858,7 +1266,7 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__) */
|
||||
defined(__MVS__) || defined(__QNX__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
@@ -875,7 +1283,7 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
defined(__MVS__) || defined(__QNX__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
@@ -883,7 +1291,7 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
|
||||
&on,
|
||||
sizeof(on));
|
||||
#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) ||
|
||||
defined(__MVS__) */
|
||||
defined(__MVS__) || defined(__QNX__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
|
||||
@@ -100,6 +100,17 @@ void* uv__realloc(void* ptr, size_t size) {
|
||||
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,
|
||||
@@ -211,6 +222,9 @@ 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));
|
||||
}
|
||||
|
||||
@@ -260,6 +274,20 @@ int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
|
||||
}
|
||||
|
||||
|
||||
int uv_ip_name(const struct sockaddr *src, char *dst, size_t size) {
|
||||
switch (src->sa_family) {
|
||||
case AF_INET:
|
||||
return uv_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr,
|
||||
dst, size);
|
||||
case AF_INET6:
|
||||
return uv_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr,
|
||||
dst, size);
|
||||
default:
|
||||
return UV_EAFNOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_bind(uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int flags) {
|
||||
@@ -279,6 +307,36 @@ int uv_tcp_bind(uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
@@ -804,3 +862,127 @@ void uv_loop_delete(uv_loop_t* loop) {
|
||||
if (loop != default_loop)
|
||||
uv__free(loop);
|
||||
}
|
||||
|
||||
|
||||
int uv_read_start(uv_stream_t* stream,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb) {
|
||||
if (stream == NULL || alloc_cb == NULL || read_cb == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (stream->flags & UV_HANDLE_READING)
|
||||
return UV_EALREADY;
|
||||
|
||||
if (!(stream->flags & UV_HANDLE_READABLE))
|
||||
return UV_ENOTCONN;
|
||||
|
||||
return uv__read_start(stream, alloc_cb, read_cb);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* Also covers __clang__ and __INTEL_COMPILER. Disabled on Windows because
|
||||
* threads have already been forcibly terminated by the operating system
|
||||
* by the time destructors run, ergo, it's not safe to try to clean them up.
|
||||
*/
|
||||
#if defined(__GNUC__) && !defined(_WIN32)
|
||||
__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();
|
||||
#ifdef __MVS__
|
||||
/* TODO(itodorov) - zos: revisit when Woz compiler is available. */
|
||||
uv__os390_cleanup();
|
||||
#else
|
||||
uv__threadpool_cleanup();
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,16 @@ extern int snprintf(char*, size_t, const char*, ...);
|
||||
#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
|
||||
|
||||
#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)
|
||||
|
||||
/* Handle flags. Some flags are specific to Windows or UNIX. */
|
||||
enum {
|
||||
/* Used by all handles. */
|
||||
@@ -98,12 +108,12 @@ enum {
|
||||
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,
|
||||
UV_HANDLE_SHARED_TCP_SOCKET = 0x10000000,
|
||||
|
||||
/* 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,
|
||||
@@ -120,13 +130,20 @@ enum {
|
||||
UV_SIGNAL_ONE_SHOT = 0x02000000,
|
||||
|
||||
/* Only used by uv_poll_t handles. */
|
||||
UV_HANDLE_POLL_SLOW = 0x01000000
|
||||
UV_HANDLE_POLL_SLOW = 0x01000000,
|
||||
|
||||
/* Only used by uv_process_t handles. */
|
||||
UV_HANDLE_REAP = 0x10000000
|
||||
};
|
||||
|
||||
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__read_start(uv_stream_t* stream,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb);
|
||||
|
||||
int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
@@ -138,6 +155,11 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
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,
|
||||
@@ -200,6 +222,10 @@ 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)
|
||||
|
||||
@@ -315,6 +341,12 @@ void uv__timer_close(uv_timer_t* handle);
|
||||
} \
|
||||
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);
|
||||
@@ -322,5 +354,23 @@ 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_ */
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/* 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) {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
|
||||
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));
|
||||
@@ -54,9 +54,9 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
|
||||
}
|
||||
|
||||
|
||||
void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
|
||||
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__want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
|
||||
uv__handle_closing(handle);
|
||||
@@ -83,7 +83,7 @@ int uv_async_send(uv_async_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
void uv_process_async_wakeup_req(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) {
|
||||
assert(handle->type == UV_ASYNC);
|
||||
assert(req->type == UV_WAKEUP);
|
||||
@@ -91,7 +91,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
|
||||
handle->async_sent = 0;
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
} else if (handle->async_cb != NULL) {
|
||||
handle->async_cb(handle);
|
||||
}
|
||||
|
||||
@@ -39,10 +39,11 @@ static char INLINE uv__atomic_exchange_set(char volatile* target) {
|
||||
return _InterlockedOr8(target, 1);
|
||||
}
|
||||
|
||||
#else /* GCC */
|
||||
#else /* GCC, Clang in mingw mode */
|
||||
|
||||
/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
|
||||
static inline char uv__atomic_exchange_set(char volatile* target) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
|
||||
const char one = 1;
|
||||
char old_value;
|
||||
__asm__ __volatile__ ("lock xchgb %0, %1\n\t"
|
||||
@@ -50,6 +51,9 @@ static inline char uv__atomic_exchange_set(char volatile* target) {
|
||||
: "0"(one), "m"(*target)
|
||||
: "memory");
|
||||
return old_value;
|
||||
#else
|
||||
return __sync_fetch_and_or(target, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -84,10 +84,12 @@ 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;
|
||||
@@ -116,6 +118,7 @@ failed_loops_realloc:
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
|
||||
static void uv__loops_remove(uv_loop_t* loop) {
|
||||
int loop_index;
|
||||
int smaller_capacity;
|
||||
@@ -175,7 +178,7 @@ void uv__wake_all_loops(void) {
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
static void uv_init(void) {
|
||||
static void uv__init(void) {
|
||||
/* Tell Windows that we will handle critical errors. */
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||
SEM_NOOPENFILEERRORBOX);
|
||||
@@ -201,19 +204,19 @@ static void uv_init(void) {
|
||||
/* Fetch winapi function pointers. This must be done first because other
|
||||
* initialization code might need these function pointers to be loaded.
|
||||
*/
|
||||
uv_winapi_init();
|
||||
uv__winapi_init();
|
||||
|
||||
/* Initialize winsock */
|
||||
uv_winsock_init();
|
||||
uv__winsock_init();
|
||||
|
||||
/* Initialize FS */
|
||||
uv_fs_init();
|
||||
uv__fs_init();
|
||||
|
||||
/* Initialize signal stuff */
|
||||
uv_signals_init();
|
||||
uv__signals_init();
|
||||
|
||||
/* Initialize console */
|
||||
uv_console_init();
|
||||
uv__console_init();
|
||||
|
||||
/* Initialize utilities */
|
||||
uv__util_init();
|
||||
@@ -224,6 +227,7 @@ static void uv_init(void) {
|
||||
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
struct heap* timer_heap;
|
||||
int err;
|
||||
|
||||
@@ -235,6 +239,15 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
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.
|
||||
*/
|
||||
@@ -299,6 +312,11 @@ fail_mutex_init:
|
||||
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;
|
||||
|
||||
@@ -314,17 +332,23 @@ void uv_update_time(uv_loop_t* loop) {
|
||||
|
||||
|
||||
void uv__once_init(void) {
|
||||
uv_once(&uv_init_guard_, uv_init);
|
||||
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 */
|
||||
assert(!loop->wq_async.async_sent);
|
||||
/* 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);
|
||||
@@ -344,11 +368,24 @@ void uv__loop_close(uv_loop_t* loop) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -363,23 +400,28 @@ int uv_loop_fork(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
static int uv__loop_alive(const uv_loop_t* loop) {
|
||||
return uv__has_active_handles(loop) ||
|
||||
uv__has_active_reqs(loop) ||
|
||||
loop->pending_reqs_tail != NULL ||
|
||||
loop->endgame_handles != NULL;
|
||||
}
|
||||
|
||||
|
||||
int uv_loop_alive(const uv_loop_t* loop) {
|
||||
return uv__loop_alive(loop);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
if (loop->stop_flag == 0 &&
|
||||
/* uv__loop_alive(loop) && */
|
||||
(uv__has_active_handles(loop) || uv__has_active_reqs(loop)) &&
|
||||
loop->pending_reqs_tail == NULL &&
|
||||
loop->idle_handles == NULL &&
|
||||
loop->endgame_handles == NULL)
|
||||
return uv__next_timeout(loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -390,20 +432,48 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
||||
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);
|
||||
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.
|
||||
@@ -442,16 +512,44 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
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++) {
|
||||
success = GetQueuedCompletionStatusEx(loop->iocp,
|
||||
overlappeds,
|
||||
ARRAY_SIZE(overlappeds),
|
||||
&count,
|
||||
timeout,
|
||||
FALSE);
|
||||
/* 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++) {
|
||||
@@ -459,8 +557,8 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
* meant only to wake us up.
|
||||
*/
|
||||
if (overlappeds[i].lpOverlapped) {
|
||||
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
req = uv__overlapped_to_req(overlappeds[i].lpOverlapped);
|
||||
uv__insert_pending_req(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,18 +591,6 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -518,9 +604,9 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
uv_update_time(loop);
|
||||
uv__run_timers(loop);
|
||||
|
||||
ran_pending = uv_process_reqs(loop);
|
||||
uv_idle_invoke(loop);
|
||||
uv_prepare_invoke(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)
|
||||
@@ -531,9 +617,15 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
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);
|
||||
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
|
||||
@@ -544,6 +636,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
|
||||
* the check.
|
||||
*/
|
||||
uv_update_time(loop);
|
||||
uv__run_timers(loop);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/* 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"
|
||||
|
||||
@@ -72,6 +72,8 @@ int uv_translate_sys_error(int 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_ACCESS_DENIED: return UV_EACCES;
|
||||
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
|
||||
case WSAEADDRINUSE: return UV_EADDRINUSE;
|
||||
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
|
||||
@@ -104,7 +106,6 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
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;
|
||||
@@ -132,6 +133,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
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;
|
||||
@@ -153,7 +155,6 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
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;
|
||||
@@ -166,6 +167,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
|
||||
case ERROR_INVALID_FUNCTION: return UV_EISDIR;
|
||||
case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
|
||||
case WSAESOCKTNOSUPPORT: return UV_ESOCKTNOSUPPORT;
|
||||
default: return UV_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const unsigned int uv_directory_watcher_buffer_size = 4096;
|
||||
|
||||
|
||||
static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
|
||||
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);
|
||||
@@ -59,15 +59,15 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
|
||||
NULL)) {
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(&handle->req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
|
||||
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) {
|
||||
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);
|
||||
@@ -82,9 +82,10 @@ static void uv_relative_path(const WCHAR* filename,
|
||||
(*relpath)[relpathlen] = L'\0';
|
||||
}
|
||||
|
||||
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
|
||||
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)
|
||||
@@ -99,12 +100,16 @@ static int uv_split_path(const WCHAR* filename, WCHAR** dir,
|
||||
|
||||
if (i == 0) {
|
||||
if (dir) {
|
||||
*dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
|
||||
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(MAX_PATH, *dir)) {
|
||||
if (!GetCurrentDirectoryW(dir_len, *dir)) {
|
||||
uv__free(*dir);
|
||||
*dir = NULL;
|
||||
return -1;
|
||||
@@ -157,9 +162,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
int name_size, is_path_dir, size;
|
||||
DWORD attr, last_error;
|
||||
WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
|
||||
WCHAR short_path_buffer[MAX_PATH];
|
||||
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;
|
||||
|
||||
@@ -232,20 +239,30 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
*/
|
||||
|
||||
/* 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 = (WCHAR*)uv__malloc(short_path_buffer_len * sizeof(WCHAR));
|
||||
if (short_path_buffer == NULL) {
|
||||
goto short_path_done;
|
||||
}
|
||||
if (GetShortPathNameW(pathw,
|
||||
short_path_buffer,
|
||||
ARRAY_SIZE(short_path_buffer))) {
|
||||
short_path = short_path_buffer;
|
||||
} else {
|
||||
short_path = NULL;
|
||||
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) {
|
||||
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) {
|
||||
if (uv__split_path(short_path, NULL, &handle->short_filew) != 0) {
|
||||
last_error = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
@@ -348,6 +365,8 @@ error:
|
||||
if (uv__is_active(handle))
|
||||
uv__handle_stop(handle);
|
||||
|
||||
uv__free(short_path);
|
||||
|
||||
return uv_translate_sys_error(last_error);
|
||||
}
|
||||
|
||||
@@ -406,7 +425,7 @@ static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
|
||||
}
|
||||
|
||||
|
||||
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
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;
|
||||
@@ -425,7 +444,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
*/
|
||||
if (!uv__is_active(handle)) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
uv__want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -498,9 +517,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
|
||||
if (long_filenamew) {
|
||||
/* Get the file name out of the long path. */
|
||||
uv_relative_path(long_filenamew,
|
||||
handle->dirw,
|
||||
&filenamew);
|
||||
uv__relative_path(long_filenamew,
|
||||
handle->dirw,
|
||||
&filenamew);
|
||||
uv__free(long_filenamew);
|
||||
long_filenamew = filenamew;
|
||||
sizew = -1;
|
||||
@@ -557,27 +576,27 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* 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);
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
} else if (uv__is_active(handle)) {
|
||||
uv__fs_event_queue_readdirchanges(loop, handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_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);
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_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));
|
||||
|
||||
|
||||
200
wpinet/src/main/native/thirdparty/libuv/src/win/fs-fd-hash-inl.h
vendored
Normal file
200
wpinet/src/main/native/thirdparty/libuv/src/win/fs-fd-hash-inl.h
vendored
Normal 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 =
|
||||
(struct uv__fd_hash_entry_group_s*)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_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@
|
||||
\
|
||||
if (handle->flags & UV_HANDLE_CLOSING && \
|
||||
handle->reqs_pending == 0) { \
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle); \
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
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;
|
||||
|
||||
@@ -95,7 +95,7 @@ INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
INLINE static void uv_process_endgames(uv_loop_t* loop) {
|
||||
INLINE static void uv__process_endgames(uv_loop_t* loop) {
|
||||
uv_handle_t* handle;
|
||||
|
||||
while (loop->endgame_handles) {
|
||||
@@ -106,23 +106,23 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
|
||||
|
||||
switch (handle->type) {
|
||||
case UV_TCP:
|
||||
uv_tcp_endgame(loop, (uv_tcp_t*) handle);
|
||||
uv__tcp_endgame(loop, (uv_tcp_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
uv_pipe_endgame(loop, (uv_pipe_t*) handle);
|
||||
uv__pipe_endgame(loop, (uv_pipe_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_TTY:
|
||||
uv_tty_endgame(loop, (uv_tty_t*) handle);
|
||||
uv__tty_endgame(loop, (uv_tty_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_UDP:
|
||||
uv_udp_endgame(loop, (uv_udp_t*) handle);
|
||||
uv__udp_endgame(loop, (uv_udp_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_POLL:
|
||||
uv_poll_endgame(loop, (uv_poll_t*) handle);
|
||||
uv__poll_endgame(loop, (uv_poll_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_TIMER:
|
||||
@@ -133,23 +133,23 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
|
||||
case UV_PREPARE:
|
||||
case UV_CHECK:
|
||||
case UV_IDLE:
|
||||
uv_loop_watcher_endgame(loop, handle);
|
||||
uv__loop_watcher_endgame(loop, handle);
|
||||
break;
|
||||
|
||||
case UV_ASYNC:
|
||||
uv_async_endgame(loop, (uv_async_t*) handle);
|
||||
uv__async_endgame(loop, (uv_async_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_SIGNAL:
|
||||
uv_signal_endgame(loop, (uv_signal_t*) handle);
|
||||
uv__signal_endgame(loop, (uv_signal_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_PROCESS:
|
||||
uv_process_endgame(loop, (uv_process_t*) handle);
|
||||
uv__process_endgame(loop, (uv_process_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_FS_EVENT:
|
||||
uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
|
||||
uv__fs_event_endgame(loop, (uv_fs_event_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_FS_POLL:
|
||||
|
||||
@@ -77,63 +77,63 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
|
||||
/* Handle-specific close actions */
|
||||
switch (handle->type) {
|
||||
case UV_TCP:
|
||||
uv_tcp_close(loop, (uv_tcp_t*)handle);
|
||||
uv__tcp_close(loop, (uv_tcp_t*)handle);
|
||||
return;
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
uv_pipe_close(loop, (uv_pipe_t*) handle);
|
||||
uv__pipe_close(loop, (uv_pipe_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_TTY:
|
||||
uv_tty_close((uv_tty_t*) handle);
|
||||
uv__tty_close((uv_tty_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_UDP:
|
||||
uv_udp_close(loop, (uv_udp_t*) handle);
|
||||
uv__udp_close(loop, (uv_udp_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_POLL:
|
||||
uv_poll_close(loop, (uv_poll_t*) handle);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
uv__want_endgame(loop, handle);
|
||||
return;
|
||||
|
||||
case UV_ASYNC:
|
||||
uv_async_close(loop, (uv_async_t*) handle);
|
||||
uv__async_close(loop, (uv_async_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_SIGNAL:
|
||||
uv_signal_close(loop, (uv_signal_t*) handle);
|
||||
uv__signal_close(loop, (uv_signal_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_PROCESS:
|
||||
uv_process_close(loop, (uv_process_t*) handle);
|
||||
uv__process_close(loop, (uv_process_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_FS_EVENT:
|
||||
uv_fs_event_close(loop, (uv_fs_event_t*) handle);
|
||||
uv__fs_event_close(loop, (uv_fs_event_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_FS_POLL:
|
||||
|
||||
@@ -72,25 +72,25 @@ typedef struct {
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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);
|
||||
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,
|
||||
@@ -104,23 +104,23 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
/*
|
||||
* 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,
|
||||
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);
|
||||
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__create_stdio_pipe_pair(uv_loop_t* loop,
|
||||
uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags);
|
||||
|
||||
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,
|
||||
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,
|
||||
@@ -131,74 +131,74 @@ int uv__pipe_write(uv_loop_t* loop,
|
||||
uv_stream_t* send_handle,
|
||||
uv_write_cb cb);
|
||||
|
||||
void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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);
|
||||
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);
|
||||
void uv__console_init(void);
|
||||
|
||||
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
|
||||
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,
|
||||
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__tty_close(uv_tty_t* handle);
|
||||
|
||||
void uv_process_tty_read_req(uv_loop_t* loop, 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,
|
||||
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
|
||||
* 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,
|
||||
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
|
||||
* 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,
|
||||
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);
|
||||
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,
|
||||
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);
|
||||
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__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__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);
|
||||
|
||||
@@ -206,53 +206,47 @@ 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__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,
|
||||
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);
|
||||
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__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,
|
||||
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);
|
||||
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);
|
||||
|
||||
|
||||
/*
|
||||
* FS
|
||||
*/
|
||||
void uv_fs_init(void);
|
||||
void uv__fs_init(void);
|
||||
|
||||
|
||||
/*
|
||||
* FS Event
|
||||
*/
|
||||
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
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);
|
||||
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);
|
||||
|
||||
|
||||
/*
|
||||
@@ -266,7 +260,7 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
|
||||
*/
|
||||
void uv__util_init(void);
|
||||
|
||||
uint64_t uv__hrtime(double scale);
|
||||
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);
|
||||
@@ -280,6 +274,8 @@ int uv__getsockpeername(const uv_handle_t* handle,
|
||||
int* namelen,
|
||||
int delayed_error);
|
||||
|
||||
int uv__random_rtlgenrandom(void* buf, size_t buflen);
|
||||
|
||||
|
||||
/*
|
||||
* Process stdio handles.
|
||||
@@ -297,28 +293,28 @@ HANDLE uv__stdio_handle(BYTE* buffer, int fd);
|
||||
/*
|
||||
* Winapi and ntapi utility functions
|
||||
*/
|
||||
void uv_winapi_init(void);
|
||||
void uv__winapi_init(void);
|
||||
|
||||
|
||||
/*
|
||||
* Winsock utility functions
|
||||
*/
|
||||
void uv_winsock_init(void);
|
||||
void uv__winsock_init(void);
|
||||
|
||||
int uv_ntstatus_to_winsock_error(NTSTATUS status);
|
||||
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);
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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 */
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "handle-inl.h"
|
||||
|
||||
|
||||
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
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;
|
||||
@@ -104,7 +104,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
} \
|
||||
\
|
||||
\
|
||||
void uv_##name##_invoke(uv_loop_t* loop) { \
|
||||
void uv__##name##_invoke(uv_loop_t* loop) { \
|
||||
uv_##name##_t* handle; \
|
||||
\
|
||||
(loop)->next_##name##_handle = (loop)->name##_handles; \
|
||||
|
||||
@@ -100,13 +100,13 @@ static void eof_timer_destroy(uv_pipe_t* pipe);
|
||||
static void eof_timer_close_cb(uv_handle_t* handle);
|
||||
|
||||
|
||||
static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
|
||||
static void uv__unique_pipe_name(char* ptr, char* name, size_t size) {
|
||||
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
|
||||
|
||||
handle->reqs_pending = 0;
|
||||
handle->handle = INVALID_HANDLE_VALUE;
|
||||
@@ -122,8 +122,8 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
||||
}
|
||||
|
||||
|
||||
static void uv_pipe_connection_init(uv_pipe_t* handle) {
|
||||
uv_connection_init((uv_stream_t*) handle);
|
||||
static void uv__pipe_connection_init(uv_pipe_t* handle) {
|
||||
uv__connection_init((uv_stream_t*) handle);
|
||||
handle->read_req.data = handle;
|
||||
handle->pipe.conn.eof_timer = NULL;
|
||||
assert(!(handle->flags & UV_HANDLE_PIPESERVER));
|
||||
@@ -204,17 +204,17 @@ static void close_pipe(uv_pipe_t* pipe) {
|
||||
}
|
||||
|
||||
|
||||
int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
|
||||
char* name, size_t nameSize) {
|
||||
static int uv__pipe_server(
|
||||
HANDLE* pipeHandle_ptr, DWORD access,
|
||||
char* name, size_t nameSize, char* random) {
|
||||
HANDLE pipeHandle;
|
||||
int err;
|
||||
char* ptr = (char*)handle;
|
||||
|
||||
for (;;) {
|
||||
uv_unique_pipe_name(ptr, name, nameSize);
|
||||
uv__unique_pipe_name(random, name, nameSize);
|
||||
|
||||
pipeHandle = CreateNamedPipeA(name,
|
||||
access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
|
||||
access | FILE_FLAG_FIRST_PIPE_INSTANCE,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
|
||||
NULL);
|
||||
|
||||
@@ -228,37 +228,235 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Pipe name collision. Increment the pointer and try again. */
|
||||
ptr++;
|
||||
/* Pipe name collision. Increment the random number and try again. */
|
||||
random++;
|
||||
}
|
||||
|
||||
if (CreateIoCompletionPort(pipeHandle,
|
||||
loop->iocp,
|
||||
(ULONG_PTR)handle,
|
||||
0) == NULL) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
uv_pipe_connection_init(handle);
|
||||
handle->handle = pipeHandle;
|
||||
*pipeHandle_ptr = pipeHandle;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(pipeHandle);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
uv_pipe_t* handle,
|
||||
HANDLE pipeHandle,
|
||||
int fd,
|
||||
DWORD duplex_flags) {
|
||||
static int uv__create_pipe_pair(
|
||||
HANDLE* server_pipe_ptr, HANDLE* client_pipe_ptr,
|
||||
unsigned int server_flags, unsigned int client_flags,
|
||||
int inherit_client, char* random) {
|
||||
/* allowed flags are: UV_READABLE_PIPE | UV_WRITABLE_PIPE | UV_NONBLOCK_PIPE */
|
||||
char pipe_name[64];
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
DWORD server_access;
|
||||
DWORD client_access;
|
||||
HANDLE server_pipe;
|
||||
HANDLE client_pipe;
|
||||
int err;
|
||||
|
||||
server_pipe = INVALID_HANDLE_VALUE;
|
||||
client_pipe = INVALID_HANDLE_VALUE;
|
||||
|
||||
server_access = 0;
|
||||
if (server_flags & UV_READABLE_PIPE)
|
||||
server_access |= PIPE_ACCESS_INBOUND;
|
||||
if (server_flags & UV_WRITABLE_PIPE)
|
||||
server_access |= PIPE_ACCESS_OUTBOUND;
|
||||
if (server_flags & UV_NONBLOCK_PIPE)
|
||||
server_access |= FILE_FLAG_OVERLAPPED;
|
||||
server_access |= WRITE_DAC;
|
||||
|
||||
client_access = 0;
|
||||
if (client_flags & UV_READABLE_PIPE)
|
||||
client_access |= GENERIC_READ;
|
||||
else
|
||||
client_access |= FILE_READ_ATTRIBUTES;
|
||||
if (client_flags & UV_WRITABLE_PIPE)
|
||||
client_access |= GENERIC_WRITE;
|
||||
else
|
||||
client_access |= FILE_WRITE_ATTRIBUTES;
|
||||
client_access |= WRITE_DAC;
|
||||
|
||||
/* Create server pipe handle. */
|
||||
err = uv__pipe_server(&server_pipe,
|
||||
server_access,
|
||||
pipe_name,
|
||||
sizeof(pipe_name),
|
||||
random);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
/* Create client pipe handle. */
|
||||
sa.nLength = sizeof sa;
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = inherit_client;
|
||||
|
||||
client_pipe = CreateFileA(pipe_name,
|
||||
client_access,
|
||||
0,
|
||||
&sa,
|
||||
OPEN_EXISTING,
|
||||
(client_flags & UV_NONBLOCK_PIPE) ? FILE_FLAG_OVERLAPPED : 0,
|
||||
NULL);
|
||||
if (client_pipe == INVALID_HANDLE_VALUE) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Validate that the pipe was opened in the right mode. */
|
||||
{
|
||||
DWORD mode;
|
||||
BOOL r;
|
||||
r = GetNamedPipeHandleState(client_pipe, &mode, NULL, NULL, NULL, NULL, 0);
|
||||
if (r == TRUE) {
|
||||
assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
|
||||
} else {
|
||||
fprintf(stderr, "libuv assertion failure: GetNamedPipeHandleState failed\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do a blocking ConnectNamedPipe. This should not block because we have
|
||||
* both ends of the pipe created. */
|
||||
if (!ConnectNamedPipe(server_pipe, NULL)) {
|
||||
if (GetLastError() != ERROR_PIPE_CONNECTED) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
*client_pipe_ptr = client_pipe;
|
||||
*server_pipe_ptr = server_pipe;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (server_pipe != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(server_pipe);
|
||||
|
||||
if (client_pipe != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(client_pipe);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe(uv_file fds[2], int read_flags, int write_flags) {
|
||||
uv_file temp[2];
|
||||
int err;
|
||||
HANDLE readh;
|
||||
HANDLE writeh;
|
||||
|
||||
/* Make the server side the inbound (read) end, */
|
||||
/* so that both ends will have FILE_READ_ATTRIBUTES permission. */
|
||||
/* TODO: better source of local randomness than &fds? */
|
||||
read_flags |= UV_READABLE_PIPE;
|
||||
write_flags |= UV_WRITABLE_PIPE;
|
||||
err = uv__create_pipe_pair(&readh, &writeh, read_flags, write_flags, 0, (char*) &fds[0]);
|
||||
if (err != 0)
|
||||
return err;
|
||||
temp[0] = _open_osfhandle((intptr_t) readh, 0);
|
||||
if (temp[0] == -1) {
|
||||
if (errno == UV_EMFILE)
|
||||
err = UV_EMFILE;
|
||||
else
|
||||
err = UV_UNKNOWN;
|
||||
CloseHandle(readh);
|
||||
CloseHandle(writeh);
|
||||
return err;
|
||||
}
|
||||
temp[1] = _open_osfhandle((intptr_t) writeh, 0);
|
||||
if (temp[1] == -1) {
|
||||
if (errno == UV_EMFILE)
|
||||
err = UV_EMFILE;
|
||||
else
|
||||
err = UV_UNKNOWN;
|
||||
_close(temp[0]);
|
||||
CloseHandle(writeh);
|
||||
return err;
|
||||
}
|
||||
fds[0] = temp[0];
|
||||
fds[1] = temp[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
||||
uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
|
||||
/* The parent_pipe is always the server_pipe and kept by libuv.
|
||||
* The child_pipe is always the client_pipe and is passed to the child.
|
||||
* The flags are specified with respect to their usage in the child. */
|
||||
HANDLE server_pipe;
|
||||
HANDLE client_pipe;
|
||||
unsigned int server_flags;
|
||||
unsigned int client_flags;
|
||||
int err;
|
||||
|
||||
server_pipe = INVALID_HANDLE_VALUE;
|
||||
client_pipe = INVALID_HANDLE_VALUE;
|
||||
|
||||
server_flags = 0;
|
||||
client_flags = 0;
|
||||
if (flags & UV_READABLE_PIPE) {
|
||||
/* The server needs inbound (read) 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_flags |= UV_READABLE_PIPE | UV_WRITABLE_PIPE;
|
||||
client_flags |= UV_READABLE_PIPE;
|
||||
}
|
||||
if (flags & UV_WRITABLE_PIPE) {
|
||||
server_flags |= UV_READABLE_PIPE;
|
||||
client_flags |= UV_WRITABLE_PIPE;
|
||||
}
|
||||
server_flags |= UV_NONBLOCK_PIPE;
|
||||
if (flags & UV_NONBLOCK_PIPE || parent_pipe->ipc) {
|
||||
client_flags |= UV_NONBLOCK_PIPE;
|
||||
}
|
||||
|
||||
err = uv__create_pipe_pair(&server_pipe, &client_pipe,
|
||||
server_flags, client_flags, 1, (char*) server_pipe);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
if (CreateIoCompletionPort(server_pipe,
|
||||
loop->iocp,
|
||||
(ULONG_PTR) parent_pipe,
|
||||
0) == NULL) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
uv__pipe_connection_init(parent_pipe);
|
||||
parent_pipe->handle = server_pipe;
|
||||
*child_pipe_ptr = client_pipe;
|
||||
|
||||
/* The server end is now readable and/or writable. */
|
||||
if (flags & UV_READABLE_PIPE)
|
||||
parent_pipe->flags |= UV_HANDLE_WRITABLE;
|
||||
if (flags & UV_WRITABLE_PIPE)
|
||||
parent_pipe->flags |= UV_HANDLE_READABLE;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (server_pipe != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(server_pipe);
|
||||
|
||||
if (client_pipe != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(client_pipe);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int uv__set_pipe_handle(uv_loop_t* loop,
|
||||
uv_pipe_t* handle,
|
||||
HANDLE pipeHandle,
|
||||
int fd,
|
||||
DWORD duplex_flags) {
|
||||
NTSTATUS nt_status;
|
||||
IO_STATUS_BLOCK io_status;
|
||||
FILE_MODE_INFORMATION mode_info;
|
||||
@@ -266,8 +464,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
DWORD current_mode = 0;
|
||||
DWORD err = 0;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
|
||||
handle->handle != INVALID_HANDLE_VALUE)
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER)
|
||||
return UV_EINVAL;
|
||||
if (handle->handle != INVALID_HANDLE_VALUE)
|
||||
return UV_EBUSY;
|
||||
|
||||
if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
|
||||
@@ -314,7 +513,7 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
/* Overlapped pipe. Try to associate with IOCP. */
|
||||
if (CreateIoCompletionPort(pipeHandle,
|
||||
loop->iocp,
|
||||
(ULONG_PTR)handle,
|
||||
(ULONG_PTR) handle,
|
||||
0) == NULL) {
|
||||
handle->flags |= UV_HANDLE_EMULATE_IOCP;
|
||||
}
|
||||
@@ -328,6 +527,38 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
static int pipe_alloc_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_pipe_accept_t* req, BOOL firstInstance) {
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
|
||||
req->pipeHandle =
|
||||
CreateNamedPipeW(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC |
|
||||
(firstInstance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||
|
||||
if (req->pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Associate it with IOCP so we can get events. */
|
||||
if (CreateIoCompletionPort(req->pipeHandle,
|
||||
loop->iocp,
|
||||
(ULONG_PTR) handle,
|
||||
0) == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateIoCompletionPort");
|
||||
}
|
||||
|
||||
/* Stash a handle in the server object for use from places such as
|
||||
* getsockname and chmod. As we transfer ownership of these to client
|
||||
* objects, we'll allocate new ones here. */
|
||||
handle->handle = req->pipeHandle;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
|
||||
uv_loop_t* loop;
|
||||
uv_pipe_t* handle;
|
||||
@@ -349,7 +580,7 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
|
||||
}
|
||||
|
||||
|
||||
void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
int err;
|
||||
DWORD result;
|
||||
uv_shutdown_t* req;
|
||||
@@ -401,7 +632,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
|
||||
if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
|
||||
/* Short-circuit, no need to call FlushFileBuffers. */
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -460,7 +691,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
UnregisterWait(handle->read_req.wait_handle);
|
||||
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (handle->read_req.event_handle) {
|
||||
if (handle->read_req.event_handle != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
@@ -542,13 +773,10 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
* Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
|
||||
* If this fails then there's already a pipe server for the given pipe name.
|
||||
*/
|
||||
handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||
|
||||
if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
if (!pipe_alloc_accept(loop,
|
||||
handle,
|
||||
&handle->pipe.serv.accept_reqs[0],
|
||||
TRUE)) {
|
||||
err = GetLastError();
|
||||
if (err == ERROR_ACCESS_DENIED) {
|
||||
err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */
|
||||
@@ -558,15 +786,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (uv_set_pipe_handle(loop,
|
||||
handle,
|
||||
handle->pipe.serv.accept_reqs[0].pipeHandle,
|
||||
-1,
|
||||
0)) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
handle->pipe.serv.pending_accepts = NULL;
|
||||
handle->flags |= UV_HANDLE_PIPESERVER;
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
@@ -579,11 +798,6 @@ error:
|
||||
handle->name = NULL;
|
||||
}
|
||||
|
||||
if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
|
||||
handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
@@ -607,15 +821,14 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
|
||||
while (WaitNamedPipeW(handle->name, 30000)) {
|
||||
/* The pipe is now available, try to connect. */
|
||||
pipeHandle = open_named_pipe(handle->name, &duplex_flags);
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
}
|
||||
|
||||
SwitchToThread();
|
||||
}
|
||||
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE &&
|
||||
!uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
|
||||
!uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
|
||||
SET_REQ_SUCCESS(req);
|
||||
} else {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
@@ -679,17 +892,17 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
||||
|
||||
assert(pipeHandle != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (uv_set_pipe_handle(loop,
|
||||
(uv_pipe_t*) req->handle,
|
||||
pipeHandle,
|
||||
-1,
|
||||
duplex_flags)) {
|
||||
if (uv__set_pipe_handle(loop,
|
||||
(uv_pipe_t*) req->handle,
|
||||
pipeHandle,
|
||||
-1,
|
||||
duplex_flags)) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
SET_REQ_SUCCESS(req);
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
return;
|
||||
@@ -700,13 +913,12 @@ error:
|
||||
handle->name = NULL;
|
||||
}
|
||||
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(pipeHandle);
|
||||
}
|
||||
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(req, err);
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
return;
|
||||
@@ -770,7 +982,7 @@ void uv__pipe_read_stop(uv_pipe_t* handle) {
|
||||
|
||||
/* Cleans up uv_pipe_t (server or connection) and all resources associated with
|
||||
* it. */
|
||||
void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
int i;
|
||||
HANDLE pipeHandle;
|
||||
|
||||
@@ -803,7 +1015,7 @@ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
@@ -814,10 +1026,10 @@ void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
}
|
||||
|
||||
uv_pipe_cleanup(loop, handle);
|
||||
uv__pipe_cleanup(loop, handle);
|
||||
|
||||
if (handle->reqs_pending == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
uv__want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
@@ -825,33 +1037,15 @@ void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
static void uv__pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_pipe_accept_t* req, BOOL firstInstance) {
|
||||
assert(handle->flags & UV_HANDLE_LISTENING);
|
||||
|
||||
if (!firstInstance) {
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
|
||||
req->pipeHandle = CreateNamedPipeW(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||
|
||||
if (req->pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
|
||||
CloseHandle(req->pipeHandle);
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
if (!firstInstance && !pipe_alloc_accept(loop, handle, req, FALSE)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(req->pipeHandle != INVALID_HANDLE_VALUE);
|
||||
@@ -869,7 +1063,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
}
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
@@ -879,7 +1073,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
uv_loop_t* loop = server->loop;
|
||||
uv_pipe_t* pipe_client;
|
||||
uv_pipe_accept_t* req;
|
||||
@@ -906,7 +1100,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
uv__free(item);
|
||||
|
||||
} else {
|
||||
pipe_client = (uv_pipe_t*)client;
|
||||
pipe_client = (uv_pipe_t*) client;
|
||||
|
||||
/* Find a connection instance that has been connected, but not yet
|
||||
* accepted. */
|
||||
@@ -918,7 +1112,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
}
|
||||
|
||||
/* Initialize the client handle and copy the pipeHandle to the client */
|
||||
uv_pipe_connection_init(pipe_client);
|
||||
uv__pipe_connection_init(pipe_client);
|
||||
pipe_client->handle = req->pipeHandle;
|
||||
pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
|
||||
@@ -927,8 +1121,9 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
req->next_pending = NULL;
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
server->handle = INVALID_HANDLE_VALUE;
|
||||
if (!(server->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_pipe_queue_accept(loop, server, req, FALSE);
|
||||
uv__pipe_queue_accept(loop, server, req, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,7 +1132,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
|
||||
|
||||
/* Starts listening for connections for the given pipe. */
|
||||
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
int i;
|
||||
|
||||
@@ -957,6 +1152,10 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (handle->ipc) {
|
||||
return WSAEINVAL;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_LISTENING;
|
||||
INCREASE_ACTIVE_COUNT(loop, handle);
|
||||
handle->stream.serv.connection_cb = cb;
|
||||
@@ -965,7 +1164,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
|
||||
|
||||
for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
|
||||
uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0);
|
||||
uv__pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1055,7 +1254,6 @@ static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
|
||||
assert(req != NULL);
|
||||
assert(req->type == UV_WRITE);
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
assert(req->write_buffer.base);
|
||||
|
||||
result = WriteFile(handle->handle,
|
||||
req->write_buffer.base,
|
||||
@@ -1110,7 +1308,7 @@ static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out
|
||||
}
|
||||
|
||||
|
||||
static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
static void uv__pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
uv_read_t* req;
|
||||
int result;
|
||||
|
||||
@@ -1133,6 +1331,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
} else {
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
assert(req->event_handle != NULL);
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
|
||||
}
|
||||
|
||||
@@ -1150,15 +1349,9 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
if (!req->event_handle) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
}
|
||||
if (req->wait_handle == INVALID_HANDLE_VALUE) {
|
||||
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
|
||||
req->event_handle, post_completion_read_wait, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
goto error;
|
||||
@@ -1174,15 +1367,15 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
return;
|
||||
|
||||
error:
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_read_start(uv_pipe_t* handle,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb) {
|
||||
int uv__pipe_read_start(uv_pipe_t* handle,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
handle->flags |= UV_HANDLE_READING;
|
||||
@@ -1192,14 +1385,22 @@ int uv_pipe_read_start(uv_pipe_t* handle,
|
||||
|
||||
/* If reading was stopped and then started again, there could still be a read
|
||||
* request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
||||
uv_pipe_queue_read(loop, handle);
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
|
||||
handle->read_req.event_handle == NULL) {
|
||||
handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (handle->read_req.event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
}
|
||||
uv__pipe_queue_read(loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
|
||||
static void uv__insert_non_overlapped_write_req(uv_pipe_t* handle,
|
||||
uv_write_t* req) {
|
||||
req->next_req = NULL;
|
||||
if (handle->pipe.conn.non_overlapped_writes_tail) {
|
||||
@@ -1235,7 +1436,7 @@ static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
static void uv_queue_non_overlapped_write(uv_pipe_t* handle) {
|
||||
static void uv__queue_non_overlapped_write(uv_pipe_t* handle) {
|
||||
uv_write_t* req = uv_remove_non_overlapped_write_req(handle);
|
||||
if (req) {
|
||||
if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc,
|
||||
@@ -1328,7 +1529,16 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
req->coalesced = 0;
|
||||
req->event_handle = NULL;
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & (UV_HANDLE_EMULATE_IOCP | UV_HANDLE_BLOCKING_WRITES)) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (req->event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
|
||||
}
|
||||
req->write_buffer = uv_null_buf_;
|
||||
|
||||
if (nbufs == 0) {
|
||||
@@ -1367,9 +1577,9 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
return 0;
|
||||
} else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
|
||||
req->write_buffer = write_buf;
|
||||
uv_insert_non_overlapped_write_req(handle, req);
|
||||
uv__insert_non_overlapped_write_req(handle, req);
|
||||
if (handle->stream.conn.write_reqs_pending == 0) {
|
||||
uv_queue_non_overlapped_write(handle);
|
||||
uv__queue_non_overlapped_write(handle);
|
||||
}
|
||||
|
||||
/* Request queued by the kernel. */
|
||||
@@ -1377,11 +1587,6 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
handle->write_queue_size += req->u.io.queued_bytes;
|
||||
} else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
|
||||
/* Using overlapped IO, but wait for completion before returning */
|
||||
req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
|
||||
if (!req->u.io.overlapped.hEvent) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
|
||||
result = WriteFile(handle->handle,
|
||||
write_buf.base,
|
||||
write_buf.len,
|
||||
@@ -1390,7 +1595,8 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
|
||||
if (!result && GetLastError() != ERROR_IO_PENDING) {
|
||||
err = GetLastError();
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1401,14 +1607,16 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
/* Request queued by the kernel. */
|
||||
req->u.io.queued_bytes = write_buf.len;
|
||||
handle->write_queue_size += req->u.io.queued_bytes;
|
||||
if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) !=
|
||||
if (WaitForSingleObject(req->event_handle, INFINITE) !=
|
||||
WAIT_OBJECT_0) {
|
||||
err = GetLastError();
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
handle->reqs_pending++;
|
||||
@@ -1435,12 +1643,8 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
|
||||
req->event_handle, post_completion_write_wait, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
return GetLastError();
|
||||
}
|
||||
@@ -1588,20 +1792,19 @@ int uv__pipe_write(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
static void uv__pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_buf_t buf) {
|
||||
/* If there is an eof timer running, we don't need it any more, so discard
|
||||
* it. */
|
||||
eof_timer_destroy(handle);
|
||||
|
||||
handle->flags &= ~UV_HANDLE_READABLE;
|
||||
uv_read_stop((uv_stream_t*) handle);
|
||||
|
||||
handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf);
|
||||
}
|
||||
|
||||
|
||||
static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
|
||||
static void uv__pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
|
||||
uv_buf_t buf) {
|
||||
/* If there is an eof timer running, we don't need it any more, so discard
|
||||
* it. */
|
||||
@@ -1613,12 +1816,12 @@ static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
|
||||
}
|
||||
|
||||
|
||||
static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
static void uv__pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
int error, uv_buf_t buf) {
|
||||
if (error == ERROR_BROKEN_PIPE) {
|
||||
uv_pipe_read_eof(loop, handle, buf);
|
||||
uv__pipe_read_eof(loop, handle, buf);
|
||||
} else {
|
||||
uv_pipe_read_error(loop, handle, error, buf);
|
||||
uv__pipe_read_error(loop, handle, error, buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1689,7 +1892,7 @@ static DWORD uv__pipe_read_data(uv_loop_t* loop,
|
||||
|
||||
/* Read into the user buffer. */
|
||||
if (!ReadFile(handle->handle, buf.base, max_bytes, &bytes_read, NULL)) {
|
||||
uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf);
|
||||
uv__pipe_read_error_or_eof(loop, handle, GetLastError(), buf);
|
||||
return 0; /* Break out of read loop. */
|
||||
}
|
||||
|
||||
@@ -1776,14 +1979,14 @@ invalid:
|
||||
err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */
|
||||
|
||||
error:
|
||||
uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_);
|
||||
uv__pipe_read_error_or_eof(loop, handle, err, uv_null_buf_);
|
||||
return 0; /* Break out of read loop. */
|
||||
}
|
||||
|
||||
|
||||
void uv_process_pipe_read_req(uv_loop_t* loop,
|
||||
uv_pipe_t* handle,
|
||||
uv_req_t* req) {
|
||||
void uv__process_pipe_read_req(uv_loop_t* loop,
|
||||
uv_pipe_t* handle,
|
||||
uv_req_t* req) {
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
handle->flags &= ~(UV_HANDLE_READ_PENDING | UV_HANDLE_CANCELLATION_PENDING);
|
||||
@@ -1804,7 +2007,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop,
|
||||
* indicate an ERROR_OPERATION_ABORTED error. This error isn't relevant to
|
||||
* the user; we'll start a new zero-read at the end of this function. */
|
||||
if (err != ERROR_OPERATION_ABORTED)
|
||||
uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_);
|
||||
uv__pipe_read_error_or_eof(loop, handle, err, uv_null_buf_);
|
||||
|
||||
} else {
|
||||
/* The zero-read completed without error, indicating there is data
|
||||
@@ -1814,7 +2017,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop,
|
||||
/* Get the number of bytes available. */
|
||||
avail = 0;
|
||||
if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &avail, NULL))
|
||||
uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
|
||||
uv__pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
|
||||
|
||||
/* Read until we've either read all the bytes available, or the 'reading'
|
||||
* flag is cleared. */
|
||||
@@ -1843,12 +2046,12 @@ void uv_process_pipe_read_req(uv_loop_t* loop,
|
||||
/* Start another zero-read request if necessary. */
|
||||
if ((handle->flags & UV_HANDLE_READING) &&
|
||||
!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
uv_pipe_queue_read(loop, handle);
|
||||
uv__pipe_queue_read(loop, handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_write_t* req) {
|
||||
int err;
|
||||
|
||||
@@ -1890,26 +2093,26 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
|
||||
handle->pipe.conn.non_overlapped_writes_tail) {
|
||||
assert(handle->stream.conn.write_reqs_pending > 0);
|
||||
uv_queue_non_overlapped_write(handle);
|
||||
uv__queue_non_overlapped_write(handle);
|
||||
}
|
||||
|
||||
if (handle->stream.conn.shutdown_req != NULL &&
|
||||
handle->stream.conn.write_reqs_pending == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_req_t* raw_req) {
|
||||
uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
|
||||
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */
|
||||
/* The req->pipeHandle should be freed already in uv__pipe_cleanup(). */
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
return;
|
||||
@@ -1929,7 +2132,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (!(handle->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_pipe_queue_accept(loop, handle, req, FALSE);
|
||||
uv__pipe_queue_accept(loop, handle, req, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1937,7 +2140,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
}
|
||||
|
||||
|
||||
void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_connect_t* req) {
|
||||
int err;
|
||||
|
||||
@@ -1948,7 +2151,7 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
if (req->cb) {
|
||||
err = 0;
|
||||
if (REQ_SUCCESS(req)) {
|
||||
uv_pipe_connection_init(handle);
|
||||
uv__pipe_connection_init(handle);
|
||||
} else {
|
||||
err = GET_REQ_ERROR(req);
|
||||
}
|
||||
@@ -1959,7 +2162,7 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
}
|
||||
|
||||
|
||||
void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_shutdown_t* req) {
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
@@ -1970,7 +2173,7 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
* is readable and we haven't seen EOF come in ourselves. */
|
||||
eof_timer_init(handle);
|
||||
|
||||
/* If reading start the timer right now. Otherwise uv_pipe_queue_read will
|
||||
/* If reading start the timer right now. Otherwise uv__pipe_queue_read will
|
||||
* start it. */
|
||||
if (handle->flags & UV_HANDLE_READ_PENDING) {
|
||||
eof_timer_start(handle);
|
||||
@@ -2030,9 +2233,9 @@ static void eof_timer_cb(uv_timer_t* timer) {
|
||||
assert(pipe->type == UV_NAMED_PIPE);
|
||||
|
||||
/* This should always be true, since we start the timer only in
|
||||
* uv_pipe_queue_read after successfully calling ReadFile, or in
|
||||
* uv_process_pipe_shutdown_req if a read is pending, and we always
|
||||
* immediately stop the timer in uv_process_pipe_read_req. */
|
||||
* uv__pipe_queue_read after successfully calling ReadFile, or in
|
||||
* uv__process_pipe_shutdown_req if a read is pending, and we always
|
||||
* immediately stop the timer in uv__process_pipe_read_req. */
|
||||
assert(pipe->flags & UV_HANDLE_READ_PENDING);
|
||||
|
||||
/* If there are many packets coming off the iocp then the timer callback may
|
||||
@@ -2053,7 +2256,7 @@ static void eof_timer_cb(uv_timer_t* timer) {
|
||||
|
||||
/* Report the eof and update flags. This will get reported even if the user
|
||||
* stopped reading in the meantime. TODO: is that okay? */
|
||||
uv_pipe_read_eof(loop, pipe, uv_null_buf_);
|
||||
uv__pipe_read_eof(loop, pipe, uv_null_buf_);
|
||||
}
|
||||
|
||||
|
||||
@@ -2127,20 +2330,20 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
||||
duplex_flags |= UV_HANDLE_READABLE;
|
||||
|
||||
if (os_handle == INVALID_HANDLE_VALUE ||
|
||||
uv_set_pipe_handle(pipe->loop,
|
||||
pipe,
|
||||
os_handle,
|
||||
file,
|
||||
duplex_flags) == -1) {
|
||||
uv__set_pipe_handle(pipe->loop,
|
||||
pipe,
|
||||
os_handle,
|
||||
file,
|
||||
duplex_flags) == -1) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
uv_pipe_connection_init(pipe);
|
||||
uv__pipe_connection_init(pipe);
|
||||
|
||||
if (pipe->ipc) {
|
||||
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
|
||||
pipe->pipe.conn.ipc_remote_pid = uv_os_getppid();
|
||||
assert(pipe->pipe.conn.ipc_remote_pid != (DWORD) -1);
|
||||
assert(pipe->pipe.conn.ipc_remote_pid != (DWORD)(uv_pid_t) -1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
|
||||
{0xf9eab0c0, 0x26d4, 0x11d0,
|
||||
{0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
|
||||
{0x9fc48064, 0x7298, 0x43e4,
|
||||
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
|
||||
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}},
|
||||
{0xa00943d9, 0x9c2e, 0x4633,
|
||||
{0x9b, 0x59, 0x00, 0x57, 0xa3, 0x16, 0x09, 0x94}}
|
||||
};
|
||||
|
||||
typedef struct uv_single_fd_set_s {
|
||||
@@ -122,44 +124,18 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
|
||||
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);
|
||||
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);
|
||||
uv__insert_pending_req(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
AFD_POLL_INFO afd_poll_info;
|
||||
int result;
|
||||
|
||||
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) {
|
||||
DWORD error = WSAGetLastError();
|
||||
if (error != WSA_IO_PENDING)
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
uv_req_t* req) {
|
||||
unsigned char mask_events;
|
||||
@@ -221,45 +197,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* 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 int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
|
||||
if (handle->events != 0) {
|
||||
uv__handle_start(handle);
|
||||
} else {
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
if ((handle->events & ~(handle->submitted_events_1 |
|
||||
handle->submitted_events_2)) != 0) {
|
||||
uv__fast_poll_submit_poll_req(handle->loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
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;
|
||||
} else {
|
||||
/* Cancel outstanding poll requests by executing another, unique poll
|
||||
* request that forces the outstanding ones to return. */
|
||||
return uv__fast_poll_cancel_poll_req(loop, handle);
|
||||
uv__want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,7 +359,7 @@ static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
WT_EXECUTELONGFUNCTION)) {
|
||||
/* Make this req pending, reporting an error. */
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, req);
|
||||
uv__insert_pending_req(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,46 +402,11 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* 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);
|
||||
uv__want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
|
||||
if (handle->events != 0) {
|
||||
uv__handle_start(handle);
|
||||
} else {
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
if ((handle->events &
|
||||
~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
|
||||
uv__slow_poll_submit_poll_req(handle->loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
@@ -582,39 +485,48 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
|
||||
int err;
|
||||
static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) {
|
||||
int submitted_events;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
err = uv__fast_poll_set(handle->loop, handle, events);
|
||||
} else {
|
||||
err = uv__slow_poll_set(handle->loop, handle, events);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
|
||||
UV_PRIORITIZED)) == 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_stop(uv_poll_t* handle) {
|
||||
int err;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
err = uv__fast_poll_set(handle->loop, handle, 0);
|
||||
} else {
|
||||
err = uv__slow_poll_set(handle->loop, handle, 0);
|
||||
}
|
||||
|
||||
return uv_translate_sys_error(err);
|
||||
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
|
||||
return uv__poll_set(handle, events, cb);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
|
||||
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 {
|
||||
@@ -623,16 +535,48 @@ 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) {
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
return uv__fast_poll_close(loop, handle);
|
||||
} else {
|
||||
return uv__slow_poll_close(loop, handle);
|
||||
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) {
|
||||
void uv__poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
|
||||
@@ -95,102 +95,6 @@ void uv_disable_stdio_inheritance(void) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
BOOL 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;
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@ static const env_var_t required_vars[] = { /* keep me sorted */
|
||||
E_V("USERPROFILE"),
|
||||
E_V("WINDIR"),
|
||||
};
|
||||
static size_t n_required_vars = ARRAY_SIZE(required_vars);
|
||||
|
||||
|
||||
static HANDLE uv_global_job_handle_;
|
||||
@@ -107,7 +106,7 @@ static void uv__init_global_job_handle(void) {
|
||||
}
|
||||
|
||||
|
||||
static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
|
||||
static int uv__utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
|
||||
int ws_len, r;
|
||||
WCHAR* ws;
|
||||
|
||||
@@ -139,7 +138,7 @@ static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
|
||||
}
|
||||
|
||||
|
||||
static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
|
||||
static void uv__process_init(uv_loop_t* loop, uv_process_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
|
||||
handle->exit_cb = NULL;
|
||||
handle->pid = 0;
|
||||
@@ -171,7 +170,9 @@ static WCHAR* search_path_join_test(const WCHAR* dir,
|
||||
size_t cwd_len) {
|
||||
WCHAR *result, *result_pos;
|
||||
DWORD attrs;
|
||||
if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') {
|
||||
if (dir_len > 2 &&
|
||||
((dir[0] == L'\\' || dir[0] == L'/') &&
|
||||
(dir[1] == L'\\' || dir[1] == L'/'))) {
|
||||
/* It's a UNC path so ignore cwd */
|
||||
cwd_len = 0;
|
||||
} else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
|
||||
@@ -644,7 +645,7 @@ int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
|
||||
assert(r==nb);
|
||||
B[nb] = L'\0';
|
||||
|
||||
while (1) {
|
||||
for (;;) {
|
||||
wchar_t AA = *A++;
|
||||
wchar_t BB = *B++;
|
||||
if (AA < BB) {
|
||||
@@ -693,8 +694,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
WCHAR* dst_copy;
|
||||
WCHAR** ptr_copy;
|
||||
WCHAR** env_copy;
|
||||
DWORD* required_vars_value_len =
|
||||
(DWORD*)alloca(n_required_vars * sizeof(DWORD*));
|
||||
DWORD required_vars_value_len[ARRAY_SIZE(required_vars)];
|
||||
|
||||
/* first pass: determine size in UTF-16 */
|
||||
for (env = env_block; *env; env++) {
|
||||
@@ -716,7 +716,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
|
||||
/* second pass: copy to UTF-16 environment block */
|
||||
dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
|
||||
if (!dst_copy) {
|
||||
if (dst_copy == NULL && env_len > 0) {
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
env_copy = (WCHAR**)alloca(env_block_count * sizeof(WCHAR*));
|
||||
@@ -741,13 +741,13 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
}
|
||||
}
|
||||
*ptr_copy = NULL;
|
||||
assert(env_len == (size_t) (ptr - dst_copy));
|
||||
assert(env_len == 0 || env_len == (size_t) (ptr - dst_copy));
|
||||
|
||||
/* sort our (UTF-16) copy */
|
||||
qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
|
||||
|
||||
/* third pass: check for required variables */
|
||||
for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
|
||||
for (ptr_copy = env_copy, i = 0; i < ARRAY_SIZE(required_vars); ) {
|
||||
int cmp;
|
||||
if (!*ptr_copy) {
|
||||
cmp = -1;
|
||||
@@ -780,10 +780,10 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
}
|
||||
|
||||
for (ptr = dst, ptr_copy = env_copy, i = 0;
|
||||
*ptr_copy || i < n_required_vars;
|
||||
*ptr_copy || i < ARRAY_SIZE(required_vars);
|
||||
ptr += len) {
|
||||
int cmp;
|
||||
if (i >= n_required_vars) {
|
||||
if (i >= ARRAY_SIZE(required_vars)) {
|
||||
cmp = 1;
|
||||
} else if (!*ptr_copy) {
|
||||
cmp = -1;
|
||||
@@ -865,7 +865,7 @@ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
|
||||
|
||||
|
||||
/* Called on main thread after a child process has exited. */
|
||||
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
|
||||
void uv__process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
|
||||
int64_t exit_code;
|
||||
DWORD status;
|
||||
|
||||
@@ -875,7 +875,7 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
|
||||
/* If we're closing, don't call the exit callback. Just schedule a close
|
||||
* callback now. */
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
uv__want_endgame(loop, (uv_handle_t*) handle);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -903,7 +903,7 @@ 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_close(uv_loop_t* loop, uv_process_t* handle) {
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->wait_handle != INVALID_HANDLE_VALUE) {
|
||||
@@ -919,12 +919,12 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
|
||||
}
|
||||
|
||||
if (!handle->exit_cb_pending) {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
|
||||
void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle) {
|
||||
assert(!handle->exit_cb_pending);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
@@ -949,7 +949,7 @@ int uv_spawn(uv_loop_t* loop,
|
||||
PROCESS_INFORMATION info;
|
||||
DWORD process_flags;
|
||||
|
||||
uv_process_init(loop, process);
|
||||
uv__process_init(loop, process);
|
||||
process->exit_cb = options->exit_cb;
|
||||
|
||||
if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
|
||||
@@ -970,7 +970,7 @@ int uv_spawn(uv_loop_t* loop,
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI |
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
|
||||
|
||||
err = uv_utf8_to_utf16_alloc(options->file, &application);
|
||||
err = uv__utf8_to_utf16_alloc(options->file, &application);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
@@ -989,7 +989,7 @@ int uv_spawn(uv_loop_t* loop,
|
||||
|
||||
if (options->cwd) {
|
||||
/* Explicit cwd */
|
||||
err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
|
||||
err = uv__utf8_to_utf16_alloc(options->cwd, &cwd);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
(pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
|
||||
|
||||
#define GET_REQ_SOCK_ERROR(req) \
|
||||
(uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
|
||||
(uv__ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
|
||||
|
||||
|
||||
#define REGISTER_HANDLE_REQ(loop, handle, req) \
|
||||
@@ -82,12 +82,12 @@
|
||||
}
|
||||
|
||||
|
||||
INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
|
||||
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) {
|
||||
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
|
||||
@@ -115,19 +115,19 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
|
||||
do { \
|
||||
switch (((uv_handle_t*) (req)->handle_at)->type) { \
|
||||
case UV_TCP: \
|
||||
uv_process_tcp_##method##_req(loop, \
|
||||
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__process_pipe_##method##_req(loop, \
|
||||
(uv_pipe_t*) ((req)->handle_at), \
|
||||
req); \
|
||||
break; \
|
||||
\
|
||||
case UV_TTY: \
|
||||
uv_process_tty_##method##_req(loop, \
|
||||
uv__process_tty_##method##_req(loop, \
|
||||
(uv_tty_t*) ((req)->handle_at), \
|
||||
req); \
|
||||
break; \
|
||||
@@ -138,7 +138,7 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
|
||||
} while (0)
|
||||
|
||||
|
||||
INLINE static int uv_process_reqs(uv_loop_t* loop) {
|
||||
INLINE static int uv__process_reqs(uv_loop_t* loop) {
|
||||
uv_req_t* req;
|
||||
uv_req_t* first;
|
||||
uv_req_t* next;
|
||||
@@ -174,40 +174,40 @@ INLINE static int uv_process_reqs(uv_loop_t* loop) {
|
||||
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(
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
uv__process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -39,13 +39,18 @@ int uv__signal_start(uv_signal_t* handle,
|
||||
int signum,
|
||||
int oneshot);
|
||||
|
||||
void uv_signals_init(void) {
|
||||
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. */
|
||||
@@ -226,7 +231,7 @@ int uv__signal_start(uv_signal_t* handle,
|
||||
}
|
||||
|
||||
|
||||
void uv_process_signal_req(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) {
|
||||
long dispatched_signum;
|
||||
|
||||
@@ -249,22 +254,22 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* 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);
|
||||
uv__want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_signal_close(uv_loop_t* loop, uv_signal_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);
|
||||
uv__want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_signal_endgame(uv_loop_t* loop, uv_signal_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));
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
INLINE static void uv_stream_init(uv_loop_t* loop,
|
||||
uv_stream_t* handle,
|
||||
uv_handle_type type) {
|
||||
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;
|
||||
@@ -46,7 +46,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
INLINE static void uv_connection_init(uv_stream_t* handle) {
|
||||
INLINE static void uv__connection_init(uv_stream_t* handle) {
|
||||
handle->flags |= UV_HANDLE_CONNECTION;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
|
||||
err = ERROR_INVALID_PARAMETER;
|
||||
switch (stream->type) {
|
||||
case UV_TCP:
|
||||
err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
|
||||
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);
|
||||
err = uv__pipe_listen((uv_pipe_t*)stream, backlog, cb);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -52,10 +52,10 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
||||
err = ERROR_INVALID_PARAMETER;
|
||||
switch (server->type) {
|
||||
case UV_TCP:
|
||||
err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
|
||||
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);
|
||||
err = uv__pipe_accept((uv_pipe_t*)server, client);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -65,28 +65,21 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
||||
}
|
||||
|
||||
|
||||
int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb) {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
err = uv__tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -104,7 +97,7 @@ int uv_read_stop(uv_stream_t* handle) {
|
||||
|
||||
err = 0;
|
||||
if (handle->type == UV_TTY) {
|
||||
err = uv_tty_read_stop((uv_tty_t*) handle);
|
||||
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 {
|
||||
@@ -131,14 +124,14 @@ int uv_write(uv_write_t* req,
|
||||
err = ERROR_INVALID_PARAMETER;
|
||||
switch (handle->type) {
|
||||
case UV_TCP:
|
||||
err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
|
||||
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);
|
||||
err = uv__tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -195,11 +188,23 @@ int uv_try_write(uv_stream_t* stream,
|
||||
}
|
||||
|
||||
|
||||
int uv_try_write2(uv_stream_t* stream,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
uv_stream_t* send_handle) {
|
||||
if (send_handle != NULL)
|
||||
return UV_EAGAIN;
|
||||
return uv_try_write(stream, bufs, nbufs);
|
||||
}
|
||||
|
||||
|
||||
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)) {
|
||||
return UV_EPIPE;
|
||||
if (!(handle->flags & UV_HANDLE_WRITABLE) ||
|
||||
handle->flags & UV_HANDLE_SHUTTING ||
|
||||
uv__is_closing(handle)) {
|
||||
return UV_ENOTCONN;
|
||||
}
|
||||
|
||||
UV_REQ_INIT(req, UV_SHUTDOWN);
|
||||
@@ -207,11 +212,12 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
|
||||
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);
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -78,11 +78,11 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign
|
||||
}
|
||||
|
||||
|
||||
static int uv_tcp_set_socket(uv_loop_t* loop,
|
||||
uv_tcp_t* handle,
|
||||
SOCKET socket,
|
||||
int family,
|
||||
int imported) {
|
||||
static int uv__tcp_set_socket(uv_loop_t* loop,
|
||||
uv_tcp_t* handle,
|
||||
SOCKET socket,
|
||||
int family,
|
||||
int imported) {
|
||||
DWORD yes = 1;
|
||||
int non_ifs_lsp;
|
||||
int err;
|
||||
@@ -162,7 +162,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
|
||||
if (flags & ~0xFF)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
|
||||
uv__stream_init(loop, (uv_stream_t*) handle, UV_TCP);
|
||||
handle->tcp.serv.accept_reqs = NULL;
|
||||
handle->tcp.serv.pending_accepts = NULL;
|
||||
handle->socket = INVALID_SOCKET;
|
||||
@@ -173,7 +173,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
|
||||
handle->delayed_error = 0;
|
||||
|
||||
/* 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.
|
||||
* the handle queue, since it was added by uv__handle_init in uv__stream_init.
|
||||
*/
|
||||
|
||||
if (domain != AF_UNSPEC) {
|
||||
@@ -187,7 +187,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0);
|
||||
err = uv__tcp_set_socket(handle->loop, handle, sock, domain, 0);
|
||||
if (err) {
|
||||
closesocket(sock);
|
||||
QUEUE_REMOVE(&handle->handle_queue);
|
||||
@@ -205,7 +205,7 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
int err;
|
||||
unsigned int i;
|
||||
uv_tcp_accept_t* req;
|
||||
@@ -236,12 +236,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
|
||||
closesocket(handle->socket);
|
||||
handle->socket = INVALID_SOCKET;
|
||||
handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
|
||||
}
|
||||
assert(handle->socket == INVALID_SOCKET);
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
@@ -251,7 +246,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle) {
|
||||
if (req->event_handle != NULL) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
@@ -268,7 +263,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
UnregisterWait(handle->read_req.wait_handle);
|
||||
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (handle->read_req.event_handle) {
|
||||
if (handle->read_req.event_handle != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
@@ -291,10 +286,10 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
* See issue #1360.
|
||||
*
|
||||
*/
|
||||
static int uv_tcp_try_bind(uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags) {
|
||||
static int uv__tcp_try_bind(uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags) {
|
||||
DWORD err;
|
||||
int r;
|
||||
|
||||
@@ -310,7 +305,7 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
|
||||
err = uv__tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
|
||||
if (err) {
|
||||
closesocket(sock);
|
||||
return err;
|
||||
@@ -390,7 +385,7 @@ static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
|
||||
}
|
||||
|
||||
|
||||
static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
static void uv__tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
BOOL success;
|
||||
DWORD bytes;
|
||||
@@ -411,7 +406,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
accept_socket = socket(family, SOCK_STREAM, 0);
|
||||
if (accept_socket == INVALID_SOCKET) {
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
@@ -419,7 +414,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
/* Make the socket non-inheritable */
|
||||
if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
handle->reqs_pending++;
|
||||
closesocket(accept_socket);
|
||||
return;
|
||||
@@ -428,6 +423,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
assert(req->event_handle != NULL);
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
|
||||
}
|
||||
|
||||
@@ -444,7 +440,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
/* Process the req without IOCP. */
|
||||
req->accept_socket = accept_socket;
|
||||
handle->reqs_pending++;
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(success)) {
|
||||
/* The req will be processed with IOCP. */
|
||||
req->accept_socket = accept_socket;
|
||||
@@ -455,25 +451,25 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
req->event_handle, post_completion, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
}
|
||||
} else {
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
handle->reqs_pending++;
|
||||
/* Destroy the preallocated client socket. */
|
||||
closesocket(accept_socket);
|
||||
/* Destroy the event handle */
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
static void uv__tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
uv_read_t* req;
|
||||
uv_buf_t buf;
|
||||
int result;
|
||||
@@ -509,7 +505,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
assert(req->event_handle);
|
||||
assert(req->event_handle != NULL);
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
|
||||
}
|
||||
|
||||
@@ -522,34 +518,47 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
&req->u.io.overlapped,
|
||||
NULL);
|
||||
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
handle->reqs_pending++;
|
||||
|
||||
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
|
||||
/* Process the req without IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
req->u.io.overlapped.InternalHigh = bytes;
|
||||
handle->reqs_pending++;
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||
/* The req will be processed with IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
handle->reqs_pending++;
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
|
||||
req->wait_handle == INVALID_HANDLE_VALUE &&
|
||||
!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->event_handle, post_completion, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
}
|
||||
} else {
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
handle->reqs_pending++;
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
|
||||
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;
|
||||
|
||||
if (0 != setsockopt(handle->socket, SOL_SOCKET, SO_LINGER, (const char*)&l, sizeof(l)))
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
unsigned int i, simultaneous_accepts;
|
||||
uv_tcp_accept_t* req;
|
||||
int err;
|
||||
@@ -569,10 +578,10 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND)) {
|
||||
err = uv_tcp_try_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip4_any_,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
0);
|
||||
err = uv__tcp_try_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip4_any_,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
0);
|
||||
if (err)
|
||||
return err;
|
||||
if (handle->delayed_error)
|
||||
@@ -580,11 +589,12 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
}
|
||||
|
||||
if (!handle->tcp.serv.func_acceptex) {
|
||||
if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
|
||||
if (!uv__get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
|
||||
return WSAEAFNOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this flag is set, we already made this listen call in xfer. */
|
||||
if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
|
||||
listen(handle->socket, backlog) == SOCKET_ERROR) {
|
||||
return WSAGetLastError();
|
||||
@@ -597,9 +607,9 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
|
||||
: uv_simultaneous_server_accepts;
|
||||
|
||||
if(!handle->tcp.serv.accept_reqs) {
|
||||
handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
|
||||
uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
|
||||
if (handle->tcp.serv.accept_reqs == NULL) {
|
||||
handle->tcp.serv.accept_reqs =
|
||||
(uv_tcp_accept_t*)uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
|
||||
if (!handle->tcp.serv.accept_reqs) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
@@ -613,14 +623,14 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
if (req->event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
} else {
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
|
||||
uv_tcp_queue_accept(handle, req);
|
||||
uv__tcp_queue_accept(handle, req);
|
||||
}
|
||||
|
||||
/* Initialize other unused requests too, because uv_tcp_endgame doesn't
|
||||
@@ -640,7 +650,7 @@ 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_accept(uv_tcp_t* server, uv_tcp_t* client) {
|
||||
uv_loop_t* loop = server->loop;
|
||||
int err = 0;
|
||||
int family;
|
||||
@@ -662,7 +672,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
|
||||
family = AF_INET;
|
||||
}
|
||||
|
||||
err = uv_tcp_set_socket(client->loop,
|
||||
err = uv__tcp_set_socket(client->loop,
|
||||
client,
|
||||
req->accept_socket,
|
||||
family,
|
||||
@@ -670,7 +680,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
|
||||
if (err) {
|
||||
closesocket(req->accept_socket);
|
||||
} else {
|
||||
uv_connection_init((uv_stream_t*) client);
|
||||
uv__connection_init((uv_stream_t*) client);
|
||||
/* AcceptEx() implicitly binds the accepted socket. */
|
||||
client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
}
|
||||
@@ -683,7 +693,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
|
||||
if (!(server->flags & UV_HANDLE_CLOSING)) {
|
||||
/* Check if we're in a middle of changing the number of pending accepts. */
|
||||
if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
|
||||
uv_tcp_queue_accept(server, req);
|
||||
uv__tcp_queue_accept(server, req);
|
||||
} else {
|
||||
/* We better be switching to a single pending accept. */
|
||||
assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
|
||||
@@ -696,7 +706,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
|
||||
* All previously queued accept requests are now processed.
|
||||
* We now switch to queueing just a single accept.
|
||||
*/
|
||||
uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
|
||||
uv__tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
|
||||
server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
|
||||
server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
}
|
||||
@@ -709,7 +719,7 @@ 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,
|
||||
int uv__tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
@@ -722,25 +732,60 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
|
||||
* request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
|
||||
!handle->read_req.event_handle) {
|
||||
handle->read_req.event_handle == NULL) {
|
||||
handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!handle->read_req.event_handle) {
|
||||
if (handle->read_req.event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
}
|
||||
uv_tcp_queue_read(loop, handle);
|
||||
uv__tcp_queue_read(loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uv__is_loopback(const struct sockaddr_storage* storage) {
|
||||
const struct sockaddr_in* in4;
|
||||
const struct sockaddr_in6* in6;
|
||||
int i;
|
||||
|
||||
static int uv_tcp_try_connect(uv_connect_t* req,
|
||||
if (storage->ss_family == AF_INET) {
|
||||
in4 = (const struct sockaddr_in*) storage;
|
||||
return in4->sin_addr.S_un.S_un_b.s_b1 == 127;
|
||||
}
|
||||
if (storage->ss_family == AF_INET6) {
|
||||
in6 = (const struct sockaddr_in6*) storage;
|
||||
for (i = 0; i < 7; ++i) {
|
||||
if (in6->sin6_addr.u.Word[i] != 0)
|
||||
return 0;
|
||||
}
|
||||
return in6->sin6_addr.u.Word[7] == htons(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if Windows version is 10.0.16299 or later
|
||||
static int uv__is_fast_loopback_fail_supported(void) {
|
||||
OSVERSIONINFOW os_info;
|
||||
if (!pRtlGetVersion)
|
||||
return 0;
|
||||
pRtlGetVersion(&os_info);
|
||||
if (os_info.dwMajorVersion < 10)
|
||||
return 0;
|
||||
if (os_info.dwMajorVersion > 10)
|
||||
return 1;
|
||||
if (os_info.dwMinorVersion > 0)
|
||||
return 1;
|
||||
return os_info.dwBuildNumber >= 16299;
|
||||
}
|
||||
|
||||
static int uv__tcp_try_connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
uv_connect_cb cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
TCP_INITIAL_RTO_PARAMETERS retransmit_ioctl;
|
||||
const struct sockaddr* bind_addr;
|
||||
struct sockaddr_storage converted;
|
||||
BOOL success;
|
||||
@@ -751,9 +796,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (handle->delayed_error) {
|
||||
return handle->delayed_error;
|
||||
}
|
||||
if (handle->delayed_error != 0)
|
||||
goto out;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND)) {
|
||||
if (addrlen == sizeof(uv_addr_ip4_any_)) {
|
||||
@@ -763,24 +807,53 @@ static int uv_tcp_try_connect(uv_connect_t* req,
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
|
||||
err = uv__tcp_try_bind(handle, bind_addr, addrlen, 0);
|
||||
if (err)
|
||||
return err;
|
||||
if (handle->delayed_error)
|
||||
return handle->delayed_error;
|
||||
if (handle->delayed_error != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!handle->tcp.conn.func_connectex) {
|
||||
if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
|
||||
if (!uv__get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
|
||||
return WSAEAFNOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
/* This makes connect() fail instantly if the target port on the localhost
|
||||
* is not reachable, instead of waiting for 2s. We do not care if this fails.
|
||||
* This only works on Windows version 10.0.16299 and later.
|
||||
*/
|
||||
if (uv__is_fast_loopback_fail_supported() && uv__is_loopback(&converted)) {
|
||||
memset(&retransmit_ioctl, 0, sizeof(retransmit_ioctl));
|
||||
retransmit_ioctl.Rtt = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS;
|
||||
retransmit_ioctl.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS;
|
||||
WSAIoctl(handle->socket,
|
||||
SIO_TCP_INITIAL_RTO,
|
||||
&retransmit_ioctl,
|
||||
sizeof(retransmit_ioctl),
|
||||
NULL,
|
||||
0,
|
||||
&bytes,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
UV_REQ_INIT(req, UV_CONNECT);
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->cb = cb;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
|
||||
if (handle->delayed_error != 0) {
|
||||
/* Process the req without IOCP. */
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
success = handle->tcp.conn.func_connectex(handle->socket,
|
||||
(const struct sockaddr*) &converted,
|
||||
addrlen,
|
||||
@@ -793,7 +866,7 @@ static int uv_tcp_try_connect(uv_connect_t* req,
|
||||
/* Process the req without IOCP. */
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(success)) {
|
||||
/* The req will be processed with IOCP. */
|
||||
handle->reqs_pending++;
|
||||
@@ -830,7 +903,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_write(uv_loop_t* loop,
|
||||
int uv__tcp_write(uv_loop_t* loop,
|
||||
uv_write_t* req,
|
||||
uv_tcp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
@@ -847,7 +920,7 @@ int uv_tcp_write(uv_loop_t* loop,
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
if (req->event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
|
||||
@@ -868,7 +941,7 @@ int uv_tcp_write(uv_loop_t* loop,
|
||||
handle->reqs_pending++;
|
||||
handle->stream.conn.write_reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||
/* Request queued by the kernel. */
|
||||
req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
|
||||
@@ -881,7 +954,7 @@ int uv_tcp_write(uv_loop_t* loop,
|
||||
req->event_handle, post_write_completion, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
}
|
||||
} else {
|
||||
/* Send failed due to an error, report it later */
|
||||
@@ -890,7 +963,7 @@ int uv_tcp_write(uv_loop_t* loop,
|
||||
handle->stream.conn.write_reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -921,7 +994,7 @@ int uv__tcp_try_write(uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
void uv__process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_req_t* req) {
|
||||
DWORD bytes, flags, err;
|
||||
uv_buf_t buf;
|
||||
@@ -947,6 +1020,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
*/
|
||||
err = WSAECONNRESET;
|
||||
}
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
|
||||
handle->read_cb((uv_stream_t*)handle,
|
||||
uv_translate_sys_error(err),
|
||||
@@ -970,7 +1044,6 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
}
|
||||
handle->flags &= ~UV_HANDLE_READABLE;
|
||||
|
||||
buf.base = 0;
|
||||
buf.len = 0;
|
||||
@@ -1007,7 +1080,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
}
|
||||
} else {
|
||||
/* Connection closed */
|
||||
handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE);
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
|
||||
handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf);
|
||||
@@ -1028,6 +1101,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
* Unix. */
|
||||
err = WSAECONNRESET;
|
||||
}
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
|
||||
handle->read_cb((uv_stream_t*)handle,
|
||||
uv_translate_sys_error(err),
|
||||
@@ -1041,7 +1115,7 @@ done:
|
||||
/* Post another read if still reading and not closing. */
|
||||
if ((handle->flags & UV_HANDLE_READING) &&
|
||||
!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
uv_tcp_queue_read(loop, handle);
|
||||
uv__tcp_queue_read(loop, handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1049,7 +1123,7 @@ done:
|
||||
}
|
||||
|
||||
|
||||
void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_write_t* req) {
|
||||
int err;
|
||||
|
||||
@@ -1065,7 +1139,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle) {
|
||||
if (req->event_handle != NULL) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
@@ -1081,16 +1155,21 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
handle->stream.conn.write_reqs_pending--;
|
||||
if (handle->stream.conn.shutdown_req != NULL &&
|
||||
handle->stream.conn.write_reqs_pending == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
if (handle->stream.conn.write_reqs_pending == 0) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
closesocket(handle->socket);
|
||||
handle->socket = INVALID_SOCKET;
|
||||
}
|
||||
if (handle->stream.conn.shutdown_req != NULL) {
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
}
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_req_t* raw_req) {
|
||||
uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req;
|
||||
int err;
|
||||
@@ -1130,7 +1209,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
closesocket(req->accept_socket);
|
||||
req->accept_socket = INVALID_SOCKET;
|
||||
if (handle->flags & UV_HANDLE_LISTENING) {
|
||||
uv_tcp_queue_accept(handle, req);
|
||||
uv__tcp_queue_accept(handle, req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1138,7 +1217,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_connect_t* req) {
|
||||
int err;
|
||||
|
||||
@@ -1147,7 +1226,14 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
||||
err = 0;
|
||||
if (REQ_SUCCESS(req)) {
|
||||
if (handle->delayed_error) {
|
||||
/* To smooth over the differences between unixes errors that
|
||||
* were reported synchronously on the first connect can be delayed
|
||||
* until the next tick--which is now.
|
||||
*/
|
||||
err = handle->delayed_error;
|
||||
handle->delayed_error = 0;
|
||||
} else if (REQ_SUCCESS(req)) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* use UV_ECANCELED for consistency with Unix */
|
||||
err = ERROR_OPERATION_ABORTED;
|
||||
@@ -1156,7 +1242,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
SO_UPDATE_CONNECT_CONTEXT,
|
||||
NULL,
|
||||
0) == 0) {
|
||||
uv_connection_init((uv_stream_t*)handle);
|
||||
uv__connection_init((uv_stream_t*)handle);
|
||||
handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
loop->active_tcp_streams++;
|
||||
} else {
|
||||
@@ -1226,7 +1312,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
err = uv_tcp_set_socket(
|
||||
err = uv__tcp_set_socket(
|
||||
tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1);
|
||||
if (err) {
|
||||
closesocket(socket);
|
||||
@@ -1237,7 +1323,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET;
|
||||
|
||||
if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) {
|
||||
uv_connection_init((uv_stream_t*)tcp);
|
||||
uv__connection_init((uv_stream_t*)tcp);
|
||||
tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
}
|
||||
|
||||
@@ -1252,7 +1338,7 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
|
||||
if (handle->socket != INVALID_SOCKET) {
|
||||
err = uv__tcp_nodelay(handle, handle->socket, enable);
|
||||
if (err)
|
||||
return err;
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
@@ -1271,7 +1357,7 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
|
||||
if (handle->socket != INVALID_SOCKET) {
|
||||
err = uv__tcp_keepalive(handle, handle->socket, enable, delay);
|
||||
if (err)
|
||||
return err;
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
@@ -1318,9 +1404,24 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
|
||||
}
|
||||
|
||||
|
||||
static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
|
||||
SOCKET socket = tcp->socket;
|
||||
static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) {
|
||||
SOCKET socket;
|
||||
int non_ifs_lsp;
|
||||
int reading;
|
||||
int writing;
|
||||
|
||||
socket = tcp->socket;
|
||||
reading = tcp->flags & UV_HANDLE_READING;
|
||||
writing = tcp->stream.conn.write_reqs_pending > 0;
|
||||
if (!reading && !writing)
|
||||
return;
|
||||
|
||||
/* TODO: in libuv v2, keep explicit track of write_reqs, so we can cancel
|
||||
* them each explicitly with CancelIoEx (like unix). */
|
||||
if (reading)
|
||||
CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped);
|
||||
if (writing)
|
||||
CancelIo((HANDLE) socket);
|
||||
|
||||
/* Check if we have any non-IFS LSPs stacked on top of TCP */
|
||||
non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
|
||||
@@ -1340,71 +1441,41 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
|
||||
NULL,
|
||||
NULL) != 0) {
|
||||
/* Failed. We can't do CancelIo. */
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
assert(socket != 0 && socket != INVALID_SOCKET);
|
||||
|
||||
if (!CancelIo((HANDLE) socket)) {
|
||||
return GetLastError();
|
||||
if (socket != tcp->socket) {
|
||||
if (reading)
|
||||
CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped);
|
||||
if (writing)
|
||||
CancelIo((HANDLE) socket);
|
||||
}
|
||||
|
||||
/* It worked. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
|
||||
int close_socket = 1;
|
||||
|
||||
if (tcp->flags & UV_HANDLE_READ_PENDING) {
|
||||
/* In order for winsock to do a graceful close there must not be any any
|
||||
* pending reads, or the socket must be shut down for writing */
|
||||
if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
|
||||
/* Just do shutdown on non-shared sockets, which ensures graceful close. */
|
||||
shutdown(tcp->socket, SD_SEND);
|
||||
|
||||
} else if (uv_tcp_try_cancel_io(tcp) == 0) {
|
||||
/* In case of a shared socket, we try to cancel all outstanding I/O,. If
|
||||
* that works, don't close the socket yet - wait for the read req to
|
||||
* return and close the socket in uv_tcp_endgame. */
|
||||
close_socket = 0;
|
||||
|
||||
} else {
|
||||
/* When cancelling isn't possible - which could happen when an LSP is
|
||||
* present on an old Windows version, we will have to close the socket
|
||||
* with a read pending. That is not nice because trailing sent bytes may
|
||||
* not make it to the other side. */
|
||||
void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
|
||||
if (tcp->flags & UV_HANDLE_CONNECTION) {
|
||||
uv__tcp_try_cancel_reqs(tcp);
|
||||
if (tcp->flags & UV_HANDLE_READING) {
|
||||
uv_read_stop((uv_stream_t*) tcp);
|
||||
}
|
||||
|
||||
} else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
|
||||
tcp->tcp.serv.accept_reqs != NULL) {
|
||||
/* Under normal circumstances closesocket() will ensure that all pending
|
||||
* accept reqs are canceled. However, when the socket is shared the
|
||||
* presence of another reference to the socket in another process will keep
|
||||
* the accept reqs going, so we have to ensure that these are canceled. */
|
||||
if (uv_tcp_try_cancel_io(tcp) != 0) {
|
||||
/* When cancellation is not possible, there is another option: we can
|
||||
* close the incoming sockets, which will also cancel the accept
|
||||
* operations. However this is not cool because we might inadvertently
|
||||
* close a socket that just accepted a new connection, which will cause
|
||||
* the connection to be aborted. */
|
||||
} else {
|
||||
if (tcp->tcp.serv.accept_reqs != NULL) {
|
||||
/* First close the incoming sockets to cancel the accept operations before
|
||||
* we free their resources. */
|
||||
unsigned int i;
|
||||
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
|
||||
uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
|
||||
if (req->accept_socket != INVALID_SOCKET &&
|
||||
!HasOverlappedIoCompleted(&req->u.io.overlapped)) {
|
||||
if (req->accept_socket != INVALID_SOCKET) {
|
||||
closesocket(req->accept_socket);
|
||||
req->accept_socket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tcp->flags & UV_HANDLE_READING) {
|
||||
tcp->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(loop, tcp);
|
||||
assert(!(tcp->flags & UV_HANDLE_READING));
|
||||
}
|
||||
|
||||
if (tcp->flags & UV_HANDLE_LISTENING) {
|
||||
@@ -1412,17 +1483,22 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
|
||||
DECREASE_ACTIVE_COUNT(loop, tcp);
|
||||
}
|
||||
|
||||
if (close_socket) {
|
||||
/* If any overlapped req failed to cancel, calling `closesocket` now would
|
||||
* cause Win32 to send an RST packet. Try to avoid that for writes, if
|
||||
* possibly applicable, by waiting to process the completion notifications
|
||||
* first (which typically should be cancellations). There's not much we can
|
||||
* do about canceled reads, which also will generate an RST packet. */
|
||||
if (!(tcp->flags & UV_HANDLE_CONNECTION) ||
|
||||
tcp->stream.conn.write_reqs_pending == 0) {
|
||||
closesocket(tcp->socket);
|
||||
tcp->socket = INVALID_SOCKET;
|
||||
tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
uv__handle_closing(tcp);
|
||||
|
||||
if (tcp->reqs_pending == 0) {
|
||||
uv_want_endgame(tcp->loop, (uv_handle_t*)tcp);
|
||||
uv__want_endgame(tcp->loop, (uv_handle_t*)tcp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1444,7 +1520,7 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
err = uv_tcp_set_socket(handle->loop,
|
||||
err = uv__tcp_set_socket(handle->loop,
|
||||
handle,
|
||||
sock,
|
||||
protocol_info.iAddressFamily,
|
||||
@@ -1461,7 +1537,7 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
|
||||
saddr_len = sizeof(saddr);
|
||||
if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) {
|
||||
/* Socket is already connected. */
|
||||
uv_connection_init((uv_stream_t*) handle);
|
||||
uv__connection_init((uv_stream_t*) handle);
|
||||
handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
}
|
||||
}
|
||||
@@ -1479,7 +1555,7 @@ int uv__tcp_bind(uv_tcp_t* handle,
|
||||
unsigned int flags) {
|
||||
int err;
|
||||
|
||||
err = uv_tcp_try_bind(handle, addr, addrlen, flags);
|
||||
err = uv__tcp_try_bind(handle, addr, addrlen, flags);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
@@ -1497,9 +1573,124 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
uv_connect_cb cb) {
|
||||
int err;
|
||||
|
||||
err = uv_tcp_try_connect(req, handle, addr, addrlen, cb);
|
||||
err = uv__tcp_try_connect(req, handle, addr, addrlen, cb);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef WSA_FLAG_NO_HANDLE_INHERIT
|
||||
/* Added in Windows 7 SP1. Specify this to avoid race conditions, */
|
||||
/* but also manually clear the inherit flag in case this failed. */
|
||||
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
|
||||
#endif
|
||||
|
||||
int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
|
||||
SOCKET server = INVALID_SOCKET;
|
||||
SOCKET client0 = INVALID_SOCKET;
|
||||
SOCKET client1 = INVALID_SOCKET;
|
||||
SOCKADDR_IN name;
|
||||
LPFN_ACCEPTEX func_acceptex;
|
||||
WSAOVERLAPPED overlap;
|
||||
char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32];
|
||||
int namelen;
|
||||
int err;
|
||||
DWORD bytes;
|
||||
DWORD flags;
|
||||
DWORD client0_flags = WSA_FLAG_NO_HANDLE_INHERIT;
|
||||
DWORD client1_flags = WSA_FLAG_NO_HANDLE_INHERIT;
|
||||
|
||||
if (flags0 & UV_NONBLOCK_PIPE)
|
||||
client0_flags |= WSA_FLAG_OVERLAPPED;
|
||||
if (flags1 & UV_NONBLOCK_PIPE)
|
||||
client1_flags |= WSA_FLAG_OVERLAPPED;
|
||||
|
||||
server = WSASocketW(AF_INET, type, protocol, NULL, 0,
|
||||
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);
|
||||
if (server == INVALID_SOCKET)
|
||||
goto wsaerror;
|
||||
if (!SetHandleInformation((HANDLE) server, HANDLE_FLAG_INHERIT, 0))
|
||||
goto error;
|
||||
name.sin_family = AF_INET;
|
||||
name.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
name.sin_port = 0;
|
||||
if (bind(server, (SOCKADDR*) &name, sizeof(name)) != 0)
|
||||
goto wsaerror;
|
||||
if (listen(server, 1) != 0)
|
||||
goto wsaerror;
|
||||
namelen = sizeof(name);
|
||||
if (getsockname(server, (SOCKADDR*) &name, &namelen) != 0)
|
||||
goto wsaerror;
|
||||
client0 = WSASocketW(AF_INET, type, protocol, NULL, 0, client0_flags);
|
||||
if (client0 == INVALID_SOCKET)
|
||||
goto wsaerror;
|
||||
if (!SetHandleInformation((HANDLE) client0, HANDLE_FLAG_INHERIT, 0))
|
||||
goto error;
|
||||
if (connect(client0, (SOCKADDR*) &name, sizeof(name)) != 0)
|
||||
goto wsaerror;
|
||||
client1 = WSASocketW(AF_INET, type, protocol, NULL, 0, client1_flags);
|
||||
if (client1 == INVALID_SOCKET)
|
||||
goto wsaerror;
|
||||
if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0))
|
||||
goto error;
|
||||
if (!uv__get_acceptex_function(server, &func_acceptex)) {
|
||||
err = WSAEAFNOSUPPORT;
|
||||
goto cleanup;
|
||||
}
|
||||
memset(&overlap, 0, sizeof(overlap));
|
||||
if (!func_acceptex(server,
|
||||
client1,
|
||||
accept_buffer,
|
||||
0,
|
||||
sizeof(struct sockaddr_storage),
|
||||
sizeof(struct sockaddr_storage),
|
||||
&bytes,
|
||||
&overlap)) {
|
||||
err = WSAGetLastError();
|
||||
if (err == ERROR_IO_PENDING) {
|
||||
/* Result should complete immediately, since we already called connect,
|
||||
* but empirically, we sometimes have to poll the kernel a couple times
|
||||
* until it notices that. */
|
||||
while (!WSAGetOverlappedResult(client1, &overlap, &bytes, FALSE, &flags)) {
|
||||
err = WSAGetLastError();
|
||||
if (err != WSA_IO_INCOMPLETE)
|
||||
goto cleanup;
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
else {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
if (setsockopt(client1, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
|
||||
(char*) &server, sizeof(server)) != 0) {
|
||||
goto wsaerror;
|
||||
}
|
||||
|
||||
closesocket(server);
|
||||
|
||||
fds[0] = client0;
|
||||
fds[1] = client1;
|
||||
|
||||
return 0;
|
||||
|
||||
wsaerror:
|
||||
err = WSAGetLastError();
|
||||
goto cleanup;
|
||||
|
||||
error:
|
||||
err = GetLastError();
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
if (server != INVALID_SOCKET)
|
||||
closesocket(server);
|
||||
if (client0 != INVALID_SOCKET)
|
||||
closesocket(client0);
|
||||
if (client1 != INVALID_SOCKET)
|
||||
closesocket(client1);
|
||||
|
||||
assert(err);
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ static UINT __stdcall uv__thread_start(void* arg) {
|
||||
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);
|
||||
uv_key_set(&uv__current_thread_key, ctx.self);
|
||||
|
||||
ctx.entry(ctx.arg);
|
||||
|
||||
@@ -182,8 +182,20 @@ int uv_thread_create_ex(uv_thread_t* tid,
|
||||
|
||||
|
||||
uv_thread_t uv_thread_self(void) {
|
||||
uv_thread_t key;
|
||||
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
|
||||
return (uv_thread_t) uv_key_get(&uv__current_thread_key);
|
||||
key = uv_key_get(&uv__current_thread_key);
|
||||
if (key == NULL) {
|
||||
/* If the thread wasn't started by uv_thread_create (such as the main
|
||||
* thread), we assign an id to it now. */
|
||||
if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
||||
GetCurrentProcess(), &key, 0,
|
||||
FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
uv_fatal_error(GetLastError(), "DuplicateHandle");
|
||||
}
|
||||
uv_key_set(&uv__current_thread_key, key);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
@@ -237,113 +249,60 @@ void uv_mutex_unlock(uv_mutex_t* mutex) {
|
||||
LeaveCriticalSection(mutex);
|
||||
}
|
||||
|
||||
/* Ensure that the ABI for this type remains stable in v1.x */
|
||||
#ifdef _WIN64
|
||||
STATIC_ASSERT(sizeof(uv_rwlock_t) == 80);
|
||||
#else
|
||||
STATIC_ASSERT(sizeof(uv_rwlock_t) == 48);
|
||||
#endif
|
||||
|
||||
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;
|
||||
memset(rwlock, 0, sizeof(*rwlock));
|
||||
InitializeSRWLock(&rwlock->read_write_lock_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
|
||||
DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
|
||||
CloseHandle(rwlock->state_.write_semaphore_);
|
||||
/* SRWLock does not need explicit destruction so long as there are no waiting threads
|
||||
See: https://docs.microsoft.com/windows/win32/api/synchapi/nf-synchapi-initializesrwlock#remarks */
|
||||
}
|
||||
|
||||
|
||||
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_);
|
||||
AcquireSRWLockShared(&rwlock->read_write_lock_);
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
|
||||
int err;
|
||||
|
||||
if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
|
||||
if (!TryAcquireSRWLockShared(&rwlock->read_write_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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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_);
|
||||
ReleaseSRWLockShared(&rwlock->read_write_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");
|
||||
AcquireSRWLockExclusive(&rwlock->read_write_lock_);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
if (!TryAcquireSRWLockExclusive(&rwlock->read_write_lock_))
|
||||
return UV_EBUSY;
|
||||
else
|
||||
uv_fatal_error(GetLastError(), "WaitForSingleObject");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
|
||||
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
|
||||
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
|
||||
ReleaseSRWLockExclusive(&rwlock->read_write_lock_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -60,7 +60,7 @@ int uv_udp_getsockname(const uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
|
||||
static int uv__udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
|
||||
int family) {
|
||||
DWORD yes = 1;
|
||||
WSAPROTOCOL_INFOW info;
|
||||
@@ -106,8 +106,8 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
|
||||
FILE_SKIP_SET_EVENT_ON_HANDLE |
|
||||
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
|
||||
handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
|
||||
handle->func_wsarecv = uv_wsarecv_workaround;
|
||||
handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
|
||||
handle->func_wsarecv = uv__wsarecv_workaround;
|
||||
handle->func_wsarecvfrom = uv__wsarecvfrom_workaround;
|
||||
} else if (GetLastError() != ERROR_INVALID_FUNCTION) {
|
||||
return GetLastError();
|
||||
}
|
||||
@@ -125,17 +125,10 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, 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;
|
||||
|
||||
int uv__udp_init_ex(uv_loop_t* loop,
|
||||
uv_udp_t* handle,
|
||||
unsigned flags,
|
||||
int domain) {
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
|
||||
handle->socket = INVALID_SOCKET;
|
||||
handle->reqs_pending = 0;
|
||||
@@ -162,7 +155,7 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
err = uv_udp_set_socket(handle->loop, handle, sock, domain);
|
||||
err = uv__udp_set_socket(handle->loop, handle, sock, domain);
|
||||
if (err) {
|
||||
closesocket(sock);
|
||||
QUEUE_REMOVE(&handle->handle_queue);
|
||||
@@ -174,12 +167,7 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
|
||||
}
|
||||
|
||||
|
||||
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
void uv__udp_close(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
uv_udp_recv_stop(handle);
|
||||
closesocket(handle->socket);
|
||||
handle->socket = INVALID_SOCKET;
|
||||
@@ -187,12 +175,12 @@ void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->reqs_pending == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
uv__want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
void uv__udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
@@ -201,10 +189,15 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
static int uv_udp_maybe_bind(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags) {
|
||||
int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__udp_maybe_bind(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags) {
|
||||
int r;
|
||||
int err;
|
||||
DWORD no = 0;
|
||||
@@ -223,7 +216,7 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
|
||||
err = uv__udp_set_socket(handle->loop, handle, sock, addr->sa_family);
|
||||
if (err) {
|
||||
closesocket(sock);
|
||||
return err;
|
||||
@@ -271,7 +264,7 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
static void uv__udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
uv_req_t* req;
|
||||
uv_buf_t buf;
|
||||
DWORD bytes, flags;
|
||||
@@ -291,7 +284,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
||||
|
||||
handle->recv_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
|
||||
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &handle->recv_buffer);
|
||||
if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
|
||||
return;
|
||||
@@ -318,7 +311,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
req->u.io.overlapped.InternalHigh = bytes;
|
||||
handle->reqs_pending++;
|
||||
uv_insert_pending_req(loop, req);
|
||||
uv__insert_pending_req(loop, req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||
/* The req will be processed with IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
@@ -326,7 +319,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
} else {
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv_insert_pending_req(loop, req);
|
||||
uv__insert_pending_req(loop, req);
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
|
||||
@@ -350,7 +343,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
req->u.io.overlapped.InternalHigh = bytes;
|
||||
handle->reqs_pending++;
|
||||
uv_insert_pending_req(loop, req);
|
||||
uv__insert_pending_req(loop, req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||
/* The req will be processed with IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
@@ -358,7 +351,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
} else {
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv_insert_pending_req(loop, req);
|
||||
uv__insert_pending_req(loop, req);
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
}
|
||||
@@ -374,10 +367,10 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
return UV_EALREADY;
|
||||
}
|
||||
|
||||
err = uv_udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip4_any_,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
0);
|
||||
err = uv__udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip4_any_,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
0);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
@@ -391,7 +384,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
/* If reading was stopped and then started again, there could still be a recv
|
||||
* request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
||||
uv_udp_queue_recv(loop, handle);
|
||||
uv__udp_queue_recv(loop, handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -440,7 +433,7 @@ static int uv__send(uv_udp_send_t* req,
|
||||
handle->send_queue_size += req->u.io.queued_bytes;
|
||||
handle->send_queue_count++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||
/* Request queued by the kernel. */
|
||||
req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
|
||||
@@ -457,7 +450,7 @@ static int uv__send(uv_udp_send_t* req,
|
||||
}
|
||||
|
||||
|
||||
void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
uv_req_t* req) {
|
||||
uv_buf_t buf;
|
||||
int partial;
|
||||
@@ -508,7 +501,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
/* Do a nonblocking receive.
|
||||
* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
goto done;
|
||||
@@ -561,14 +554,14 @@ done:
|
||||
/* Post another read if still reading and not closing. */
|
||||
if ((handle->flags & UV_HANDLE_READING) &&
|
||||
!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
uv_udp_queue_recv(loop, handle);
|
||||
uv__udp_queue_recv(loop, handle);
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
uv_udp_send_t* req) {
|
||||
int err;
|
||||
|
||||
@@ -605,10 +598,10 @@ static int uv__udp_set_membership4(uv_udp_t* handle,
|
||||
return UV_EINVAL;
|
||||
|
||||
/* If the socket is unbound, bind to inaddr_any. */
|
||||
err = uv_udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip4_any_,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
UV_UDP_REUSEADDR);
|
||||
err = uv__udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip4_any_,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
UV_UDP_REUSEADDR);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
@@ -659,10 +652,10 @@ int uv__udp_set_membership6(uv_udp_t* handle,
|
||||
if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
|
||||
return UV_EINVAL;
|
||||
|
||||
err = uv_udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip6_any_,
|
||||
sizeof(uv_addr_ip6_any_),
|
||||
UV_UDP_REUSEADDR);
|
||||
err = uv__udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip6_any_,
|
||||
sizeof(uv_addr_ip6_any_),
|
||||
UV_UDP_REUSEADDR);
|
||||
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
@@ -702,6 +695,115 @@ int uv__udp_set_membership6(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
static int uv__udp_set_source_membership4(uv_udp_t* handle,
|
||||
const struct sockaddr_in* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const struct sockaddr_in* source_addr,
|
||||
uv_membership membership) {
|
||||
struct ip_mreq_source mreq;
|
||||
int optname;
|
||||
int err;
|
||||
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* If the socket is unbound, bind to inaddr_any. */
|
||||
err = uv__udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip4_any_,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
UV_UDP_REUSEADDR);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
|
||||
if (interface_addr != NULL) {
|
||||
err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
|
||||
mreq.imr_sourceaddr.s_addr = source_addr->sin_addr.s_addr;
|
||||
|
||||
if (membership == UV_JOIN_GROUP)
|
||||
optname = IP_ADD_SOURCE_MEMBERSHIP;
|
||||
else if (membership == UV_LEAVE_GROUP)
|
||||
optname = IP_DROP_SOURCE_MEMBERSHIP;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setsockopt(handle->socket,
|
||||
IPPROTO_IP,
|
||||
optname,
|
||||
(char*) &mreq,
|
||||
sizeof(mreq)) == SOCKET_ERROR) {
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_set_source_membership6(uv_udp_t* handle,
|
||||
const struct sockaddr_in6* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const struct sockaddr_in6* source_addr,
|
||||
uv_membership membership) {
|
||||
struct group_source_req mreq;
|
||||
struct sockaddr_in6 addr6;
|
||||
int optname;
|
||||
int err;
|
||||
|
||||
STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
|
||||
STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
|
||||
|
||||
if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
|
||||
return UV_EINVAL;
|
||||
|
||||
err = uv__udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip6_any_,
|
||||
sizeof(uv_addr_ip6_any_),
|
||||
UV_UDP_REUSEADDR);
|
||||
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
|
||||
if (interface_addr != NULL) {
|
||||
err = uv_ip6_addr(interface_addr, 0, &addr6);
|
||||
if (err)
|
||||
return err;
|
||||
mreq.gsr_interface = addr6.sin6_scope_id;
|
||||
} else {
|
||||
mreq.gsr_interface = 0;
|
||||
}
|
||||
|
||||
memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
|
||||
memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
|
||||
|
||||
if (membership == UV_JOIN_GROUP)
|
||||
optname = MCAST_JOIN_SOURCE_GROUP;
|
||||
else if (membership == UV_LEAVE_GROUP)
|
||||
optname = MCAST_LEAVE_SOURCE_GROUP;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setsockopt(handle->socket,
|
||||
IPPROTO_IPV6,
|
||||
optname,
|
||||
(char*) &mreq,
|
||||
sizeof(mreq)) == SOCKET_ERROR) {
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
@@ -718,6 +820,50 @@ int uv_udp_set_membership(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_source_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const char* source_addr,
|
||||
uv_membership membership) {
|
||||
int err;
|
||||
struct sockaddr_storage mcast_addr;
|
||||
struct sockaddr_in* mcast_addr4;
|
||||
struct sockaddr_in6* mcast_addr6;
|
||||
struct sockaddr_storage src_addr;
|
||||
struct sockaddr_in* src_addr4;
|
||||
struct sockaddr_in6* src_addr6;
|
||||
|
||||
mcast_addr4 = (struct sockaddr_in*)&mcast_addr;
|
||||
mcast_addr6 = (struct sockaddr_in6*)&mcast_addr;
|
||||
src_addr4 = (struct sockaddr_in*)&src_addr;
|
||||
src_addr6 = (struct sockaddr_in6*)&src_addr;
|
||||
|
||||
err = uv_ip4_addr(multicast_addr, 0, mcast_addr4);
|
||||
if (err) {
|
||||
err = uv_ip6_addr(multicast_addr, 0, mcast_addr6);
|
||||
if (err)
|
||||
return err;
|
||||
err = uv_ip6_addr(source_addr, 0, src_addr6);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_source_membership6(handle,
|
||||
mcast_addr6,
|
||||
interface_addr,
|
||||
src_addr6,
|
||||
membership);
|
||||
}
|
||||
|
||||
err = uv_ip4_addr(source_addr, 0, src_addr4);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_source_membership4(handle,
|
||||
mcast_addr4,
|
||||
interface_addr,
|
||||
src_addr4,
|
||||
membership);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
|
||||
struct sockaddr_storage addr_st;
|
||||
struct sockaddr_in* addr4;
|
||||
@@ -816,10 +962,10 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
err = uv_udp_set_socket(handle->loop,
|
||||
handle,
|
||||
sock,
|
||||
protocol_info.iAddressFamily);
|
||||
err = uv__udp_set_socket(handle->loop,
|
||||
handle,
|
||||
sock,
|
||||
protocol_info.iAddressFamily);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
@@ -898,7 +1044,7 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
unsigned int flags) {
|
||||
int err;
|
||||
|
||||
err = uv_udp_maybe_bind(handle, addr, addrlen, flags);
|
||||
err = uv__udp_maybe_bind(handle, addr, addrlen, flags);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
@@ -920,14 +1066,14 @@ int uv__udp_connect(uv_udp_t* handle,
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
err = connect(handle->socket, addr, addrlen);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
handle->flags |= UV_HANDLE_UDP_CONNECTED;
|
||||
|
||||
@@ -937,13 +1083,13 @@ int uv__udp_connect(uv_udp_t* handle,
|
||||
|
||||
int uv__udp_disconnect(uv_udp_t* handle) {
|
||||
int err;
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
err = connect(handle->socket, &addr, sizeof(addr));
|
||||
err = connect(handle->socket, (const sockaddr*) &addr, sizeof(addr));
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
|
||||
return 0;
|
||||
@@ -971,7 +1117,7 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
@@ -1013,7 +1159,7 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
@@ -30,12 +30,14 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
#include <winsock2.h>
|
||||
#include <winperf.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <windows.h>
|
||||
/* clang-format on */
|
||||
#include <userenv.h>
|
||||
#include <math.h>
|
||||
|
||||
@@ -60,8 +62,10 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* Maximum environment variable size, including the terminating null */
|
||||
#define MAX_ENV_VAR_LENGTH 32767
|
||||
/* A RtlGenRandom() by any other name... */
|
||||
extern "C" {
|
||||
extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
|
||||
}
|
||||
|
||||
/* Cached copy of the process title, plus a mutex guarding it. */
|
||||
static char *process_title;
|
||||
@@ -73,8 +77,8 @@ static CRITICAL_SECTION process_title_lock;
|
||||
#pragma comment(lib, "Userenv.lib")
|
||||
#pragma comment(lib, "kernel32.lib")
|
||||
|
||||
/* Interval (in seconds) of the high-resolution clock. */
|
||||
static double hrtime_interval_ = 0;
|
||||
/* Frequency of the high-resolution clock. */
|
||||
static uint64_t hrtime_frequency_ = 0;
|
||||
|
||||
|
||||
/*
|
||||
@@ -90,9 +94,9 @@ void uv__util_init(void) {
|
||||
* and precompute its reciprocal.
|
||||
*/
|
||||
if (QueryPerformanceFrequency(&perf_frequency)) {
|
||||
hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
|
||||
hrtime_frequency_ = perf_frequency.QuadPart;
|
||||
} else {
|
||||
hrtime_interval_= 0;
|
||||
uv_fatal_error(GetLastError(), "QueryPerformanceFrequency");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,20 +161,26 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
|
||||
|
||||
int uv_cwd(char* buffer, size_t* size) {
|
||||
DWORD utf16_len;
|
||||
WCHAR utf16_buffer[MAX_PATH];
|
||||
WCHAR *utf16_buffer;
|
||||
int r;
|
||||
|
||||
if (buffer == NULL || size == NULL) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
|
||||
utf16_len = GetCurrentDirectoryW(0, NULL);
|
||||
if (utf16_len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (utf16_len > MAX_PATH) {
|
||||
/* This should be impossible; however the CRT has a code path to deal with
|
||||
* this scenario, so I added a check anyway. */
|
||||
return UV_EIO;
|
||||
}
|
||||
utf16_buffer = (WCHAR*)uv__malloc(utf16_len * sizeof(WCHAR));
|
||||
if (utf16_buffer == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
|
||||
if (utf16_len == 0) {
|
||||
uv__free(utf16_buffer);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* utf16_len contains the length, *not* including the terminating null. */
|
||||
@@ -194,8 +204,10 @@ int uv_cwd(char* buffer, size_t* size) {
|
||||
NULL,
|
||||
NULL);
|
||||
if (r == 0) {
|
||||
uv__free(utf16_buffer);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (r > (int) *size) {
|
||||
uv__free(utf16_buffer);
|
||||
*size = r;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
@@ -209,6 +221,8 @@ int uv_cwd(char* buffer, size_t* size) {
|
||||
*size > INT_MAX ? INT_MAX : (int) *size,
|
||||
NULL,
|
||||
NULL);
|
||||
uv__free(utf16_buffer);
|
||||
|
||||
if (r == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
@@ -219,43 +233,61 @@ int uv_cwd(char* buffer, size_t* size) {
|
||||
|
||||
|
||||
int uv_chdir(const char* dir) {
|
||||
WCHAR utf16_buffer[MAX_PATH];
|
||||
size_t utf16_len;
|
||||
WCHAR *utf16_buffer;
|
||||
size_t utf16_len, new_utf16_len;
|
||||
WCHAR drive_letter, env_var[4];
|
||||
|
||||
if (dir == NULL) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
utf16_len = MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
dir,
|
||||
-1,
|
||||
NULL,
|
||||
0);
|
||||
if (utf16_len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
utf16_buffer = (WCHAR*)uv__malloc(utf16_len * sizeof(WCHAR));
|
||||
if (utf16_buffer == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
dir,
|
||||
-1,
|
||||
utf16_buffer,
|
||||
MAX_PATH) == 0) {
|
||||
DWORD error = GetLastError();
|
||||
/* The maximum length of the current working directory is 260 chars,
|
||||
* including terminating null. If it doesn't fit, the path name must be too
|
||||
* long. */
|
||||
if (error == ERROR_INSUFFICIENT_BUFFER) {
|
||||
return UV_ENAMETOOLONG;
|
||||
} else {
|
||||
return uv_translate_sys_error(error);
|
||||
}
|
||||
utf16_len) == 0) {
|
||||
uv__free(utf16_buffer);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
if (!SetCurrentDirectoryW(utf16_buffer)) {
|
||||
uv__free(utf16_buffer);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* Windows stores the drive-local path in an "hidden" environment variable,
|
||||
* which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
|
||||
* this, so we'll have to do it. */
|
||||
utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
|
||||
new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
|
||||
if (new_utf16_len > utf16_len ) {
|
||||
uv__free(utf16_buffer);
|
||||
utf16_buffer = (WCHAR*)uv__malloc(new_utf16_len * sizeof(WCHAR));
|
||||
if (utf16_buffer == NULL) {
|
||||
/* When updating the environment variable fails, return UV_OK anyway.
|
||||
* We did successfully change current working directory, only updating
|
||||
* hidden env variable failed. */
|
||||
return 0;
|
||||
}
|
||||
new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer);
|
||||
}
|
||||
if (utf16_len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (utf16_len > MAX_PATH) {
|
||||
return UV_EIO;
|
||||
uv__free(utf16_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The returned directory should not have a trailing slash, unless it points
|
||||
@@ -287,11 +319,10 @@ int uv_chdir(const char* dir) {
|
||||
env_var[2] = L':';
|
||||
env_var[3] = L'\0';
|
||||
|
||||
if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
SetEnvironmentVariableW(env_var, utf16_buffer);
|
||||
}
|
||||
|
||||
uv__free(utf16_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -364,6 +395,10 @@ char** uv_setup_args(int argc, char** argv) {
|
||||
}
|
||||
|
||||
|
||||
void uv__process_title_cleanup(void) {
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
int err;
|
||||
int length;
|
||||
@@ -465,23 +500,25 @@ uint64_t uv_hrtime(void) {
|
||||
return uv__hrtime(UV__NANOSEC);
|
||||
}
|
||||
|
||||
uint64_t uv__hrtime(double scale) {
|
||||
uint64_t uv__hrtime(unsigned int scale) {
|
||||
LARGE_INTEGER counter;
|
||||
double scaled_freq;
|
||||
double result;
|
||||
|
||||
/* If the performance interval is zero, there's no support. */
|
||||
if (hrtime_interval_ == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(hrtime_frequency_ != 0);
|
||||
assert(scale != 0);
|
||||
if (!QueryPerformanceCounter(&counter)) {
|
||||
return 0;
|
||||
uv_fatal_error(GetLastError(), "QueryPerformanceCounter");
|
||||
}
|
||||
assert(counter.QuadPart != 0);
|
||||
|
||||
/* Because we have no guarantee about the order of magnitude of the
|
||||
* performance counter interval, integer math could cause this computation
|
||||
* to overflow. Therefore we resort to floating point math.
|
||||
*/
|
||||
return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale);
|
||||
scaled_freq = (double) hrtime_frequency_ / scale;
|
||||
result = (double) counter.QuadPart / scaled_freq;
|
||||
return (uint64_t) result;
|
||||
}
|
||||
|
||||
|
||||
@@ -502,103 +539,25 @@ int uv_resident_set_memory(size_t* rss) {
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
BYTE stack_buffer[4096];
|
||||
BYTE* malloced_buffer = NULL;
|
||||
BYTE* buffer = (BYTE*) stack_buffer;
|
||||
size_t buffer_size = sizeof(stack_buffer);
|
||||
DWORD data_size;
|
||||
*uptime = GetTickCount64() / 1000.0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PERF_DATA_BLOCK* data_block;
|
||||
PERF_OBJECT_TYPE* object_type;
|
||||
PERF_COUNTER_DEFINITION* counter_definition;
|
||||
|
||||
DWORD i;
|
||||
unsigned int uv_available_parallelism(void) {
|
||||
SYSTEM_INFO info;
|
||||
unsigned rc;
|
||||
|
||||
for (;;) {
|
||||
LONG result;
|
||||
/* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
|
||||
* with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
|
||||
*/
|
||||
GetSystemInfo(&info);
|
||||
|
||||
data_size = (DWORD) buffer_size;
|
||||
result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
|
||||
L"2",
|
||||
NULL,
|
||||
NULL,
|
||||
buffer,
|
||||
&data_size);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
break;
|
||||
} else if (result != ERROR_MORE_DATA) {
|
||||
*uptime = 0;
|
||||
return uv_translate_sys_error(result);
|
||||
}
|
||||
rc = info.dwNumberOfProcessors;
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
|
||||
buffer_size *= 2;
|
||||
/* Don't let the buffer grow infinitely. */
|
||||
if (buffer_size > 1 << 20) {
|
||||
goto internalError;
|
||||
}
|
||||
|
||||
uv__free(malloced_buffer);
|
||||
|
||||
buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
|
||||
if (malloced_buffer == NULL) {
|
||||
*uptime = 0;
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (data_size < sizeof(*data_block))
|
||||
goto internalError;
|
||||
|
||||
data_block = (PERF_DATA_BLOCK*) buffer;
|
||||
|
||||
if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
|
||||
goto internalError;
|
||||
|
||||
if (data_size < data_block->HeaderLength + sizeof(*object_type))
|
||||
goto internalError;
|
||||
|
||||
object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
|
||||
|
||||
if (object_type->NumInstances != PERF_NO_INSTANCES)
|
||||
goto internalError;
|
||||
|
||||
counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
|
||||
data_block->HeaderLength + object_type->HeaderLength);
|
||||
for (i = 0; i < object_type->NumCounters; i++) {
|
||||
if ((BYTE*) counter_definition + sizeof(*counter_definition) >
|
||||
buffer + data_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (counter_definition->CounterNameTitleIndex == 674 &&
|
||||
counter_definition->CounterSize == sizeof(uint64_t)) {
|
||||
if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
|
||||
!(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
|
||||
goto internalError;
|
||||
} else {
|
||||
BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
|
||||
counter_definition->CounterOffset;
|
||||
uint64_t value = *((uint64_t*) address);
|
||||
*uptime = floor((double) (object_type->PerfTime.QuadPart - value) /
|
||||
(double) object_type->PerfFreq.QuadPart);
|
||||
uv__free(malloced_buffer);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
counter_definition = (PERF_COUNTER_DEFINITION*)
|
||||
((BYTE*) counter_definition + counter_definition->ByteLength);
|
||||
}
|
||||
|
||||
/* If we get here, the uptime value was not found. */
|
||||
uv__free(malloced_buffer);
|
||||
*uptime = 0;
|
||||
return UV_ENOSYS;
|
||||
|
||||
internalError:
|
||||
uv__free(malloced_buffer);
|
||||
*uptime = 0;
|
||||
return UV_EIO;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -727,17 +686,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static int is_windows_version_or_greater(DWORD os_major,
|
||||
DWORD os_minor,
|
||||
WORD service_pack_major,
|
||||
@@ -1178,20 +1126,29 @@ int uv_os_homedir(char* buffer, size_t* size) {
|
||||
|
||||
|
||||
int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
wchar_t path[MAX_PATH + 1];
|
||||
wchar_t *path;
|
||||
DWORD bufsize;
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
len = GetTempPathW(MAX_PATH + 1, path);
|
||||
|
||||
len = 0;
|
||||
len = GetTempPathW(0, NULL);
|
||||
if (len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (len > MAX_PATH + 1) {
|
||||
/* This should not be possible */
|
||||
return UV_EIO;
|
||||
}
|
||||
/* Include space for terminating null char. */
|
||||
len += 1;
|
||||
path = (wchar_t*)uv__malloc(len * sizeof(wchar_t));
|
||||
if (path == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
len = GetTempPathW(len, path);
|
||||
|
||||
if (len == 0) {
|
||||
uv__free(path);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* The returned directory should not have a trailing slash, unless it points
|
||||
@@ -1206,8 +1163,10 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (bufsize == 0) {
|
||||
uv__free(path);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (bufsize > *size) {
|
||||
uv__free(path);
|
||||
*size = bufsize;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
@@ -1221,6 +1180,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
*size,
|
||||
NULL,
|
||||
NULL);
|
||||
uv__free(path);
|
||||
|
||||
if (bufsize == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
@@ -1332,7 +1292,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
(*utf16)[bufsize] = '\0';
|
||||
(*utf16)[bufsize] = L'\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1340,7 +1300,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
HANDLE token;
|
||||
wchar_t username[UNLEN + 1];
|
||||
wchar_t path[MAX_PATH];
|
||||
wchar_t *path;
|
||||
DWORD bufsize;
|
||||
int r;
|
||||
|
||||
@@ -1351,15 +1311,24 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
bufsize = ARRAY_SIZE(path);
|
||||
bufsize = 0;
|
||||
GetUserProfileDirectoryW(token, NULL, &bufsize);
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
r = GetLastError();
|
||||
CloseHandle(token);
|
||||
return uv_translate_sys_error(r);
|
||||
}
|
||||
|
||||
path = (wchar_t*)uv__malloc(bufsize * sizeof(wchar_t));
|
||||
if (path == NULL) {
|
||||
CloseHandle(token);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
|
||||
r = GetLastError();
|
||||
CloseHandle(token);
|
||||
|
||||
/* This should not be possible */
|
||||
if (r == ERROR_INSUFFICIENT_BUFFER)
|
||||
return UV_ENOMEM;
|
||||
|
||||
uv__free(path);
|
||||
return uv_translate_sys_error(r);
|
||||
}
|
||||
|
||||
@@ -1369,6 +1338,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
bufsize = ARRAY_SIZE(username);
|
||||
if (!GetUserNameW(username, &bufsize)) {
|
||||
r = GetLastError();
|
||||
uv__free(path);
|
||||
|
||||
/* This should not be possible */
|
||||
if (r == ERROR_INSUFFICIENT_BUFFER)
|
||||
@@ -1379,6 +1349,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
|
||||
pwd->homedir = NULL;
|
||||
r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
|
||||
uv__free(path);
|
||||
|
||||
if (r != 0)
|
||||
return r;
|
||||
@@ -1404,8 +1375,81 @@ int uv_os_get_passwd(uv_passwd_t* pwd) {
|
||||
}
|
||||
|
||||
|
||||
int uv_os_environ(uv_env_item_t** envitems, int* count) {
|
||||
wchar_t* env;
|
||||
wchar_t* penv;
|
||||
int i, cnt;
|
||||
uv_env_item_t* envitem;
|
||||
|
||||
*envitems = NULL;
|
||||
*count = 0;
|
||||
|
||||
env = GetEnvironmentStringsW();
|
||||
if (env == NULL)
|
||||
return 0;
|
||||
|
||||
for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
|
||||
|
||||
*envitems = (uv_env_item_t*)uv__calloc(i, sizeof(**envitems));
|
||||
if (*envitems == NULL) {
|
||||
FreeEnvironmentStringsW(env);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
penv = env;
|
||||
cnt = 0;
|
||||
|
||||
while (*penv != L'\0' && cnt < i) {
|
||||
char* buf;
|
||||
char* ptr;
|
||||
|
||||
if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
|
||||
goto fail;
|
||||
|
||||
/* Using buf + 1 here because we know that `buf` has length at least 1,
|
||||
* and some special environment variables on Windows start with a = sign. */
|
||||
ptr = strchr(buf + 1, '=');
|
||||
if (ptr == NULL) {
|
||||
uv__free(buf);
|
||||
goto do_continue;
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
envitem = &(*envitems)[cnt];
|
||||
envitem->name = buf;
|
||||
envitem->value = ptr + 1;
|
||||
|
||||
cnt++;
|
||||
|
||||
do_continue:
|
||||
penv += wcslen(penv) + 1;
|
||||
}
|
||||
|
||||
FreeEnvironmentStringsW(env);
|
||||
|
||||
*count = cnt;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
FreeEnvironmentStringsW(env);
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
envitem = &(*envitems)[cnt];
|
||||
uv__free(envitem->name);
|
||||
}
|
||||
uv__free(*envitems);
|
||||
|
||||
*envitems = NULL;
|
||||
*count = 0;
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
wchar_t var[MAX_ENV_VAR_LENGTH];
|
||||
wchar_t fastvar[512];
|
||||
wchar_t* var;
|
||||
DWORD varlen;
|
||||
wchar_t* name_w;
|
||||
DWORD bufsize;
|
||||
size_t len;
|
||||
@@ -1419,27 +1463,52 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
|
||||
var = fastvar;
|
||||
varlen = ARRAY_SIZE(fastvar);
|
||||
|
||||
for (;;) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
len = GetEnvironmentVariableW(name_w, var, varlen);
|
||||
|
||||
if (len < varlen)
|
||||
break;
|
||||
|
||||
/* Try repeatedly because we might have been preempted by another thread
|
||||
* modifying the environment variable just as we're trying to read it.
|
||||
*/
|
||||
if (var != fastvar)
|
||||
uv__free(var);
|
||||
|
||||
varlen = 1 + len;
|
||||
var = (wchar_t*)uv__malloc(varlen * sizeof(*var));
|
||||
|
||||
if (var == NULL) {
|
||||
r = UV_ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
uv__free(name_w);
|
||||
assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
|
||||
name_w = NULL;
|
||||
|
||||
if (len == 0) {
|
||||
r = GetLastError();
|
||||
|
||||
if (r == ERROR_ENVVAR_NOT_FOUND)
|
||||
return UV_ENOENT;
|
||||
|
||||
return uv_translate_sys_error(r);
|
||||
if (r != ERROR_SUCCESS) {
|
||||
r = uv_translate_sys_error(r);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check how much space we need */
|
||||
bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (bufsize == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto fail;
|
||||
} else if (bufsize > *size) {
|
||||
*size = bufsize;
|
||||
return UV_ENOBUFS;
|
||||
r = UV_ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Convert to UTF-8 */
|
||||
@@ -1452,11 +1521,23 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (bufsize == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
if (bufsize == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*size = bufsize - 1;
|
||||
return 0;
|
||||
r = 0;
|
||||
|
||||
fail:
|
||||
|
||||
if (name_w != NULL)
|
||||
uv__free(name_w);
|
||||
|
||||
if (var != fastvar)
|
||||
uv__free(var);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -1514,26 +1595,36 @@ int uv_os_unsetenv(const char* name) {
|
||||
|
||||
|
||||
int uv_os_gethostname(char* buffer, size_t* size) {
|
||||
char buf[UV_MAXHOSTNAMESIZE];
|
||||
WCHAR buf[UV_MAXHOSTNAMESIZE];
|
||||
size_t len;
|
||||
char* utf8_str;
|
||||
int convert_result;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv__once_init(); /* Initialize winsock */
|
||||
|
||||
if (gethostname(buf, sizeof(buf)) != 0)
|
||||
if (pGetHostNameW == NULL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
|
||||
len = strlen(buf);
|
||||
convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
|
||||
|
||||
if (convert_result != 0)
|
||||
return convert_result;
|
||||
|
||||
len = strlen(utf8_str);
|
||||
if (len >= *size) {
|
||||
*size = len + 1;
|
||||
uv__free(utf8_str);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, buf, len + 1);
|
||||
memcpy(buffer, utf8_str, len + 1);
|
||||
uv__free(utf8_str);
|
||||
*size = len;
|
||||
return 0;
|
||||
}
|
||||
@@ -1658,7 +1749,9 @@ int uv_os_uname(uv_utsname_t* buffer) {
|
||||
pRtlGetVersion(&os_info);
|
||||
} else {
|
||||
/* Silence GetVersionEx() deprecation warning. */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(suppress : 4996)
|
||||
#endif
|
||||
if (GetVersionExW(&os_info) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
@@ -1725,7 +1818,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
|
||||
"MINGW32_NT-%u.%u",
|
||||
(unsigned int) os_info.dwMajorVersion,
|
||||
(unsigned int) os_info.dwMinorVersion);
|
||||
assert(r < sizeof(buffer->sysname));
|
||||
assert((size_t)r < sizeof(buffer->sysname));
|
||||
#else
|
||||
uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
|
||||
#endif
|
||||
@@ -1737,7 +1830,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
|
||||
(unsigned int) os_info.dwMajorVersion,
|
||||
(unsigned int) os_info.dwMinorVersion,
|
||||
(unsigned int) os_info.dwBuildNumber);
|
||||
assert(r < sizeof(buffer->release));
|
||||
assert((size_t)r < sizeof(buffer->release));
|
||||
|
||||
/* Populate the machine field. */
|
||||
GetSystemInfo(&system_info);
|
||||
@@ -1809,3 +1902,17 @@ int uv_gettimeofday(uv_timeval64_t* tv) {
|
||||
tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv__random_rtlgenrandom(void* buf, size_t buflen) {
|
||||
if (buflen == 0)
|
||||
return 0;
|
||||
|
||||
if (SystemFunction036(buf, buflen) == FALSE)
|
||||
return UV_EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv_sleep(unsigned int msec) {
|
||||
Sleep(msec);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ sNtSetInformationFile pNtSetInformationFile;
|
||||
sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
|
||||
sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
sNtQueryInformationProcess pNtQueryInformationProcess;
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
@@ -44,12 +45,15 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
/* User32.dll function pointer */
|
||||
sSetWinEventHook pSetWinEventHook;
|
||||
|
||||
/* ws2_32.dll function pointer */
|
||||
uv_sGetHostNameW pGetHostNameW;
|
||||
|
||||
void uv_winapi_init(void) {
|
||||
void uv__winapi_init(void) {
|
||||
HMODULE ntdll_module;
|
||||
HMODULE powrprof_module;
|
||||
HMODULE user32_module;
|
||||
HMODULE kernel32_module;
|
||||
HMODULE ws2_32_module;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
@@ -106,6 +110,13 @@ void uv_winapi_init(void) {
|
||||
uv_fatal_error(GetLastError(), "GetProcAddress");
|
||||
}
|
||||
|
||||
pNtQueryInformationProcess = (sNtQueryInformationProcess) GetProcAddress(
|
||||
ntdll_module,
|
||||
"NtQueryInformationProcess");
|
||||
if (pNtQueryInformationProcess == NULL) {
|
||||
uv_fatal_error(GetLastError(), "GetProcAddress");
|
||||
}
|
||||
|
||||
kernel32_module = GetModuleHandleA("kernel32.dll");
|
||||
if (kernel32_module == NULL) {
|
||||
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
||||
@@ -115,16 +126,22 @@ void uv_winapi_init(void) {
|
||||
kernel32_module,
|
||||
"GetQueuedCompletionStatusEx");
|
||||
|
||||
powrprof_module = LoadLibraryA("powrprof.dll");
|
||||
powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (powrprof_module != NULL) {
|
||||
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
|
||||
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
|
||||
}
|
||||
|
||||
user32_module = LoadLibraryA("user32.dll");
|
||||
user32_module = GetModuleHandleA("user32.dll");
|
||||
if (user32_module != NULL) {
|
||||
pSetWinEventHook = (sSetWinEventHook)
|
||||
GetProcAddress(user32_module, "SetWinEventHook");
|
||||
}
|
||||
|
||||
ws2_32_module = GetModuleHandleA("ws2_32.dll");
|
||||
if (ws2_32_module != NULL) {
|
||||
pGetHostNameW = (uv_sGetHostNameW) GetProcAddress(
|
||||
ws2_32_module,
|
||||
"GetHostNameW");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4109,7 +4109,7 @@
|
||||
#endif
|
||||
|
||||
/* from winternl.h */
|
||||
#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32_)
|
||||
#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32__)
|
||||
#define __UNICODE_STRING_DEFINED
|
||||
#endif
|
||||
typedef struct _UNICODE_STRING {
|
||||
@@ -4152,6 +4152,10 @@ typedef const UNICODE_STRING *PCUNICODE_STRING;
|
||||
struct {
|
||||
UCHAR DataBuffer[1];
|
||||
} GenericReparseBuffer;
|
||||
struct {
|
||||
ULONG StringCount;
|
||||
WCHAR StringList[1];
|
||||
} AppExecLinkReparseBuffer;
|
||||
};
|
||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||
#endif
|
||||
@@ -4436,6 +4440,10 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
|
||||
# define SystemProcessorPerformanceInformation 8
|
||||
#endif
|
||||
|
||||
#ifndef ProcessConsoleHostProcess
|
||||
# define ProcessConsoleHostProcess 49
|
||||
#endif
|
||||
|
||||
#ifndef FILE_DEVICE_FILE_SYSTEM
|
||||
# define FILE_DEVICE_FILE_SYSTEM 0x00000009
|
||||
#endif
|
||||
@@ -4513,6 +4521,9 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
|
||||
#ifndef IO_REPARSE_TAG_SYMLINK
|
||||
# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_APPEXECLINK
|
||||
# define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL)
|
||||
#endif
|
||||
|
||||
typedef VOID (NTAPI *PIO_APC_ROUTINE)
|
||||
(PVOID ApcContext,
|
||||
@@ -4578,6 +4589,13 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
|
||||
BOOLEAN RestartScan
|
||||
);
|
||||
|
||||
typedef NTSTATUS (NTAPI *sNtQueryInformationProcess)
|
||||
(HANDLE ProcessHandle,
|
||||
UINT ProcessInformationClass,
|
||||
PVOID ProcessInformation,
|
||||
ULONG Length,
|
||||
PULONG ReturnLength);
|
||||
|
||||
/*
|
||||
* Kernel32 headers
|
||||
*/
|
||||
@@ -4708,6 +4726,18 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
|
||||
DWORD idThread,
|
||||
UINT dwflags);
|
||||
|
||||
/* From mstcpip.h */
|
||||
typedef struct _TCP_INITIAL_RTO_PARAMETERS {
|
||||
USHORT Rtt;
|
||||
UCHAR MaxSynRetransmissions;
|
||||
} TCP_INITIAL_RTO_PARAMETERS, *PTCP_INITIAL_RTO_PARAMETERS;
|
||||
|
||||
#ifndef TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS
|
||||
# define TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS ((UCHAR) -2)
|
||||
#endif
|
||||
#ifndef SIO_TCP_INITIAL_RTO
|
||||
# define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17)
|
||||
#endif
|
||||
|
||||
/* Ntdll function pointers */
|
||||
extern sRtlGetVersion pRtlGetVersion;
|
||||
@@ -4718,6 +4748,7 @@ extern sNtSetInformationFile pNtSetInformationFile;
|
||||
extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
|
||||
extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
extern sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
extern sNtQueryInformationProcess pNtQueryInformationProcess;
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
@@ -4728,4 +4759,11 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi
|
||||
/* User32.dll function pointer */
|
||||
extern sSetWinEventHook pSetWinEventHook;
|
||||
|
||||
/* ws2_32.dll function pointer */
|
||||
/* mingw doesn't have this definition, so let's declare it here locally */
|
||||
typedef int (WINAPI *uv_sGetHostNameW)
|
||||
(PWSTR,
|
||||
int);
|
||||
extern uv_sGetHostNameW pGetHostNameW;
|
||||
|
||||
#endif /* UV_WIN_WINAPI_H_ */
|
||||
|
||||
@@ -40,7 +40,7 @@ struct sockaddr_in6 uv_addr_ip6_any_;
|
||||
/*
|
||||
* Retrieves the pointer to a winsock extension function.
|
||||
*/
|
||||
static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
|
||||
static BOOL uv__get_extension_function(SOCKET socket, GUID guid,
|
||||
void **target) {
|
||||
int result;
|
||||
DWORD bytes;
|
||||
@@ -64,25 +64,20 @@ static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
|
||||
}
|
||||
|
||||
|
||||
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
|
||||
BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
|
||||
const GUID wsaid_acceptex = WSAID_ACCEPTEX;
|
||||
return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
|
||||
return uv__get_extension_function(socket, wsaid_acceptex, (void**)target);
|
||||
}
|
||||
|
||||
|
||||
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
|
||||
BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
|
||||
const GUID wsaid_connectex = WSAID_CONNECTEX;
|
||||
return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
|
||||
return uv__get_extension_function(socket, wsaid_connectex, (void**)target);
|
||||
}
|
||||
|
||||
|
||||
static int error_means_no_support(DWORD error) {
|
||||
return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT ||
|
||||
error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT;
|
||||
}
|
||||
|
||||
|
||||
void uv_winsock_init(void) {
|
||||
void uv__winsock_init(void) {
|
||||
WSADATA wsa_data;
|
||||
int errorno;
|
||||
SOCKET dummy;
|
||||
@@ -107,55 +102,41 @@ void uv_winsock_init(void) {
|
||||
uv_fatal_error(errorno, "WSAStartup");
|
||||
}
|
||||
|
||||
/* Detect non-IFS LSPs */
|
||||
/* Try to detect non-IFS LSPs */
|
||||
uv_tcp_non_ifs_lsp_ipv4 = 1;
|
||||
dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
|
||||
if (dummy != INVALID_SOCKET) {
|
||||
opt_len = (int) sizeof protocol_info;
|
||||
if (getsockopt(dummy,
|
||||
SOL_SOCKET,
|
||||
SO_PROTOCOL_INFOW,
|
||||
(char*) &protocol_info,
|
||||
&opt_len) == SOCKET_ERROR)
|
||||
uv_fatal_error(WSAGetLastError(), "getsockopt");
|
||||
|
||||
if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
|
||||
uv_tcp_non_ifs_lsp_ipv4 = 1;
|
||||
|
||||
if (closesocket(dummy) == SOCKET_ERROR)
|
||||
uv_fatal_error(WSAGetLastError(), "closesocket");
|
||||
|
||||
} else if (!error_means_no_support(WSAGetLastError())) {
|
||||
/* Any error other than "socket type not supported" is fatal. */
|
||||
uv_fatal_error(WSAGetLastError(), "socket");
|
||||
&opt_len) == 0) {
|
||||
if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
|
||||
uv_tcp_non_ifs_lsp_ipv4 = 0;
|
||||
}
|
||||
closesocket(dummy);
|
||||
}
|
||||
|
||||
/* Detect IPV6 support and non-IFS LSPs */
|
||||
/* Try to detect IPV6 support and non-IFS LSPs */
|
||||
uv_tcp_non_ifs_lsp_ipv6 = 1;
|
||||
dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
|
||||
|
||||
if (dummy != INVALID_SOCKET) {
|
||||
opt_len = (int) sizeof protocol_info;
|
||||
if (getsockopt(dummy,
|
||||
SOL_SOCKET,
|
||||
SO_PROTOCOL_INFOW,
|
||||
(char*) &protocol_info,
|
||||
&opt_len) == SOCKET_ERROR)
|
||||
uv_fatal_error(WSAGetLastError(), "getsockopt");
|
||||
|
||||
if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
|
||||
uv_tcp_non_ifs_lsp_ipv6 = 1;
|
||||
|
||||
if (closesocket(dummy) == SOCKET_ERROR)
|
||||
uv_fatal_error(WSAGetLastError(), "closesocket");
|
||||
|
||||
} else if (!error_means_no_support(WSAGetLastError())) {
|
||||
/* Any error other than "socket type not supported" is fatal. */
|
||||
uv_fatal_error(WSAGetLastError(), "socket");
|
||||
&opt_len) == 0) {
|
||||
if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
|
||||
uv_tcp_non_ifs_lsp_ipv6 = 0;
|
||||
}
|
||||
closesocket(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_ntstatus_to_winsock_error(NTSTATUS status) {
|
||||
int uv__ntstatus_to_winsock_error(NTSTATUS status) {
|
||||
switch (status) {
|
||||
case STATUS_SUCCESS:
|
||||
return ERROR_SUCCESS;
|
||||
@@ -288,7 +269,7 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) {
|
||||
* the user to use the default msafd driver, doesn't work when other LSPs are
|
||||
* stacked on top of it.
|
||||
*/
|
||||
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
|
||||
int WSAAPI uv__wsarecv_workaround(SOCKET socket, WSABUF* buffers,
|
||||
DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
|
||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
|
||||
NTSTATUS status;
|
||||
@@ -367,7 +348,7 @@ int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
|
||||
break;
|
||||
|
||||
default:
|
||||
error = uv_ntstatus_to_winsock_error(status);
|
||||
error = uv__ntstatus_to_winsock_error(status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -381,8 +362,8 @@ int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
|
||||
}
|
||||
|
||||
|
||||
/* See description of uv_wsarecv_workaround. */
|
||||
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
|
||||
/* See description of uv__wsarecv_workaround. */
|
||||
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) {
|
||||
@@ -465,7 +446,7 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
|
||||
break;
|
||||
|
||||
default:
|
||||
error = uv_ntstatus_to_winsock_error(status);
|
||||
error = uv__ntstatus_to_winsock_error(status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -479,7 +460,7 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
|
||||
}
|
||||
|
||||
|
||||
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
|
||||
int WSAAPI uv__msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
|
||||
AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
|
||||
IO_STATUS_BLOCK iosb;
|
||||
IO_STATUS_BLOCK* iosb_ptr;
|
||||
@@ -552,7 +533,7 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
|
||||
break;
|
||||
|
||||
default:
|
||||
error = uv_ntstatus_to_winsock_error(status);
|
||||
error = uv__ntstatus_to_winsock_error(status);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,14 @@
|
||||
# define SIO_BASE_HANDLE 0x48000022
|
||||
#endif
|
||||
|
||||
#ifndef MCAST_JOIN_SOURCE_GROUP
|
||||
# define MCAST_JOIN_SOURCE_GROUP 45
|
||||
#endif
|
||||
|
||||
#ifndef MCAST_LEAVE_SOURCE_GROUP
|
||||
# define MCAST_LEAVE_SOURCE_GROUP 46
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TDI defines that are only in the DDK.
|
||||
* We only need receive flags so far.
|
||||
|
||||
Reference in New Issue
Block a user