mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[upstream_utils] Upgrade to libuv 1.49.2 (#7226)
This commit is contained in:
@@ -56,7 +56,7 @@ def copy_upstream_src(wpilib_root):
|
||||
def main():
|
||||
name = "libuv"
|
||||
url = "https://github.com/libuv/libuv"
|
||||
tag = "v1.48.0"
|
||||
tag = "v1.49.2"
|
||||
|
||||
libuv = Lib(name, url, tag, copy_upstream_src)
|
||||
libuv.main()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tyler Veness <calcmogul@gmail.com>
|
||||
Date: Fri, 14 Jul 2023 17:33:08 -0700
|
||||
Subject: [PATCH 01/10] Revert "win,process: write minidumps when sending
|
||||
SIGQUIT (#3840)"
|
||||
Subject: [PATCH 1/9] Revert "win,process: write minidumps when sending SIGQUIT
|
||||
(#3840)"
|
||||
|
||||
This reverts commit 748d894e82abcdfff7429cf745003e182c47f163.
|
||||
---
|
||||
@@ -13,10 +13,10 @@ This reverts commit 748d894e82abcdfff7429cf745003e182c47f163.
|
||||
4 files changed, 2 insertions(+), 131 deletions(-)
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 5e8e0166d743bc23f446b180fdbe6843492c754b..4b6ff2477e494dde7a876d8b5bd3e8985c93f0e8 100644
|
||||
index 28c6df2566696785383716bf463c37cf2d07f987..36fef0fdff5090bb3a56d7e231c3bfe390772318 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -188,10 +188,7 @@ if(WIN32)
|
||||
@@ -193,10 +193,7 @@ if(WIN32)
|
||||
advapi32
|
||||
iphlpapi
|
||||
userenv
|
||||
@@ -29,7 +29,7 @@ index 5e8e0166d743bc23f446b180fdbe6843492c754b..4b6ff2477e494dde7a876d8b5bd3e898
|
||||
src/win/async.c
|
||||
src/win/core.c
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index d4cc003e34388de77fe1cfe2ebf12ab25b00b9b8..b215638506223e1c9edb1847bbcfccb7404be33f 100644
|
||||
index 98c59363026f8657dccc3aa2ed80d8bee159ebec..c4ee0756551876eac394282f2020cf44be17d023 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -74,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false])
|
||||
@@ -42,7 +42,7 @@ index d4cc003e34388de77fe1cfe2ebf12ab25b00b9b8..b215638506223e1c9edb1847bbcfccb7
|
||||
AS_CASE([$host_os], [solaris2.10], [
|
||||
CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS"
|
||||
diff --git a/include/uv/win.h b/include/uv/win.h
|
||||
index f4adaa216c6f0c17437ed42ca594acbf1b8c2c56..518b17606c3b0c114845594e6be9c3c4d95f1776 100644
|
||||
index 12ac53b4f217d212d1b5c32cfe090800f8770a09..d4c271d4d856a5ec847439825cace5bafb0d4acd 100644
|
||||
--- a/include/uv/win.h
|
||||
+++ b/include/uv/win.h
|
||||
@@ -91,7 +91,6 @@ typedef struct pollfd {
|
||||
@@ -54,10 +54,10 @@ index f4adaa216c6f0c17437ed42ca594acbf1b8c2c56..518b17606c3b0c114845594e6be9c3c4
|
||||
#define SIGWINCH 28
|
||||
|
||||
diff --git a/src/win/process.c b/src/win/process.c
|
||||
index 4e94dee90e13eede63d8e97ddc9992726f874ea9..4f0af83e83442bb905762361775abe05ab6beb4e 100644
|
||||
index 9d48ddc6f84d6f8c425a8f6f8a344f39d3deb5cc..79bec0090cc94bfe20dab722cf2d8135ddd03cb8 100644
|
||||
--- a/src/win/process.c
|
||||
+++ b/src/win/process.c
|
||||
@@ -32,9 +32,6 @@
|
||||
@@ -31,9 +31,6 @@
|
||||
#include "internal.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
@@ -67,7 +67,7 @@ index 4e94dee90e13eede63d8e97ddc9992726f874ea9..4f0af83e83442bb905762361775abe05
|
||||
|
||||
|
||||
#define SIGKILL 9
|
||||
@@ -1179,129 +1176,7 @@ static int uv__kill(HANDLE process_handle, int signum) {
|
||||
@@ -1160,129 +1157,7 @@ static int uv__kill(HANDLE process_handle, int signum) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
From 0000000000000000000000000000000000000000 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 03/10] Fix warnings
|
||||
Subject: [PATCH 3/9] Fix warnings
|
||||
|
||||
---
|
||||
include/uv/win.h | 5 +++++
|
||||
@@ -10,6 +10,7 @@ Subject: [PATCH 03/10] Fix warnings
|
||||
src/threadpool.c | 4 ++++
|
||||
src/unix/core.c | 12 ++++++++++--
|
||||
src/unix/internal.h | 4 ++--
|
||||
src/unix/linux.c | 2 +-
|
||||
src/unix/thread.c | 6 ------
|
||||
src/uv-common.c | 8 ++++++++
|
||||
src/win/fs-event.c | 2 ++
|
||||
@@ -18,10 +19,10 @@ Subject: [PATCH 03/10] Fix warnings
|
||||
src/win/process.c | 2 ++
|
||||
src/win/thread.c | 4 ++--
|
||||
src/win/tty.c | 2 ++
|
||||
14 files changed, 47 insertions(+), 14 deletions(-)
|
||||
15 files changed, 48 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/include/uv/win.h b/include/uv/win.h
|
||||
index 518b17606c3b0c114845594e6be9c3c4d95f1776..9a8c990c1b182633f23890cb5f4532b6bee2b22c 100644
|
||||
index d4c271d4d856a5ec847439825cace5bafb0d4acd..48e1402d155ceb80e35a904815cb5739cab2fbe8 100644
|
||||
--- a/include/uv/win.h
|
||||
+++ b/include/uv/win.h
|
||||
@@ -201,11 +201,16 @@ typedef int (WSAAPI* LPFN_WSARECVFROM)
|
||||
@@ -79,7 +80,7 @@ index dd94bea3886ca37945fcad7909d765e3700e3c21..71c9e5b774d64d505e6c6d6ed2637178
|
||||
#define UV__INET6_ADDRSTRLEN 46
|
||||
|
||||
diff --git a/src/threadpool.c b/src/threadpool.c
|
||||
index f572de5aaf1a1b150e58c7b989949441cac279c4..aa282af468935b680140295a175e503ca82d8fa4 100644
|
||||
index ccb5249893df2733fc607fec6e8d3037ebe2e212..a08832cd4c292f9e7c83b2e8b6c326f542e49cd8 100644
|
||||
--- a/src/threadpool.c
|
||||
+++ b/src/threadpool.c
|
||||
@@ -27,6 +27,10 @@
|
||||
@@ -94,10 +95,10 @@ index f572de5aaf1a1b150e58c7b989949441cac279c4..aa282af468935b680140295a175e503c
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
diff --git a/src/unix/core.c b/src/unix/core.c
|
||||
index 8c08d607884335a2da5cb49f35e3108cb833da32..4bc870214afa1e08da2f7b335c031d67d221fdd6 100644
|
||||
index b72a24e94b0c70455a8ac748a53556ddefb09f49..18f0ce06336e4b3690f84d95b4be954a4466cdf6 100644
|
||||
--- a/src/unix/core.c
|
||||
+++ b/src/unix/core.c
|
||||
@@ -576,6 +576,16 @@ int uv__accept(int sockfd) {
|
||||
@@ -586,6 +586,16 @@ int uv__accept(int sockfd) {
|
||||
return peerfd;
|
||||
}
|
||||
|
||||
@@ -114,7 +115,7 @@ index 8c08d607884335a2da5cb49f35e3108cb833da32..4bc870214afa1e08da2f7b335c031d67
|
||||
|
||||
/* 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.
|
||||
@@ -590,10 +600,8 @@ int uv__close_nocancel(int fd) {
|
||||
@@ -600,10 +610,8 @@ int uv__close_nocancel(int fd) {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
|
||||
#if defined(__LP64__) || TARGET_OS_IPHONE
|
||||
@@ -126,10 +127,10 @@ index 8c08d607884335a2da5cb49f35e3108cb833da32..4bc870214afa1e08da2f7b335c031d67
|
||||
#endif
|
||||
#pragma GCC diagnostic pop
|
||||
diff --git a/src/unix/internal.h b/src/unix/internal.h
|
||||
index bcb3be577e584925d4bf4a20d2429ce13aad0584..4c167f5e529cb38a7418fc35dbbafc2a2cea626c 100644
|
||||
index 8d586b0b64a96ca53a18f22d957a81c5600098c1..1daf4d81da3a5bf931c4a5db8fd9116c4c303012 100644
|
||||
--- a/src/unix/internal.h
|
||||
+++ b/src/unix/internal.h
|
||||
@@ -384,8 +384,8 @@ UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
|
||||
@@ -394,8 +394,8 @@ UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
|
||||
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
|
||||
}
|
||||
|
||||
@@ -140,6 +141,19 @@ index bcb3be577e584925d4bf4a20d2429ce13aad0584..4c167f5e529cb38a7418fc35dbbafc2a
|
||||
|
||||
s = strrchr(path, '/');
|
||||
if (s == NULL)
|
||||
diff --git a/src/unix/linux.c b/src/unix/linux.c
|
||||
index 22f76054ef0987f215afb9d1e20aa18f97489ea4..b8063cc8900d4cf255a46a9620d01815c65c6d21 100644
|
||||
--- a/src/unix/linux.c
|
||||
+++ b/src/unix/linux.c
|
||||
@@ -2309,7 +2309,7 @@ static int uv__get_cgroupv2_constrained_cpu(const char* cgroup,
|
||||
if (uv__slurp(path, buf, sizeof(buf)) < 0)
|
||||
return UV_EIO;
|
||||
|
||||
- if (sscanf(buf, "%15s %llu", quota_buf, &constraint->period_length) != 2)
|
||||
+ if (sscanf(buf, "%15s %lld", quota_buf, &constraint->period_length) != 2)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (strncmp(quota_buf, "max", 3) == 0)
|
||||
diff --git a/src/unix/thread.c b/src/unix/thread.c
|
||||
index 20409541de3cb300504b823472a73bc95fa38f62..688c042e1aedf379264900c29758c8b01a4a90ed 100644
|
||||
--- a/src/unix/thread.c
|
||||
@@ -184,7 +198,7 @@ index 69e95801a18104ea910abf86db236d85f62afb66..49126e50f07bac16d198775454b731f4
|
||||
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 dba981c68821ece88e0beb80422b214b77e84b79..2f566f796a55c68329d5aed19bd5bb392d0082fa 100644
|
||||
index 3754437b4989d67f688153e066ef047268911708..2fdcbcb73a9ee29dd282b366011a6878fc431a47 100644
|
||||
--- a/src/win/fs-event.c
|
||||
+++ b/src/win/fs-event.c
|
||||
@@ -19,6 +19,8 @@
|
||||
@@ -197,7 +211,7 @@ index dba981c68821ece88e0beb80422b214b77e84b79..2f566f796a55c68329d5aed19bd5bb39
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
diff --git a/src/win/fs.c b/src/win/fs.c
|
||||
index 7e2367e8c1c6ad96af55a2cc370142104cc0de77..b812293048e60264f3e849367b7a129c306f8502 100644
|
||||
index cc095491d7ff14a7f7a850005f02a45860636446..f1966ab5c0245af0f56ca407a1697a5c8609ebb4 100644
|
||||
--- a/src/win/fs.c
|
||||
+++ b/src/win/fs.c
|
||||
@@ -19,6 +19,8 @@
|
||||
@@ -210,7 +224,7 @@ index 7e2367e8c1c6ad96af55a2cc370142104cc0de77..b812293048e60264f3e849367b7a129c
|
||||
#include <stdlib.h>
|
||||
#include <direct.h>
|
||||
diff --git a/src/win/pipe.c b/src/win/pipe.c
|
||||
index 27868221455dcbb90c00066fd8b716d2c0a4d371..d747dc72362a0b21077fa7b9beb57234ca62baad 100644
|
||||
index 9b2723320b72691d5ada0f8e97f0589ce53e82f8..9993f281409345d8163a9c69c103b94e7cb258d3 100644
|
||||
--- a/src/win/pipe.c
|
||||
+++ b/src/win/pipe.c
|
||||
@@ -19,6 +19,8 @@
|
||||
@@ -223,7 +237,7 @@ index 27868221455dcbb90c00066fd8b716d2c0a4d371..d747dc72362a0b21077fa7b9beb57234
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
diff --git a/src/win/process.c b/src/win/process.c
|
||||
index 25f1075745267785cdd7d7de83d9c62750305852..e4bf93d707da3d22b747300775e8c96a34039ddb 100644
|
||||
index 5a648494ae03688f6a56705f2c3d65b026605818..d6b61c14015b8d72d8a9aca71bd0483c06a16820 100644
|
||||
--- a/src/win/process.c
|
||||
+++ b/src/win/process.c
|
||||
@@ -19,6 +19,8 @@
|
||||
@@ -236,10 +250,10 @@ index 25f1075745267785cdd7d7de83d9c62750305852..e4bf93d707da3d22b747300775e8c96a
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
diff --git a/src/win/thread.c b/src/win/thread.c
|
||||
index 57f1698f595e2410a51044f7f228b5a235206819..03b33e9b4de6fe2532095d717a8639e8df454cce 100644
|
||||
index dd958ccd782772869d5448d788a563c1526a89f6..6a4d4498577b0abaa8408052051b0472dde5afec 100644
|
||||
--- a/src/win/thread.c
|
||||
+++ b/src/win/thread.c
|
||||
@@ -204,8 +204,8 @@ int uv_thread_setaffinity(uv_thread_t* tid,
|
||||
@@ -182,8 +182,8 @@ int uv_thread_setaffinity(uv_thread_t* tid,
|
||||
threadmask = 0;
|
||||
for (i = 0; i < cpumasksize; i++) {
|
||||
if (cpumask[i]) {
|
||||
@@ -251,7 +265,7 @@ index 57f1698f595e2410a51044f7f228b5a235206819..03b33e9b4de6fe2532095d717a8639e8
|
||||
return UV_EINVAL;
|
||||
}
|
||||
diff --git a/src/win/tty.c b/src/win/tty.c
|
||||
index 0b51b6c82fad711480c28ad6cee7125ddb72ca87..67df01396ab50260b986fc9e7aff0368f6ceb308 100644
|
||||
index 145706e27a7b596dc003d43d94b54f6ceb0eabee..62ddf32f0fbd29664dd05c6ba426532a2faf4668 100644
|
||||
--- a/src/win/tty.c
|
||||
+++ b/src/win/tty.c
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
From 0000000000000000000000000000000000000000 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 04/10] Preprocessor cleanup
|
||||
Subject: [PATCH 4/9] Preprocessor cleanup
|
||||
|
||||
---
|
||||
include/uv.h | 12 ------------
|
||||
include/uv/unix.h | 8 --------
|
||||
src/unix/internal.h | 2 ++
|
||||
src/win/fs.c | 1 +
|
||||
src/win/tty.c | 2 ++
|
||||
src/win/util.c | 8 ++++++++
|
||||
src/win/winsock.c | 1 +
|
||||
7 files changed, 14 insertions(+), 20 deletions(-)
|
||||
include/uv.h | 12 ------------
|
||||
include/uv/unix.h | 8 --------
|
||||
src/unix/darwin-syscalls.h | 2 ++
|
||||
src/unix/internal.h | 2 ++
|
||||
src/win/fs.c | 1 +
|
||||
src/win/tty.c | 2 ++
|
||||
src/win/util.c | 8 ++++++++
|
||||
src/win/winsock.c | 1 +
|
||||
8 files changed, 16 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/include/uv.h b/include/uv.h
|
||||
index a62b3fa69b1087847f37c7093954e19a07959b74..931c96262b33090422cc1f6c519f8eb4bfc4f9b3 100644
|
||||
index 9e450c5110fe57117b686bf683cc6631f37efaeb..d8d59a03512eff879d9688c09fb4a9a57a82ffb7 100644
|
||||
--- a/include/uv.h
|
||||
+++ b/include/uv.h
|
||||
@@ -23,9 +23,6 @@
|
||||
@@ -27,7 +28,7 @@ index a62b3fa69b1087847f37c7093954e19a07959b74..931c96262b33090422cc1f6c519f8eb4
|
||||
|
||||
#if defined(BUILDING_UV_SHARED) && defined(USING_UV_SHARED)
|
||||
#error "Define either BUILDING_UV_SHARED or USING_UV_SHARED, not both."
|
||||
@@ -796,16 +793,10 @@ UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
|
||||
@@ -824,16 +821,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);
|
||||
|
||||
@@ -44,7 +45,7 @@ index a62b3fa69b1087847f37c7093954e19a07959b74..931c96262b33090422cc1f6c519f8eb4
|
||||
UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
|
||||
|
||||
enum {
|
||||
@@ -1936,7 +1927,4 @@ void uv_wtf8_to_utf16(const char* wtf8,
|
||||
@@ -1964,7 +1955,4 @@ UV_EXTERN void uv_wtf8_to_utf16(const char* wtf8,
|
||||
#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS
|
||||
#undef UV__ERR
|
||||
|
||||
@@ -71,11 +72,25 @@ index 538f98b6c5d657169e2750a549dd82bf0b948542..2073fe61a569386cc850d733a6c94cbb
|
||||
#elif defined(__APPLE__)
|
||||
# include "uv/darwin.h"
|
||||
#elif defined(__DragonFly__) || \
|
||||
diff --git a/src/unix/darwin-syscalls.h b/src/unix/darwin-syscalls.h
|
||||
index dc2d1bd234b1f12e39b7e76d6e290c15b19a3735..851af81c74e5b5d62f5f7e72da84703c15eace90 100644
|
||||
--- a/src/unix/darwin-syscalls.h
|
||||
+++ b/src/unix/darwin-syscalls.h
|
||||
@@ -11,7 +11,9 @@ struct mmsghdr {
|
||||
size_t msg_len;
|
||||
};
|
||||
|
||||
+extern "C" {
|
||||
ssize_t recvmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags);
|
||||
ssize_t sendmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags);
|
||||
+}
|
||||
|
||||
#endif /* UV_DARWIN_SYSCALLS_H_ */
|
||||
diff --git a/src/unix/internal.h b/src/unix/internal.h
|
||||
index 4c167f5e529cb38a7418fc35dbbafc2a2cea626c..35ac6d1f6da75522d4bd69dcde696a8d0fd42bce 100644
|
||||
index 1daf4d81da3a5bf931c4a5db8fd9116c4c303012..9377e970c4a7adafb8195974f6dc5ba40437ef1a 100644
|
||||
--- a/src/unix/internal.h
|
||||
+++ b/src/unix/internal.h
|
||||
@@ -233,6 +233,8 @@ struct uv__statx {
|
||||
@@ -237,6 +237,8 @@ struct uv__statx {
|
||||
#if defined(__linux__) && O_NDELAY != O_NONBLOCK
|
||||
#undef uv__nonblock
|
||||
#define uv__nonblock uv__nonblock_fcntl
|
||||
@@ -85,7 +100,7 @@ index 4c167f5e529cb38a7418fc35dbbafc2a2cea626c..35ac6d1f6da75522d4bd69dcde696a8d
|
||||
|
||||
/* core */
|
||||
diff --git a/src/win/fs.c b/src/win/fs.c
|
||||
index b812293048e60264f3e849367b7a129c306f8502..05488e5d67101adba611f882ded4f6dc5a462d9a 100644
|
||||
index f1966ab5c0245af0f56ca407a1697a5c8609ebb4..572a82dca3cbcdb7829241dd520e8f34591d81e9 100644
|
||||
--- a/src/win/fs.c
|
||||
+++ b/src/win/fs.c
|
||||
@@ -43,6 +43,7 @@
|
||||
@@ -97,7 +112,7 @@ index b812293048e60264f3e849367b7a129c306f8502..05488e5d67101adba611f882ded4f6dc
|
||||
#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 67df01396ab50260b986fc9e7aff0368f6ceb308..7294f311e17d5d02e5873e60f8f0cdd551f6d34d 100644
|
||||
index 62ddf32f0fbd29664dd05c6ba426532a2faf4668..9a4252d9d89d82fdd316312cc4550dd3c0fe798d 100644
|
||||
--- a/src/win/tty.c
|
||||
+++ b/src/win/tty.c
|
||||
@@ -37,6 +37,8 @@
|
||||
@@ -110,7 +125,7 @@ index 67df01396ab50260b986fc9e7aff0368f6ceb308..7294f311e17d5d02e5873e60f8f0cdd5
|
||||
# define InterlockedOr _InterlockedOr
|
||||
#endif
|
||||
diff --git a/src/win/util.c b/src/win/util.c
|
||||
index 924d878e89260c2d3cf9a30b7151abeaf735b8be..5767c66c988c67edaf17155d5cb299a1936870ee 100644
|
||||
index 1aca4e9a081cd7e4481503d59f39872acbbc6a9c..1239831dcc0c5fdb8e267d4dd8e73cb73fdc88c9 100644
|
||||
--- a/src/win/util.c
|
||||
+++ b/src/win/util.c
|
||||
@@ -64,12 +64,20 @@
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
From 0000000000000000000000000000000000000000 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 05/10] Cleanup problematic language
|
||||
Subject: [PATCH 5/9] Cleanup problematic language
|
||||
|
||||
---
|
||||
src/unix/tty.c | 21 +++++++++++----------
|
||||
1 file changed, 11 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/unix/tty.c b/src/unix/tty.c
|
||||
index d099bdb3b677212d21e06ac7bb1031c8e5386499..1bd217b5a15eed13a8349c479b53471dd36ca216 100644
|
||||
index 793054ba5a9bffe4e2db9040ca09a7fff0ec6b23..699a092da2dea77277557211065f6594bcad4e0b 100644
|
||||
--- a/src/unix/tty.c
|
||||
+++ b/src/unix/tty.c
|
||||
@@ -79,7 +79,7 @@ int uv__tcsetattr(int fd, int how, const struct termios *term) {
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tyler Veness <calcmogul@gmail.com>
|
||||
Date: Sat, 21 May 2022 22:58:06 -0700
|
||||
Subject: [PATCH 06/10] Fix Win32 warning suppression pragma
|
||||
|
||||
---
|
||||
src/win/util.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/win/util.c b/src/win/util.c
|
||||
index 5767c66c988c67edaf17155d5cb299a1936870ee..52c31979589e4ed7fe12af200f7e8daab9e02797 100644
|
||||
--- a/src/win/util.c
|
||||
+++ b/src/win/util.c
|
||||
@@ -1544,7 +1544,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
|
||||
} else {
|
||||
/* Silence GetVersionEx() deprecation warning. */
|
||||
#ifdef _MSC_VER
|
||||
- #pragma warning(suppress : 4996)
|
||||
+ #pragma warning(disable : 4996)
|
||||
#endif
|
||||
if (GetVersionExW(&os_info) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
@@ -1,18 +1,18 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tyler Veness <calcmogul@gmail.com>
|
||||
Date: Thu, 13 Jul 2023 22:13:47 -0700
|
||||
Subject: [PATCH 07/10] Use C++ atomics
|
||||
Subject: [PATCH 6/9] Use C++ atomics
|
||||
|
||||
---
|
||||
src/unix/async.c | 25 +++++++++++++------------
|
||||
src/unix/core.c | 3 ++-
|
||||
src/unix/fs.c | 20 +++++++++++---------
|
||||
src/unix/fs.c | 33 +++++++++++++++++----------------
|
||||
src/unix/kqueue.c | 10 ++++++----
|
||||
src/unix/linux.c | 45 +++++++++++++++++++++++----------------------
|
||||
src/unix/tty.c | 5 +++--
|
||||
src/uv-common.c | 2 +-
|
||||
src/uv-common.h | 8 +++-----
|
||||
8 files changed, 62 insertions(+), 56 deletions(-)
|
||||
8 files changed, 68 insertions(+), 63 deletions(-)
|
||||
|
||||
diff --git a/src/unix/async.c b/src/unix/async.c
|
||||
index 0ff2669e30a628dbb2df9e28ba14b38cf14114e5..fef4ae93343edc0341179a1c4739dcd831ef6e26 100644
|
||||
@@ -91,7 +91,7 @@ index 0ff2669e30a628dbb2df9e28ba14b38cf14114e5..fef4ae93343edc0341179a1c4739dcd8
|
||||
continue;
|
||||
|
||||
diff --git a/src/unix/core.c b/src/unix/core.c
|
||||
index 4bc870214afa1e08da2f7b335c031d67d221fdd6..f13ffd1714af26dede3d4d5f6f01efa39fc78959 100644
|
||||
index 18f0ce06336e4b3690f84d95b4be954a4466cdf6..c1cc4691439580160cfdda35a01b8e940e4d270b 100644
|
||||
--- a/src/unix/core.c
|
||||
+++ b/src/unix/core.c
|
||||
@@ -45,6 +45,7 @@
|
||||
@@ -102,7 +102,7 @@ index 4bc870214afa1e08da2f7b335c031d67d221fdd6..f13ffd1714af26dede3d4d5f6f01efa3
|
||||
|
||||
#ifdef __sun
|
||||
# include <sys/filio.h>
|
||||
@@ -264,7 +265,7 @@ int uv__getiovmax(void) {
|
||||
@@ -274,7 +275,7 @@ int uv__getiovmax(void) {
|
||||
#if defined(IOV_MAX)
|
||||
return IOV_MAX;
|
||||
#elif defined(_SC_IOV_MAX)
|
||||
@@ -112,10 +112,18 @@ index 4bc870214afa1e08da2f7b335c031d67d221fdd6..f13ffd1714af26dede3d4d5f6f01efa3
|
||||
|
||||
iovmax = atomic_load_explicit(&iovmax_cached, memory_order_relaxed);
|
||||
diff --git a/src/unix/fs.c b/src/unix/fs.c
|
||||
index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e9299404f91f 100644
|
||||
index efd37d78d9216de6ad46633a953f6b292b4af735..6a2e64cb33f004350bee89f28345667d095e1bb5 100644
|
||||
--- a/src/unix/fs.c
|
||||
+++ b/src/unix/fs.c
|
||||
@@ -45,6 +45,8 @@
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
-#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -46,6 +45,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
@@ -124,7 +132,7 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
|
||||
#if defined(__linux__)
|
||||
# include <sys/sendfile.h>
|
||||
#endif
|
||||
@@ -309,7 +311,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
@@ -299,7 +300,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
int r;
|
||||
#ifdef O_CLOEXEC
|
||||
@@ -133,7 +141,7 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
|
||||
#endif
|
||||
static const char pattern[] = "XXXXXX";
|
||||
static const size_t pattern_size = sizeof(pattern) - 1;
|
||||
@@ -334,7 +336,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
@@ -324,7 +325,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
uv_once(&once, uv__mkostemp_initonce);
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
@@ -142,7 +150,7 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
|
||||
uv__mkostemp != NULL) {
|
||||
r = uv__mkostemp(path, O_CLOEXEC);
|
||||
|
||||
@@ -348,7 +350,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
@@ -338,7 +339,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
|
||||
/* We set the static variable so that next calls don't even
|
||||
try to use mkostemp. */
|
||||
@@ -151,7 +159,58 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
|
||||
}
|
||||
#endif /* O_CLOEXEC */
|
||||
|
||||
@@ -869,10 +871,10 @@ static int uv__is_cifs_or_smb(int fd) {
|
||||
@@ -459,7 +460,7 @@ static ssize_t uv__pwritev_emul(int fd,
|
||||
}
|
||||
|
||||
|
||||
-/* The function pointer cache is an uintptr_t because _Atomic void*
|
||||
+/* The function pointer cache is an uintptr_t because std::atomic<void>*
|
||||
* doesn't work on macos/ios/etc...
|
||||
* Disable optimization on armv7 to work around the bug described in
|
||||
* https://github.com/libuv/libuv/issues/4532
|
||||
@@ -471,12 +472,12 @@ static ssize_t uv__preadv_or_pwritev(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off,
|
||||
- _Atomic uintptr_t* cache,
|
||||
+ std::atomic<uintptr_t>* cache,
|
||||
int is_pread) {
|
||||
ssize_t (*f)(int, const struct iovec*, uv__iovcnt, off_t);
|
||||
void* p;
|
||||
|
||||
- p = (void*) atomic_load_explicit(cache, memory_order_relaxed);
|
||||
+ p = (void*) atomic_load_explicit(cache, std::memory_order_relaxed);
|
||||
if (p == NULL) {
|
||||
#ifdef RTLD_DEFAULT
|
||||
p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev");
|
||||
@@ -484,7 +485,7 @@ static ssize_t uv__preadv_or_pwritev(int fd,
|
||||
#endif /* RTLD_DEFAULT */
|
||||
if (p == NULL)
|
||||
p = (void*)(is_pread ? uv__preadv_emul : uv__pwritev_emul);
|
||||
- atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed);
|
||||
+ atomic_store_explicit(cache, (uintptr_t) p, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/* Use memcpy instead of `f = p` to work around a compiler bug,
|
||||
@@ -499,7 +500,7 @@ static ssize_t uv__preadv(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off) {
|
||||
- static _Atomic uintptr_t cache;
|
||||
+ static std::atomic<uintptr_t> cache;
|
||||
return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/1);
|
||||
}
|
||||
|
||||
@@ -508,7 +509,7 @@ static ssize_t uv__pwritev(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off) {
|
||||
- static _Atomic uintptr_t cache;
|
||||
+ static std::atomic<uintptr_t> cache;
|
||||
return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/0);
|
||||
}
|
||||
|
||||
@@ -985,10 +986,10 @@ static int uv__is_cifs_or_smb(int fd) {
|
||||
|
||||
static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
|
||||
int out_fd, size_t len) {
|
||||
@@ -164,7 +223,7 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
@@ -891,7 +893,7 @@ static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
|
||||
@@ -1007,7 +1008,7 @@ static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
|
||||
errno = ENOSYS; /* Use fallback. */
|
||||
break;
|
||||
case ENOSYS:
|
||||
@@ -173,7 +232,7 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
|
||||
break;
|
||||
case EPERM:
|
||||
/* It's been reported that CIFS spuriously fails.
|
||||
@@ -1382,14 +1384,14 @@ static int uv__fs_statx(int fd,
|
||||
@@ -1531,14 +1532,14 @@ static int uv__fs_statx(int fd,
|
||||
uv_stat_t* buf) {
|
||||
STATIC_ASSERT(UV_ENOSYS != -1);
|
||||
#ifdef __linux__
|
||||
@@ -190,7 +249,7 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
|
||||
return UV_ENOSYS;
|
||||
|
||||
dirfd = AT_FDCWD;
|
||||
@@ -1423,7 +1425,7 @@ static int uv__fs_statx(int fd,
|
||||
@@ -1572,7 +1573,7 @@ static int uv__fs_statx(int fd,
|
||||
* implemented, rc might return 1 with 0 set as the error code in which
|
||||
* case we return ENOSYS.
|
||||
*/
|
||||
@@ -200,7 +259,7 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
|
||||
}
|
||||
|
||||
diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c
|
||||
index c307e6631eefb1effb0e0c304eb400e0cb8d984e..bd09ac39dda916dd5a7d664979ce5735586fd7e3 100644
|
||||
index b7bd00ea0c45964d8e26d7596d9ad3734fe67237..8676a6340d7047585e230138ac130b591c164e4e 100644
|
||||
--- a/src/unix/kqueue.c
|
||||
+++ b/src/unix/kqueue.c
|
||||
@@ -37,6 +37,8 @@
|
||||
@@ -230,7 +289,7 @@ index c307e6631eefb1effb0e0c304eb400e0cb8d984e..bd09ac39dda916dd5a7d664979ce5735
|
||||
uv__free(loop->cf_state);
|
||||
loop->cf_state = NULL;
|
||||
}
|
||||
@@ -565,7 +567,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
@@ -598,7 +600,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
goto fallback;
|
||||
|
||||
if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
|
||||
@@ -239,7 +298,7 @@ index c307e6631eefb1effb0e0c304eb400e0cb8d984e..bd09ac39dda916dd5a7d664979ce5735
|
||||
int r;
|
||||
/* The fallback fd is no longer needed */
|
||||
uv__close_nocheckstdio(fd);
|
||||
@@ -601,7 +603,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
@@ -634,7 +636,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
|
||||
@@ -249,7 +308,7 @@ index c307e6631eefb1effb0e0c304eb400e0cb8d984e..bd09ac39dda916dd5a7d664979ce5735
|
||||
r = uv__fsevents_close(handle);
|
||||
#endif
|
||||
diff --git a/src/unix/linux.c b/src/unix/linux.c
|
||||
index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45025615f9 100644
|
||||
index b8063cc8900d4cf255a46a9620d01815c65c6d21..25b93ba43b98874d658d58e3faab12049f6e4edf 100644
|
||||
--- a/src/unix/linux.c
|
||||
+++ b/src/unix/linux.c
|
||||
@@ -27,7 +27,6 @@
|
||||
@@ -268,8 +327,8 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
+
|
||||
enum {
|
||||
UV__IORING_SETUP_SQPOLL = 2u,
|
||||
};
|
||||
@@ -302,7 +303,7 @@ static struct watcher_root* uv__inotify_watchers(uv_loop_t* loop) {
|
||||
UV__IORING_SETUP_NO_SQARRAY = 0x10000u,
|
||||
@@ -300,7 +301,7 @@ static struct watcher_root* uv__inotify_watchers(uv_loop_t* loop) {
|
||||
|
||||
|
||||
unsigned uv__kernel_version(void) {
|
||||
@@ -278,7 +337,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
struct utsname u;
|
||||
unsigned version;
|
||||
unsigned major;
|
||||
@@ -311,7 +312,7 @@ unsigned uv__kernel_version(void) {
|
||||
@@ -309,7 +310,7 @@ unsigned uv__kernel_version(void) {
|
||||
char v_sig[256];
|
||||
char* needle;
|
||||
|
||||
@@ -287,7 +346,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
if (version != 0)
|
||||
return version;
|
||||
|
||||
@@ -367,7 +368,7 @@ unsigned uv__kernel_version(void) {
|
||||
@@ -365,7 +366,7 @@ unsigned uv__kernel_version(void) {
|
||||
|
||||
calculate_version:
|
||||
version = major * 65536 + minor * 256 + patch;
|
||||
@@ -296,7 +355,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
|
||||
return version;
|
||||
}
|
||||
@@ -468,11 +469,11 @@ static int uv__use_io_uring(void) {
|
||||
@@ -466,11 +467,11 @@ static int uv__use_io_uring(void) {
|
||||
return 0; /* Random SIGSEGV in signal handler. */
|
||||
#else
|
||||
/* Ternary: unknown=0, yes=1, no=-1 */
|
||||
@@ -310,7 +369,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
|
||||
if (use == 0) {
|
||||
use = uv__kernel_version() >=
|
||||
@@ -491,7 +492,7 @@ static int uv__use_io_uring(void) {
|
||||
@@ -489,7 +490,7 @@ static int uv__use_io_uring(void) {
|
||||
if (val != NULL)
|
||||
use = atoi(val) ? 1 : -1;
|
||||
|
||||
@@ -319,7 +378,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
}
|
||||
|
||||
return use > 0;
|
||||
@@ -767,8 +768,8 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
|
||||
@@ -781,8 +782,8 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
|
||||
if (iou->ringfd == -1)
|
||||
return NULL;
|
||||
|
||||
@@ -330,7 +389,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
tail = *iou->sqtail;
|
||||
mask = iou->sqmask;
|
||||
|
||||
@@ -797,12 +798,12 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
|
||||
@@ -811,12 +812,12 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
|
||||
static void uv__iou_submit(struct uv__iou* iou) {
|
||||
uint32_t flags;
|
||||
|
||||
@@ -347,7 +406,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
|
||||
if (flags & UV__IORING_SQ_NEED_WAKEUP)
|
||||
if (uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_SQ_WAKEUP))
|
||||
@@ -1143,8 +1144,8 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
|
||||
@@ -1174,8 +1175,8 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
|
||||
int rc;
|
||||
|
||||
head = *iou->cqhead;
|
||||
@@ -358,7 +417,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
mask = iou->cqmask;
|
||||
cqe = (uv__io_uring_cqe*)iou->cqe;
|
||||
nevents = 0;
|
||||
@@ -1182,15 +1183,15 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
|
||||
@@ -1213,15 +1214,15 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
|
||||
nevents++;
|
||||
}
|
||||
|
||||
@@ -378,7 +437,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
|
||||
if (flags & UV__IORING_SQ_CQ_OVERFLOW) {
|
||||
do
|
||||
@@ -1583,7 +1584,7 @@ update_timeout:
|
||||
@@ -1619,7 +1620,7 @@ update_timeout:
|
||||
}
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
@@ -387,7 +446,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
struct timespec t;
|
||||
clock_t clock_id;
|
||||
|
||||
@@ -1599,7 +1600,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
@@ -1635,7 +1636,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
if (type != UV_CLOCK_FAST)
|
||||
goto done;
|
||||
|
||||
@@ -396,7 +455,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
if (clock_id != -1)
|
||||
goto done;
|
||||
|
||||
@@ -1608,7 +1609,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
@@ -1644,7 +1645,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
if (t.tv_nsec <= 1 * 1000 * 1000)
|
||||
clock_id = CLOCK_MONOTONIC_COARSE;
|
||||
|
||||
@@ -406,7 +465,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
|
||||
done:
|
||||
|
||||
diff --git a/src/unix/tty.c b/src/unix/tty.c
|
||||
index 1bd217b5a15eed13a8349c479b53471dd36ca216..1304c6d8685cfd122cffea066dc668d1dfc9ae02 100644
|
||||
index 699a092da2dea77277557211065f6594bcad4e0b..5ca2105848fc07d312455c336ac7303e61679213 100644
|
||||
--- a/src/unix/tty.c
|
||||
+++ b/src/unix/tty.c
|
||||
@@ -22,7 +22,6 @@
|
||||
@@ -449,7 +508,7 @@ index 49126e50f07bac16d198775454b731f40630d1d1..1ce25c24d6c046f7aaeaa52dcfc4fafa
|
||||
if (uv__exchange_int_relaxed(&was_shutdown, 1))
|
||||
return;
|
||||
diff --git a/src/uv-common.h b/src/uv-common.h
|
||||
index cd57e5a35153d0557351b60cce0c5be7a4468b60..5dce8eaf2705b47935b218181f6dd69af0d5b61b 100644
|
||||
index 4baede2e506ee1787d554a0ec75bc9eb346fc8f2..4978cf0633c2de5fa96bf600a59dfb539cab8201 100644
|
||||
--- a/src/uv-common.h
|
||||
+++ b/src/uv-common.h
|
||||
@@ -32,15 +32,13 @@
|
||||
@@ -1,17 +1,17 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tyler Veness <calcmogul@gmail.com>
|
||||
Date: Thu, 13 Jul 2023 23:30:58 -0700
|
||||
Subject: [PATCH 08/10] Remove static from array indices
|
||||
Subject: [PATCH 7/9] Remove static from array indices
|
||||
|
||||
---
|
||||
src/unix/linux.c | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/unix/linux.c b/src/unix/linux.c
|
||||
index e0c4902385edac10ac31bc5075a85a45025615f9..091c0474cfe37de4eb55dbf6c20144aa78e896a5 100644
|
||||
index 25b93ba43b98874d658d58e3faab12049f6e4edf..df8e9ee5564227e700d0fb83390997ea85a5a869 100644
|
||||
--- a/src/unix/linux.c
|
||||
+++ b/src/unix/linux.c
|
||||
@@ -2098,7 +2098,7 @@ static uint64_t uv__read_uint64(const char* filename) {
|
||||
@@ -2113,7 +2113,7 @@ static uint64_t uv__read_uint64(const char* filename) {
|
||||
* finds the location and length of the memory controller mount path.
|
||||
* This disregards the leading / for easy concatenation of paths.
|
||||
* Returns NULL if the memory controller wasn't found. */
|
||||
@@ -20,7 +20,7 @@ index e0c4902385edac10ac31bc5075a85a45025615f9..091c0474cfe37de4eb55dbf6c20144aa
|
||||
int* n) {
|
||||
char* p;
|
||||
|
||||
@@ -2119,7 +2119,7 @@ static char* uv__cgroup1_find_memory_controller(char buf[static 1024],
|
||||
@@ -2134,7 +2134,7 @@ static char* uv__cgroup1_find_memory_controller(char buf[static 1024],
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ index e0c4902385edac10ac31bc5075a85a45025615f9..091c0474cfe37de4eb55dbf6c20144aa
|
||||
uint64_t* max) {
|
||||
char filename[4097];
|
||||
char* p;
|
||||
@@ -2159,7 +2159,7 @@ update_limits:
|
||||
@@ -2174,7 +2174,7 @@ update_limits:
|
||||
*max = UINT64_MAX;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ index e0c4902385edac10ac31bc5075a85a45025615f9..091c0474cfe37de4eb55dbf6c20144aa
|
||||
uint64_t* max) {
|
||||
char filename[4097];
|
||||
char* p;
|
||||
@@ -2176,7 +2176,7 @@ static void uv__get_cgroup2_memory_limits(char buf[static 1024], uint64_t* high,
|
||||
@@ -2191,7 +2191,7 @@ static void uv__get_cgroup2_memory_limits(char buf[static 1024], uint64_t* high,
|
||||
*high = uv__read_uint64(filename);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ index e0c4902385edac10ac31bc5075a85a45025615f9..091c0474cfe37de4eb55dbf6c20144aa
|
||||
uint64_t high;
|
||||
uint64_t max;
|
||||
|
||||
@@ -2202,7 +2202,7 @@ uint64_t uv_get_constrained_memory(void) {
|
||||
@@ -2217,7 +2217,7 @@ uint64_t uv_get_constrained_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ index e0c4902385edac10ac31bc5075a85a45025615f9..091c0474cfe37de4eb55dbf6c20144aa
|
||||
char filename[4097];
|
||||
uint64_t current;
|
||||
char* p;
|
||||
@@ -2226,7 +2226,7 @@ static uint64_t uv__get_cgroup1_current_memory(char buf[static 1024]) {
|
||||
@@ -2241,7 +2241,7 @@ static uint64_t uv__get_cgroup1_current_memory(char buf[static 1024]) {
|
||||
return uv__read_uint64("/sys/fs/cgroup/memory/memory.usage_in_bytes");
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tyler Veness <calcmogul@gmail.com>
|
||||
Date: Fri, 14 Jul 2023 16:40:18 -0700
|
||||
Subject: [PATCH 09/10] Add pragmas for missing libraries and set _WIN32_WINNT
|
||||
to Windows 10
|
||||
Subject: [PATCH 8/9] Add pragmas for missing libraries and set _WIN32_WINNT to
|
||||
Windows 10
|
||||
|
||||
This makes GetSystemTimePreciseAsFileTime() available.
|
||||
|
||||
@@ -14,7 +14,7 @@ https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt.
|
||||
2 files changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/include/uv/win.h b/include/uv/win.h
|
||||
index 9a8c990c1b182633f23890cb5f4532b6bee2b22c..f17abc1f92681971da8ec603f7a20204fd53e5d1 100644
|
||||
index 48e1402d155ceb80e35a904815cb5739cab2fbe8..576f0fa52b60524711e04e94c740ae9b85fb36a9 100644
|
||||
--- a/include/uv/win.h
|
||||
+++ b/include/uv/win.h
|
||||
@@ -20,7 +20,7 @@
|
||||
@@ -27,7 +27,7 @@ index 9a8c990c1b182633f23890cb5f4532b6bee2b22c..f17abc1f92681971da8ec603f7a20204
|
||||
|
||||
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
|
||||
diff --git a/src/win/util.c b/src/win/util.c
|
||||
index 52c31979589e4ed7fe12af200f7e8daab9e02797..6529aa36f32eab1114488b7445a6bd872975b97b 100644
|
||||
index 1239831dcc0c5fdb8e267d4dd8e73cb73fdc88c9..907a09840931b37ec74b8011aedaee3100b5c643 100644
|
||||
--- a/src/win/util.c
|
||||
+++ b/src/win/util.c
|
||||
@@ -73,7 +73,9 @@ static char *process_title;
|
||||
@@ -1,7 +1,7 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jade Turner <spacey-sooty@proton.me>
|
||||
Date: Wed, 26 Jun 2024 11:40:37 +0800
|
||||
Subject: [PATCH 10/10] Remove swearing
|
||||
Subject: [PATCH 9/9] Remove swearing
|
||||
|
||||
---
|
||||
src/win/fs.c | 2 +-
|
||||
@@ -9,10 +9,10 @@ Subject: [PATCH 10/10] Remove swearing
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/win/fs.c b/src/win/fs.c
|
||||
index 05488e5d67101adba611f882ded4f6dc5a462d9a..d6b2b3f1d08d846fa941942f4bb33ae2fa30e320 100644
|
||||
index 572a82dca3cbcdb7829241dd520e8f34591d81e9..eaa0342f97c87cac3d6802e8f6c8c97d5bdc12ea 100644
|
||||
--- a/src/win/fs.c
|
||||
+++ b/src/win/fs.c
|
||||
@@ -1704,7 +1704,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
@@ -1845,7 +1845,7 @@ INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf,
|
||||
* impossible to delete the file afterwards, since read-only files can't be
|
||||
* deleted.
|
||||
*
|
||||
@@ -22,7 +22,7 @@ index 05488e5d67101adba611f882ded4f6dc5a462d9a..d6b2b3f1d08d846fa941942f4bb33ae2
|
||||
*
|
||||
* And uv_fs_chmod should probably just fail on windows or be a total no-op.
|
||||
diff --git a/src/win/tty.c b/src/win/tty.c
|
||||
index 7294f311e17d5d02e5873e60f8f0cdd551f6d34d..f7d5ef6c29f97a979fb1df993b66e31830af55c4 100644
|
||||
index 9a4252d9d89d82fdd316312cc4550dd3c0fe798d..f1acef2c64e5a7397c86729d81d1f15ee74b7a43 100644
|
||||
--- a/src/win/tty.c
|
||||
+++ b/src/win/tty.c
|
||||
@@ -1055,7 +1055,7 @@ int uv__tty_read_stop(uv_tty_t* handle) {
|
||||
@@ -257,7 +257,9 @@ typedef struct uv_metrics_s uv_metrics_t;
|
||||
|
||||
typedef enum {
|
||||
UV_LOOP_BLOCK_SIGNAL = 0,
|
||||
UV_METRICS_IDLE_TIME
|
||||
UV_METRICS_IDLE_TIME,
|
||||
UV_LOOP_USE_IO_URING_SQPOLL
|
||||
#define UV_LOOP_USE_IO_URING_SQPOLL UV_LOOP_USE_IO_URING_SQPOLL
|
||||
} uv_loop_option;
|
||||
|
||||
typedef enum {
|
||||
@@ -601,7 +603,18 @@ UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
|
||||
|
||||
enum uv_tcp_flags {
|
||||
/* Used with uv_tcp_bind, when an IPv6 address is used. */
|
||||
UV_TCP_IPV6ONLY = 1
|
||||
UV_TCP_IPV6ONLY = 1,
|
||||
|
||||
/* Enable SO_REUSEPORT socket option when binding the handle.
|
||||
* This allows completely duplicate bindings by multiple processes
|
||||
* or threads if they all set SO_REUSEPORT before binding the port.
|
||||
* Incoming connections are distributed across the participating
|
||||
* listener sockets.
|
||||
*
|
||||
* This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+,
|
||||
* FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now.
|
||||
*/
|
||||
UV_TCP_REUSEPORT = 2,
|
||||
};
|
||||
|
||||
UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle,
|
||||
@@ -642,10 +655,13 @@ enum uv_udp_flags {
|
||||
UV_UDP_PARTIAL = 2,
|
||||
/*
|
||||
* Indicates if SO_REUSEADDR will be set when binding the handle.
|
||||
* This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
|
||||
* Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
|
||||
* multiple threads or processes can bind to the same address without error
|
||||
* (provided they all set the flag) but only the last one to bind will receive
|
||||
* This sets the SO_REUSEPORT socket flag on the BSDs (except for
|
||||
* DragonFlyBSD), OS X, and other platforms where SO_REUSEPORTs don't
|
||||
* have the capability of load balancing, as the opposite of what
|
||||
* UV_UDP_REUSEPORT would do. On other Unix platforms, it sets the
|
||||
* SO_REUSEADDR flag. What that means is that multiple threads or
|
||||
* processes can bind to the same address without error (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,
|
||||
@@ -668,6 +684,18 @@ enum uv_udp_flags {
|
||||
* This flag is no-op on platforms other than Linux.
|
||||
*/
|
||||
UV_UDP_LINUX_RECVERR = 32,
|
||||
/*
|
||||
* Indicates if SO_REUSEPORT will be set when binding the handle.
|
||||
* This sets the SO_REUSEPORT socket option on supported platforms.
|
||||
* Unlike UV_UDP_REUSEADDR, this flag will make multiple threads or
|
||||
* processes that are binding to the same address and port "share"
|
||||
* the port, which means incoming datagrams are distributed across
|
||||
* the receiving sockets among threads or processes.
|
||||
*
|
||||
* This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+,
|
||||
* FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now.
|
||||
*/
|
||||
UV_UDP_REUSEPORT = 64,
|
||||
/*
|
||||
* Indicates that recvmmsg should be used, if available.
|
||||
*/
|
||||
@@ -1894,17 +1922,17 @@ struct uv_loop_s {
|
||||
UV_EXTERN void* uv_loop_get_data(const uv_loop_t*);
|
||||
UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
|
||||
|
||||
/* String utilities needed internally for dealing with Windows. */
|
||||
size_t uv_utf16_length_as_wtf8(const uint16_t* utf16,
|
||||
ssize_t utf16_len);
|
||||
int uv_utf16_to_wtf8(const uint16_t* utf16,
|
||||
ssize_t utf16_len,
|
||||
char** wtf8_ptr,
|
||||
size_t* wtf8_len_ptr);
|
||||
ssize_t uv_wtf8_length_as_utf16(const char* wtf8);
|
||||
void uv_wtf8_to_utf16(const char* wtf8,
|
||||
uint16_t* utf16,
|
||||
size_t utf16_len);
|
||||
/* Unicode utilities needed for dealing with Windows. */
|
||||
UV_EXTERN size_t uv_utf16_length_as_wtf8(const uint16_t* utf16,
|
||||
ssize_t utf16_len);
|
||||
UV_EXTERN int uv_utf16_to_wtf8(const uint16_t* utf16,
|
||||
ssize_t utf16_len,
|
||||
char** wtf8_ptr,
|
||||
size_t* wtf8_len_ptr);
|
||||
UV_EXTERN ssize_t uv_wtf8_length_as_utf16(const char* wtf8);
|
||||
UV_EXTERN void uv_wtf8_to_utf16(const char* wtf8,
|
||||
uint16_t* utf16,
|
||||
size_t utf16_len);
|
||||
|
||||
/* Don't export the private CPP symbols. */
|
||||
#undef UV_HANDLE_TYPE_PRIVATE
|
||||
|
||||
@@ -35,21 +35,7 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file defines data structures for different types of trees:
|
||||
* splay trees and red-black trees.
|
||||
*
|
||||
* A splay tree is a self-organizing data structure. Every operation
|
||||
* on the tree causes a splay to happen. The splay moves the requested
|
||||
* node to the root of the tree and partly rebalances it.
|
||||
*
|
||||
* This has the benefit that request locality causes faster lookups as
|
||||
* the requested nodes move to the top of the tree. On the other hand,
|
||||
* every lookup causes memory writes.
|
||||
*
|
||||
* The Balance Theorem bounds the total access time for m operations
|
||||
* and n inserts on an initially empty tree as O((m + n)lg n). The
|
||||
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
|
||||
*
|
||||
* This file defines data structures for red-black trees.
|
||||
* A red-black tree is a binary search tree with the node color as an
|
||||
* extra attribute. It fulfills a set of conditions:
|
||||
* - every search path from the root to a leaf consists of the
|
||||
@@ -61,239 +47,6 @@
|
||||
* The maximum height of a red-black tree is 2lg (n+1).
|
||||
*/
|
||||
|
||||
#define SPLAY_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sph_root; /* root of the tree */ \
|
||||
}
|
||||
|
||||
#define SPLAY_INITIALIZER(root) \
|
||||
{ NULL }
|
||||
|
||||
#define SPLAY_INIT(root) do { \
|
||||
(root)->sph_root = NULL; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *spe_left; /* left element */ \
|
||||
struct type *spe_right; /* right element */ \
|
||||
}
|
||||
|
||||
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
|
||||
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
|
||||
#define SPLAY_ROOT(head) (head)->sph_root
|
||||
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
|
||||
|
||||
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
|
||||
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKLEFT(head, tmp, field) do { \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
|
||||
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
/* Generates prototypes and inline functions */
|
||||
|
||||
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
|
||||
void name##_SPLAY(struct name *, struct type *); \
|
||||
void name##_SPLAY_MINMAX(struct name *, int); \
|
||||
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
|
||||
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
|
||||
\
|
||||
/* Finds the node with the same key as elm */ \
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_FIND(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return(NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) \
|
||||
return (head->sph_root); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
name##_SPLAY(head, elm); \
|
||||
if (SPLAY_RIGHT(elm, field) != NULL) { \
|
||||
elm = SPLAY_RIGHT(elm, field); \
|
||||
while (SPLAY_LEFT(elm, field) != NULL) { \
|
||||
elm = SPLAY_LEFT(elm, field); \
|
||||
} \
|
||||
} else \
|
||||
elm = NULL; \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_MIN_MAX(struct name *head, int val) \
|
||||
{ \
|
||||
name##_SPLAY_MINMAX(head, val); \
|
||||
return (SPLAY_ROOT(head)); \
|
||||
}
|
||||
|
||||
/* Main splay operation.
|
||||
* Moves node close to the key of elm to top
|
||||
*/
|
||||
#define SPLAY_GENERATE(name, type, field, cmp) \
|
||||
struct type * \
|
||||
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
if (SPLAY_EMPTY(head)) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
|
||||
} else { \
|
||||
int __comp; \
|
||||
name##_SPLAY(head, elm); \
|
||||
__comp = (cmp)(elm, (head)->sph_root); \
|
||||
if(__comp < 0) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_LEFT((head)->sph_root, field) = NULL; \
|
||||
} else if (__comp > 0) { \
|
||||
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
SPLAY_LEFT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
|
||||
} else \
|
||||
return ((head)->sph_root); \
|
||||
} \
|
||||
(head)->sph_root = (elm); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
struct type * \
|
||||
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *__tmp; \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return (NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) { \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
} else { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||
name##_SPLAY(head, elm); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
name##_SPLAY(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
int __comp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) > 0){ \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
} \
|
||||
\
|
||||
/* Splay with either the minimum or the maximum element \
|
||||
* Used to find minimum or maximum element in tree. \
|
||||
*/ \
|
||||
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
|
||||
{ \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
for (;;) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp > 0) { \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
}
|
||||
|
||||
#define SPLAY_NEGINF -1
|
||||
#define SPLAY_INF 1
|
||||
|
||||
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
|
||||
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
|
||||
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
|
||||
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
|
||||
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
|
||||
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
|
||||
|
||||
#define SPLAY_FOREACH(x, name, head) \
|
||||
for ((x) = SPLAY_MIN(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = SPLAY_NEXT(name, head, x))
|
||||
|
||||
/* Macros that define a red-black tree */
|
||||
#define RB_HEAD(name, type) \
|
||||
struct name { \
|
||||
@@ -730,8 +483,8 @@ name##_RB_MINMAX(struct name *head, int val) \
|
||||
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
|
||||
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
|
||||
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
|
||||
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
|
||||
#define RB_PREV(name, x, y) name##_RB_PREV(y)
|
||||
#define RB_NEXT(name, x) name##_RB_NEXT(x)
|
||||
#define RB_PREV(name, x) name##_RB_PREV(x)
|
||||
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
|
||||
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
*/
|
||||
|
||||
#define UV_VERSION_MAJOR 1
|
||||
#define UV_VERSION_MINOR 48
|
||||
#define UV_VERSION_PATCH 0
|
||||
#define UV_VERSION_MINOR 49
|
||||
#define UV_VERSION_PATCH 2
|
||||
#define UV_VERSION_IS_RELEASE 1
|
||||
#define UV_VERSION_SUFFIX ""
|
||||
|
||||
|
||||
@@ -294,8 +294,8 @@ typedef struct {
|
||||
#define UV_ONCE_INIT { 0, NULL }
|
||||
|
||||
typedef struct uv_once_s {
|
||||
unsigned char ran;
|
||||
HANDLE event;
|
||||
unsigned char unused;
|
||||
INIT_ONCE init_once;
|
||||
} uv_once_t;
|
||||
|
||||
/* Platform-specific definitions for uv_spawn support. */
|
||||
|
||||
@@ -82,7 +82,7 @@ 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);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
if (status == 0)
|
||||
status = req->status;
|
||||
|
||||
@@ -360,7 +360,7 @@ static void uv__queue_done(struct uv__work* w, int err) {
|
||||
uv_work_t* req;
|
||||
|
||||
req = container_of(w, uv_work_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
if (req->after_work_cb == NULL)
|
||||
return;
|
||||
|
||||
@@ -54,7 +54,8 @@
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <sys/filio.h>
|
||||
# endif /* defined(__APPLE__) */
|
||||
# include <sys/sysctl.h>
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
@@ -95,6 +96,15 @@ extern char** environ;
|
||||
# define uv__accept4 accept4
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
# include <sys/param.h>
|
||||
# include <sys/cpuset.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
# include <sched.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
|
||||
# include <sanitizer/linux_syscall_hooks.h>
|
||||
#endif
|
||||
@@ -157,7 +167,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
||||
break;
|
||||
|
||||
case UV_TTY:
|
||||
uv__stream_close((uv_stream_t*)handle);
|
||||
uv__tty_close((uv_tty_t*)handle);
|
||||
break;
|
||||
|
||||
case UV_TCP:
|
||||
@@ -1033,7 +1043,7 @@ int uv_getrusage(uv_rusage_t* rusage) {
|
||||
#if defined(__APPLE__)
|
||||
rusage->ru_maxrss /= 1024; /* macOS and iOS report bytes. */
|
||||
#elif defined(__sun)
|
||||
rusage->ru_maxrss /= getpagesize() / 1024; /* Solaris reports pages. */
|
||||
rusage->ru_maxrss *= getpagesize() / 1024; /* Solaris reports pages. */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -1625,6 +1635,7 @@ static int set_nice_for_calling_thread(int priority) {
|
||||
* If the function fails, the return value is non-zero.
|
||||
*/
|
||||
int uv_thread_setpriority(uv_thread_t tid, int priority) {
|
||||
#if !defined(__GNU__)
|
||||
int r;
|
||||
int min;
|
||||
int max;
|
||||
@@ -1690,6 +1701,10 @@ int uv_thread_setpriority(uv_thread_t tid, int priority) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else /* !defined(__GNU__) */
|
||||
/* Simulate success on systems where thread priority is not implemented. */
|
||||
return 0;
|
||||
#endif /* !defined(__GNU__) */
|
||||
}
|
||||
|
||||
int uv_os_uname(uv_utsname_t* buffer) {
|
||||
@@ -1873,11 +1888,31 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined (__FreeBSD__)
|
||||
# define uv__cpu_count(cpuset) CPU_COUNT(cpuset)
|
||||
#elif defined(__NetBSD__)
|
||||
static int uv__cpu_count(cpuset_t* set) {
|
||||
int rc;
|
||||
cpuid_t i;
|
||||
|
||||
rc = 0;
|
||||
for (i = 0;; i++) {
|
||||
int r = cpuset_isset(i, set);
|
||||
if (r < 0)
|
||||
break;
|
||||
if (r)
|
||||
rc++;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
unsigned int uv_available_parallelism(void) {
|
||||
long rc = -1;
|
||||
|
||||
#ifdef __linux__
|
||||
cpu_set_t set;
|
||||
long rc;
|
||||
|
||||
memset(&set, 0, sizeof(set));
|
||||
|
||||
@@ -1886,29 +1921,127 @@ unsigned int uv_available_parallelism(void) {
|
||||
* 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;
|
||||
rc = uv__cpu_count(&set);
|
||||
#elif defined(__MVS__)
|
||||
int rc;
|
||||
|
||||
rc = __get_num_online_cpus();
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
|
||||
return (unsigned) rc;
|
||||
#else /* __linux__ */
|
||||
long rc;
|
||||
#elif defined(__FreeBSD__)
|
||||
cpuset_t set;
|
||||
|
||||
memset(&set, 0, sizeof(set));
|
||||
|
||||
if (0 == cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(set), &set))
|
||||
rc = uv__cpu_count(&set);
|
||||
#elif defined(__NetBSD__)
|
||||
cpuset_t* set = cpuset_create();
|
||||
if (set != NULL) {
|
||||
if (0 == sched_getaffinity_np(getpid(), sizeof(set), &set))
|
||||
rc = uv__cpu_count(&set);
|
||||
cpuset_destroy(set);
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
int nprocs;
|
||||
size_t i;
|
||||
size_t len = sizeof(nprocs);
|
||||
static const char *mib[] = {
|
||||
"hw.activecpu",
|
||||
"hw.logicalcpu",
|
||||
"hw.ncpu"
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mib); i++) {
|
||||
if (0 == sysctlbyname(mib[i], &nprocs, &len, NULL, 0) &&
|
||||
len == sizeof(nprocs) &&
|
||||
nprocs > 0) {
|
||||
rc = nprocs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif defined(__OpenBSD__)
|
||||
int nprocs;
|
||||
size_t i;
|
||||
size_t len = sizeof(nprocs);
|
||||
static int mib[][2] = {
|
||||
# ifdef HW_NCPUONLINE
|
||||
{ CTL_HW, HW_NCPUONLINE },
|
||||
# endif
|
||||
{ CTL_HW, HW_NCPU }
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mib); i++) {
|
||||
if (0 == sysctl(mib[i], ARRAY_SIZE(mib[i]), &nprocs, &len, NULL, 0) &&
|
||||
len == sizeof(nprocs) &&
|
||||
nprocs > 0) {
|
||||
rc = nprocs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
if (rc < 0)
|
||||
rc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
double rc_with_cgroup;
|
||||
uv__cpu_constraint c = {0, 0, 0.0};
|
||||
|
||||
if (uv__get_constrained_cpu(&c) == 0 && c.period_length > 0) {
|
||||
rc_with_cgroup = (double)c.quota_per_period / c.period_length * c.proportions;
|
||||
if (rc_with_cgroup < rc)
|
||||
rc = (long)rc_with_cgroup; /* Casting is safe since rc_with_cgroup < rc < LONG_MAX */
|
||||
}
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
rc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
|
||||
return (unsigned) rc;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
int uv__sock_reuseport(int fd) {
|
||||
int on = 1;
|
||||
#if defined(__FreeBSD__) && __FreeBSD__ >= 12 && defined(SO_REUSEPORT_LB)
|
||||
/* FreeBSD 12 introduced a new socket option named SO_REUSEPORT_LB
|
||||
* with the capability of load balancing, it's the substitution of
|
||||
* the SO_REUSEPORTs on Linux and DragonFlyBSD. */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
#elif (defined(__linux__) || \
|
||||
defined(_AIX73) || \
|
||||
(defined(__DragonFly__) && __DragonFly_version >= 300600) || \
|
||||
(defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4)) && \
|
||||
defined(SO_REUSEPORT)
|
||||
/* On Linux 3.9+, the SO_REUSEPORT implementation distributes connections
|
||||
* evenly across all of the threads (or processes) that are blocked in
|
||||
* accept() on the same port. As with TCP, SO_REUSEPORT distributes datagrams
|
||||
* evenly across all of the receiving threads (or process).
|
||||
*
|
||||
* DragonFlyBSD 3.6.0 extended SO_REUSEPORT to distribute workload to
|
||||
* available sockets, which made it the equivalent of Linux's SO_REUSEPORT.
|
||||
*
|
||||
* AIX 7.2.5 added the feature that would add the capability to distribute
|
||||
* incoming connections or datagrams across all listening ports for SO_REUSEPORT.
|
||||
*
|
||||
* Solaris 11 supported SO_REUSEPORT, but it's implemented only for
|
||||
* binding to the same address and port, without load balancing.
|
||||
* Solaris 11.4 extended SO_REUSEPORT with the capability of load balancing.
|
||||
*/
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
(void) (fd);
|
||||
(void) (on);
|
||||
/* SO_REUSEPORTs do not have the capability of load balancing on platforms
|
||||
* other than those mentioned above. The semantics are completely different,
|
||||
* therefore we shouldn't enable it, but fail this operation to indicate that
|
||||
* UV_[TCP/UDP]_REUSEPORT is not supported on these platforms. */
|
||||
return UV_ENOTSUP;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,9 +36,45 @@ int uv_uptime(double* uptime) {
|
||||
}
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
/* FIXME: read /proc/meminfo? */
|
||||
*rss = 0;
|
||||
char buf[1024];
|
||||
const char* s;
|
||||
long val;
|
||||
int rc;
|
||||
int i;
|
||||
struct sysinfo si;
|
||||
|
||||
/* rss: 24th element */
|
||||
rc = uv__slurp("/proc/self/stat", buf, sizeof(buf));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* find the last ')' */
|
||||
s = strrchr(buf, ')');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
|
||||
for (i = 1; i <= 22; i++) {
|
||||
s = strchr(s + 1, ' ');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
val = strtol(s, NULL, 10);
|
||||
if (val < 0 || errno != 0)
|
||||
goto err;
|
||||
|
||||
do
|
||||
rc = sysinfo(&si);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
if (rc == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*rss = val * si.mem_unit;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
|
||||
19
wpinet/src/main/native/thirdparty/libuv/src/unix/darwin-syscalls.h
vendored
Normal file
19
wpinet/src/main/native/thirdparty/libuv/src/unix/darwin-syscalls.h
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef UV_DARWIN_SYSCALLS_H_
|
||||
#define UV_DARWIN_SYSCALLS_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
/* https://github.com/apple/darwin-xnu/blob/master/bsd/sys/socket.h */
|
||||
|
||||
struct mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
size_t msg_len;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
ssize_t recvmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags);
|
||||
ssize_t sendmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags);
|
||||
}
|
||||
|
||||
#endif /* UV_DARWIN_SYSCALLS_H_ */
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
@@ -34,7 +33,6 @@
|
||||
#include <unistd.h> /* sysconf */
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
static uint64_t (*time_func)(void);
|
||||
static mach_timebase_info_data_t timebase;
|
||||
|
||||
|
||||
@@ -56,16 +54,12 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
static void uv__hrtime_init_once(void) {
|
||||
if (KERN_SUCCESS != mach_timebase_info(&timebase))
|
||||
abort();
|
||||
|
||||
time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time");
|
||||
if (time_func == NULL)
|
||||
time_func = mach_absolute_time;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
uv_once(&once, uv__hrtime_init_once);
|
||||
return time_func() * timebase.numer / timebase.denom;
|
||||
return mach_continuous_time() * timebase.numer / timebase.denom;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,12 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <paths.h>
|
||||
#include <sys/user.h>
|
||||
#if defined(__DragonFly__)
|
||||
# include <sys/event.h>
|
||||
# include <sys/kinfo.h>
|
||||
#else
|
||||
# include <sys/user.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
@@ -84,17 +84,6 @@
|
||||
# include <sys/statfs.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__) || \
|
||||
(defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \
|
||||
(defined(__sun) && !defined(__illumos__)) || \
|
||||
(defined(__APPLE__) && !TARGET_OS_IPHONE && \
|
||||
MAC_OS_X_VERSION_MIN_REQUIRED < 110000)
|
||||
#define preadv(fd, bufs, nbufs, off) \
|
||||
pread(fd, (bufs)->iov_base, (bufs)->iov_len, off)
|
||||
#define pwritev(fd, bufs, nbufs, off) \
|
||||
pwrite(fd, (bufs)->iov_base, (bufs)->iov_len, off)
|
||||
#endif
|
||||
|
||||
#if defined(_AIX) && _XOPEN_SOURCE <= 600
|
||||
extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
|
||||
#endif
|
||||
@@ -151,7 +140,7 @@ extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
|
||||
#define POST \
|
||||
do { \
|
||||
if (cb != NULL) { \
|
||||
uv__req_register(loop, req); \
|
||||
uv__req_register(loop); \
|
||||
uv__work_submit(loop, \
|
||||
&req->work_req, \
|
||||
UV__WORK_FAST_IO, \
|
||||
@@ -408,6 +397,123 @@ static ssize_t uv__fs_open(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__preadv_or_pwritev_emul(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off,
|
||||
int is_pread) {
|
||||
ssize_t total;
|
||||
ssize_t r;
|
||||
size_t i;
|
||||
size_t n;
|
||||
void* p;
|
||||
|
||||
total = 0;
|
||||
for (i = 0; i < (size_t) nbufs; i++) {
|
||||
p = bufs[i].iov_base;
|
||||
n = bufs[i].iov_len;
|
||||
|
||||
do
|
||||
if (is_pread)
|
||||
r = pread(fd, p, n, off);
|
||||
else
|
||||
r = pwrite(fd, p, n, off);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1) {
|
||||
if (total > 0)
|
||||
return total;
|
||||
return -1;
|
||||
}
|
||||
|
||||
off += r;
|
||||
total += r;
|
||||
|
||||
if ((size_t) r < n)
|
||||
return total;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
typedef int uv__iovcnt;
|
||||
#else
|
||||
typedef size_t uv__iovcnt;
|
||||
#endif
|
||||
|
||||
|
||||
static ssize_t uv__preadv_emul(int fd,
|
||||
const struct iovec* bufs,
|
||||
uv__iovcnt nbufs,
|
||||
off_t off) {
|
||||
return uv__preadv_or_pwritev_emul(fd, bufs, nbufs, off, /*is_pread*/1);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__pwritev_emul(int fd,
|
||||
const struct iovec* bufs,
|
||||
uv__iovcnt nbufs,
|
||||
off_t off) {
|
||||
return uv__preadv_or_pwritev_emul(fd, bufs, nbufs, off, /*is_pread*/0);
|
||||
}
|
||||
|
||||
|
||||
/* The function pointer cache is an uintptr_t because std::atomic<void>*
|
||||
* doesn't work on macos/ios/etc...
|
||||
* Disable optimization on armv7 to work around the bug described in
|
||||
* https://github.com/libuv/libuv/issues/4532
|
||||
*/
|
||||
#if defined(__arm__) && (__ARM_ARCH == 7)
|
||||
__attribute__((optimize("O0")))
|
||||
#endif
|
||||
static ssize_t uv__preadv_or_pwritev(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off,
|
||||
std::atomic<uintptr_t>* cache,
|
||||
int is_pread) {
|
||||
ssize_t (*f)(int, const struct iovec*, uv__iovcnt, off_t);
|
||||
void* p;
|
||||
|
||||
p = (void*) atomic_load_explicit(cache, std::memory_order_relaxed);
|
||||
if (p == NULL) {
|
||||
#ifdef RTLD_DEFAULT
|
||||
p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev");
|
||||
dlerror(); /* Clear errors. */
|
||||
#endif /* RTLD_DEFAULT */
|
||||
if (p == NULL)
|
||||
p = (void*)(is_pread ? uv__preadv_emul : uv__pwritev_emul);
|
||||
atomic_store_explicit(cache, (uintptr_t) p, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/* Use memcpy instead of `f = p` to work around a compiler bug,
|
||||
* see https://github.com/libuv/libuv/issues/4532
|
||||
*/
|
||||
memcpy(&f, &p, sizeof(p));
|
||||
return f(fd, bufs, nbufs, off);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__preadv(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off) {
|
||||
static std::atomic<uintptr_t> cache;
|
||||
return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/1);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__pwritev(int fd,
|
||||
const struct iovec* bufs,
|
||||
size_t nbufs,
|
||||
off_t off) {
|
||||
static std::atomic<uintptr_t> cache;
|
||||
return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/0);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
const struct iovec* bufs;
|
||||
unsigned int iovmax;
|
||||
@@ -435,7 +541,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
if (nbufs == 1)
|
||||
r = pread(fd, bufs->iov_base, bufs->iov_len, off);
|
||||
else if (nbufs > 1)
|
||||
r = preadv(fd, bufs, nbufs, off);
|
||||
r = uv__preadv(fd, bufs, nbufs, off);
|
||||
}
|
||||
|
||||
#ifdef __PASE__
|
||||
@@ -693,14 +799,23 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
|
||||
static ssize_t uv__fs_realpath(uv_fs_t* req) {
|
||||
char* buf;
|
||||
char* tmp;
|
||||
|
||||
#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L
|
||||
buf = realpath(req->path, NULL);
|
||||
if (buf == NULL)
|
||||
tmp = realpath(req->path, NULL);
|
||||
if (tmp == NULL)
|
||||
return -1;
|
||||
buf = uv__strdup(tmp);
|
||||
free(tmp); /* _Not_ uv__free. */
|
||||
if (buf == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
ssize_t len;
|
||||
|
||||
(void)tmp;
|
||||
|
||||
len = uv__fs_pathmax_size(req->path);
|
||||
buf = (char*)uv__malloc(len + 1);
|
||||
|
||||
@@ -964,7 +1079,10 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
#elif defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
/* sendfile() on iOS(arm64) will throw SIGSYS signal cause crash. */
|
||||
#elif (defined(__APPLE__) && !TARGET_OS_IPHONE) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__)
|
||||
{
|
||||
off_t len;
|
||||
ssize_t r;
|
||||
@@ -1114,7 +1232,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
|
||||
if (nbufs == 1)
|
||||
r = pwrite(fd, bufs->iov_base, bufs->iov_len, off);
|
||||
else if (nbufs > 1)
|
||||
r = pwritev(fd, bufs, nbufs, off);
|
||||
r = uv__pwritev(fd, bufs, nbufs, off);
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -1127,6 +1245,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
uv_file dstfd;
|
||||
struct stat src_statsbuf;
|
||||
struct stat dst_statsbuf;
|
||||
struct timespec times[2];
|
||||
int dst_flags;
|
||||
int result;
|
||||
int err;
|
||||
@@ -1204,6 +1323,35 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the timestamps of the destination file to match the source file.
|
||||
*/
|
||||
#if defined(__APPLE__)
|
||||
times[0] = src_statsbuf.st_atimespec;
|
||||
times[1] = src_statsbuf.st_mtimespec;
|
||||
#elif defined(_AIX)
|
||||
times[0].tv_sec = src_statsbuf.st_atime;
|
||||
times[0].tv_nsec = src_statsbuf.st_atime_n;
|
||||
times[1].tv_sec = src_statsbuf.st_mtime;
|
||||
times[1].tv_nsec = src_statsbuf.st_mtime_n;
|
||||
#else
|
||||
times[0] = src_statsbuf.st_atim;
|
||||
times[1] = src_statsbuf.st_mtim;
|
||||
#endif
|
||||
|
||||
if (futimens(dstfd, times) == -1) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the ownership and permissions of the destination file to match the
|
||||
* source file.
|
||||
* `cp -p` does not care about errors here, so we don't either. Reuse the
|
||||
* `result` variable to silence a -Wunused-result warning.
|
||||
*/
|
||||
result = fchown(dstfd, src_statsbuf.st_uid, src_statsbuf.st_gid);
|
||||
|
||||
if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
|
||||
err = UV__ERR(errno);
|
||||
#ifdef __linux__
|
||||
@@ -1621,7 +1769,7 @@ static void uv__fs_done(struct uv__work* w, int status) {
|
||||
uv_fs_t* req;
|
||||
|
||||
req = container_of(w, uv_fs_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
assert(req->result == 0);
|
||||
@@ -1633,7 +1781,7 @@ static void uv__fs_done(struct uv__work* w, int status) {
|
||||
|
||||
|
||||
void uv__fs_post(uv_loop_t* loop, uv_fs_t* req) {
|
||||
uv__req_register(loop, req);
|
||||
uv__req_register(loop);
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_FAST_IO,
|
||||
@@ -1768,6 +1916,9 @@ int uv_fs_ftruncate(uv_loop_t* loop,
|
||||
INIT(FTRUNCATE);
|
||||
req->file = file;
|
||||
req->off = off;
|
||||
if (cb != NULL)
|
||||
if (uv__iou_fs_ftruncate(loop, req))
|
||||
return 0;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
@@ -276,10 +276,6 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
|
||||
path += handle->realpath_len;
|
||||
len -= handle->realpath_len;
|
||||
|
||||
/* Ignore events with path equal to directory itself */
|
||||
if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
continue;
|
||||
|
||||
if (len == 0) {
|
||||
/* Since we're using fsevents to watch the file itself,
|
||||
* realpath == path, and we now need to get the basename of the file back
|
||||
@@ -793,6 +789,7 @@ int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
|
||||
/* Runs in UV loop to initialize handle */
|
||||
int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
char* buf;
|
||||
int err;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
@@ -801,9 +798,13 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
return err;
|
||||
|
||||
/* Get absolute path to file */
|
||||
handle->realpath = realpath(handle->path, NULL);
|
||||
if (handle->realpath == NULL)
|
||||
buf = realpath(handle->path, NULL);
|
||||
if (buf == NULL)
|
||||
return UV__ERR(errno);
|
||||
handle->realpath = uv__strdup(buf);
|
||||
free(buf); /* _Not_ uv__free. */
|
||||
if (handle->realpath == NULL)
|
||||
return UV_ENOMEM;
|
||||
handle->realpath_len = strlen(handle->realpath);
|
||||
|
||||
/* Initialize event queue */
|
||||
|
||||
@@ -109,7 +109,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
uv_getaddrinfo_t* req;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
/* See initialization in uv_getaddrinfo(). */
|
||||
if (req->hints)
|
||||
|
||||
@@ -58,7 +58,7 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) {
|
||||
char* service;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
host = service = NULL;
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
|
||||
@@ -71,8 +71,11 @@
|
||||
# include <poll.h>
|
||||
#endif /* _AIX */
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
# include <AvailabilityMacros.h>
|
||||
#if defined(__APPLE__)
|
||||
# include "darwin-syscalls.h"
|
||||
# if !TARGET_OS_IPHONE
|
||||
# include <AvailabilityMacros.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -157,7 +160,8 @@ typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
|
||||
/* loop flags */
|
||||
enum {
|
||||
UV_LOOP_BLOCK_SIGPROF = 0x1,
|
||||
UV_LOOP_REAP_CHILDREN = 0x2
|
||||
UV_LOOP_REAP_CHILDREN = 0x2,
|
||||
UV_LOOP_ENABLE_IO_URING_SQPOLL = 0x4
|
||||
};
|
||||
|
||||
/* flags of excluding ifaddr */
|
||||
@@ -245,6 +249,7 @@ int uv__close(int fd); /* preserves errno */
|
||||
int uv__close_nocheckstdio(int fd);
|
||||
int uv__close_nocancel(int fd);
|
||||
int uv__socket(int domain, int type, int protocol);
|
||||
int uv__sock_reuseport(int fd);
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
|
||||
void uv__make_close_pending(uv_handle_t* handle);
|
||||
int uv__getiovmax(void);
|
||||
@@ -289,6 +294,9 @@ 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);
|
||||
|
||||
/* tty */
|
||||
void uv__tty_close(uv_tty_t* handle);
|
||||
|
||||
/* pipe */
|
||||
int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
|
||||
@@ -334,6 +342,7 @@ int uv__random_sysctl(void* buf, size_t buflen);
|
||||
/* io_uring */
|
||||
#ifdef __linux__
|
||||
int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uint32_t fsync_flags);
|
||||
@@ -352,6 +361,7 @@ int uv__iou_fs_symlink(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_unlink(uv_loop_t* loop, uv_fs_t* req);
|
||||
#else
|
||||
#define uv__iou_fs_close(loop, req) 0
|
||||
#define uv__iou_fs_ftruncate(loop, req) 0
|
||||
#define uv__iou_fs_fsync_or_fdatasync(loop, req, fsync_flags) 0
|
||||
#define uv__iou_fs_link(loop, req) 0
|
||||
#define uv__iou_fs_mkdir(loop, req) 0
|
||||
@@ -474,4 +484,26 @@ uv__fs_copy_file_range(int fd_in,
|
||||
#define UV__CPU_AFFINITY_SUPPORTED 0
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
typedef struct {
|
||||
long long quota_per_period;
|
||||
long long period_length;
|
||||
double proportions;
|
||||
} uv__cpu_constraint;
|
||||
|
||||
int uv__get_constrained_cpu(uv__cpu_constraint* constraint);
|
||||
#endif
|
||||
|
||||
#if defined(__sun) && !defined(__illumos__)
|
||||
#ifdef SO_FLOW_NAME
|
||||
/* Since it's impossible to detect the Solaris 11.4 version via OS macros,
|
||||
* so we check the presence of the socket option SO_FLOW_NAME that was first
|
||||
* introduced to Solaris 11.4 and define a custom macro for determining 11.4.
|
||||
*/
|
||||
#define UV__SOLARIS_11_4 (1)
|
||||
#else
|
||||
#define UV__SOLARIS_11_4 (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* UV_UNIX_INTERNAL_H_ */
|
||||
|
||||
@@ -101,6 +101,39 @@ int uv__io_fork(uv_loop_t* loop) {
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct kevent ev;
|
||||
int rc;
|
||||
struct stat sb;
|
||||
#ifdef __APPLE__
|
||||
char path[MAXPATHLEN];
|
||||
#endif
|
||||
|
||||
if (uv__fstat(fd, &sb))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* On FreeBSD, kqueue only supports EVFILT_READ notification for regular files
|
||||
* and always reports ready events for writing, resulting in busy-looping.
|
||||
*
|
||||
* On Darwin, DragonFlyBSD, NetBSD and OpenBSD, kqueue reports ready events for
|
||||
* regular files as readable and writable only once, acting like an EV_ONESHOT.
|
||||
*
|
||||
* Neither of the above cases should be added to the kqueue.
|
||||
*/
|
||||
if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
|
||||
return UV_EINVAL;
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* On Darwin (both macOS and iOS), in addition to regular files, FIFOs also don't
|
||||
* work properly with kqueue: the disconnection from the last writer won't trigger
|
||||
* an event for kqueue in spite of what the man pages say. Thus, we also disallow
|
||||
* the case of S_IFIFO. */
|
||||
if (S_ISFIFO(sb.st_mode)) {
|
||||
/* File descriptors of FIFO, pipe and kqueue share the same type of file,
|
||||
* therefore there is no way to tell them apart via stat.st_mode&S_IFMT.
|
||||
* Fortunately, FIFO is the only one that has a persisted file on filesystem,
|
||||
* from which we're able to make the distinction for it. */
|
||||
if (!fcntl(fd, F_GETPATH, path))
|
||||
return UV_EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = 0;
|
||||
EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
|
||||
enum {
|
||||
UV__IORING_SETUP_SQPOLL = 2u,
|
||||
UV__IORING_SETUP_NO_SQARRAY = 0x10000u,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -148,6 +149,7 @@ enum {
|
||||
UV__IORING_OP_MKDIRAT = 37,
|
||||
UV__IORING_OP_SYMLINKAT = 38,
|
||||
UV__IORING_OP_LINKAT = 39,
|
||||
UV__IORING_OP_FTRUNCATE = 55,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -160,10 +162,6 @@ enum {
|
||||
UV__IORING_SQ_CQ_OVERFLOW = 2u,
|
||||
};
|
||||
|
||||
enum {
|
||||
UV__MKDIRAT_SYMLINKAT_LINKAT = 1u,
|
||||
};
|
||||
|
||||
struct uv__io_cqring_offsets {
|
||||
uint32_t head;
|
||||
uint32_t tail;
|
||||
@@ -510,10 +508,13 @@ static void uv__iou_init(int epollfd,
|
||||
size_t sqlen;
|
||||
size_t maxlen;
|
||||
size_t sqelen;
|
||||
unsigned kernel_version;
|
||||
uint32_t* sqarray;
|
||||
uint32_t i;
|
||||
char* sq;
|
||||
char* sqe;
|
||||
int ringfd;
|
||||
int no_sqarray;
|
||||
|
||||
sq = (char*)MAP_FAILED;
|
||||
sqe = (char*)MAP_FAILED;
|
||||
@@ -521,11 +522,15 @@ static void uv__iou_init(int epollfd,
|
||||
if (!uv__use_io_uring())
|
||||
return;
|
||||
|
||||
kernel_version = uv__kernel_version();
|
||||
no_sqarray =
|
||||
UV__IORING_SETUP_NO_SQARRAY * (kernel_version >= /* 6.6 */0x060600);
|
||||
|
||||
/* SQPOLL required CAP_SYS_NICE until linux v5.12 relaxed that requirement.
|
||||
* Mostly academic because we check for a v5.13 kernel afterwards anyway.
|
||||
*/
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.flags = flags;
|
||||
params.flags = flags | no_sqarray;
|
||||
|
||||
if (flags & UV__IORING_SETUP_SQPOLL)
|
||||
params.sq_thread_idle = 10; /* milliseconds */
|
||||
@@ -587,7 +592,6 @@ static void uv__iou_init(int epollfd,
|
||||
iou->sqhead = (uint32_t*) (sq + params.sq_off.head);
|
||||
iou->sqtail = (uint32_t*) (sq + params.sq_off.tail);
|
||||
iou->sqmask = *(uint32_t*) (sq + params.sq_off.ring_mask);
|
||||
iou->sqarray = (uint32_t*) (sq + params.sq_off.array);
|
||||
iou->sqflags = (uint32_t*) (sq + params.sq_off.flags);
|
||||
iou->cqhead = (uint32_t*) (sq + params.cq_off.head);
|
||||
iou->cqtail = (uint32_t*) (sq + params.cq_off.tail);
|
||||
@@ -601,13 +605,13 @@ static void uv__iou_init(int epollfd,
|
||||
iou->sqelen = sqelen;
|
||||
iou->ringfd = ringfd;
|
||||
iou->in_flight = 0;
|
||||
iou->flags = 0;
|
||||
|
||||
if (uv__kernel_version() >= /* 5.15.0 */ 0x050F00)
|
||||
iou->flags |= UV__MKDIRAT_SYMLINKAT_LINKAT;
|
||||
if (no_sqarray)
|
||||
return;
|
||||
|
||||
sqarray = (uint32_t*) (sq + params.sq_off.array);
|
||||
for (i = 0; i <= iou->sqmask; i++)
|
||||
iou->sqarray[i] = i; /* Slot -> sqe identity mapping. */
|
||||
sqarray[i] = i; /* Slot -> sqe identity mapping. */
|
||||
|
||||
return;
|
||||
|
||||
@@ -623,7 +627,7 @@ fail:
|
||||
|
||||
|
||||
static void uv__iou_delete(struct uv__iou* iou) {
|
||||
if (iou->ringfd != -1) {
|
||||
if (iou->ringfd > -1) {
|
||||
munmap(iou->sq, iou->maxlen);
|
||||
munmap(iou->sqe, iou->sqelen);
|
||||
uv__close(iou->ringfd);
|
||||
@@ -637,7 +641,7 @@ int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
|
||||
lfields = uv__get_internal_fields(loop);
|
||||
lfields->ctl.ringfd = -1;
|
||||
lfields->iou.ringfd = -1;
|
||||
lfields->iou.ringfd = -2; /* "uninitialized" */
|
||||
|
||||
loop->inotify_watchers = NULL;
|
||||
loop->inotify_fd = -1;
|
||||
@@ -646,7 +650,6 @@ int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
if (loop->backend_fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
uv__iou_init(loop->backend_fd, &lfields->iou, 64, UV__IORING_SETUP_SQPOLL);
|
||||
uv__iou_init(loop->backend_fd, &lfields->ctl, 256, 0);
|
||||
|
||||
return 0;
|
||||
@@ -714,23 +717,17 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
* This avoids a problem where the same file description remains open
|
||||
* in another process, causing repeated junk epoll events.
|
||||
*
|
||||
* Perform EPOLL_CTL_DEL immediately instead of going through
|
||||
* io_uring's submit queue, otherwise the file descriptor may
|
||||
* be closed by the time the kernel starts the operation.
|
||||
*
|
||||
* We pass in a dummy epoll_event, to work around a bug in old kernels.
|
||||
*
|
||||
* 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));
|
||||
|
||||
if (inv == NULL) {
|
||||
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
|
||||
} else {
|
||||
uv__epoll_ctl_prep(loop->backend_fd,
|
||||
&lfields->ctl,
|
||||
inv->prep,
|
||||
EPOLL_CTL_DEL,
|
||||
fd,
|
||||
&dummy);
|
||||
}
|
||||
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
|
||||
}
|
||||
|
||||
|
||||
@@ -765,6 +762,23 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
|
||||
uint32_t mask;
|
||||
uint32_t slot;
|
||||
|
||||
/* Lazily create the ring. State machine: -2 means uninitialized, -1 means
|
||||
* initialization failed. Anything else is a valid ring file descriptor.
|
||||
*/
|
||||
if (iou->ringfd == -2) {
|
||||
/* By default, the SQPOLL is not created. Enable only if the loop is
|
||||
* configured with UV_LOOP_USE_IO_URING_SQPOLL.
|
||||
*/
|
||||
if ((loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) == 0) {
|
||||
iou->ringfd = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL);
|
||||
if (iou->ringfd == -2)
|
||||
iou->ringfd = -1; /* "failed" */
|
||||
}
|
||||
|
||||
if (iou->ringfd == -1)
|
||||
return NULL;
|
||||
|
||||
@@ -788,7 +802,7 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
|
||||
req->work_req.done = NULL;
|
||||
uv__queue_init(&req->work_req.wq);
|
||||
|
||||
uv__req_register(loop, req);
|
||||
uv__req_register(loop);
|
||||
iou->in_flight++;
|
||||
|
||||
return sqe;
|
||||
@@ -851,6 +865,26 @@ int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
int uv__iou_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req) {
|
||||
struct uv__io_uring_sqe* sqe;
|
||||
struct uv__iou* iou;
|
||||
|
||||
if (uv__kernel_version() < /* 6.9 */0x060900)
|
||||
return 0;
|
||||
|
||||
iou = &uv__get_internal_fields(loop)->iou;
|
||||
sqe = uv__iou_get_sqe(iou, loop, req);
|
||||
if (sqe == NULL)
|
||||
return 0;
|
||||
|
||||
sqe->fd = req->file;
|
||||
sqe->len = req->off;
|
||||
sqe->opcode = UV__IORING_OP_FTRUNCATE;
|
||||
uv__iou_submit(iou);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uint32_t fsync_flags) {
|
||||
@@ -880,11 +914,10 @@ int uv__iou_fs_link(uv_loop_t* loop, uv_fs_t* req) {
|
||||
struct uv__io_uring_sqe* sqe;
|
||||
struct uv__iou* iou;
|
||||
|
||||
iou = &uv__get_internal_fields(loop)->iou;
|
||||
|
||||
if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT))
|
||||
if (uv__kernel_version() < /* 5.15.0 */0x050F00)
|
||||
return 0;
|
||||
|
||||
iou = &uv__get_internal_fields(loop)->iou;
|
||||
sqe = uv__iou_get_sqe(iou, loop, req);
|
||||
if (sqe == NULL)
|
||||
return 0;
|
||||
@@ -905,11 +938,10 @@ int uv__iou_fs_mkdir(uv_loop_t* loop, uv_fs_t* req) {
|
||||
struct uv__io_uring_sqe* sqe;
|
||||
struct uv__iou* iou;
|
||||
|
||||
iou = &uv__get_internal_fields(loop)->iou;
|
||||
|
||||
if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT))
|
||||
if (uv__kernel_version() < /* 5.15.0 */0x050F00)
|
||||
return 0;
|
||||
|
||||
iou = &uv__get_internal_fields(loop)->iou;
|
||||
sqe = uv__iou_get_sqe(iou, loop, req);
|
||||
if (sqe == NULL)
|
||||
return 0;
|
||||
@@ -973,11 +1005,10 @@ int uv__iou_fs_symlink(uv_loop_t* loop, uv_fs_t* req) {
|
||||
struct uv__io_uring_sqe* sqe;
|
||||
struct uv__iou* iou;
|
||||
|
||||
iou = &uv__get_internal_fields(loop)->iou;
|
||||
|
||||
if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT))
|
||||
if (uv__kernel_version() < /* 5.15.0 */0x050F00)
|
||||
return 0;
|
||||
|
||||
iou = &uv__get_internal_fields(loop)->iou;
|
||||
sqe = uv__iou_get_sqe(iou, loop, req);
|
||||
if (sqe == NULL)
|
||||
return 0;
|
||||
@@ -1156,7 +1187,7 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
|
||||
req = (uv_fs_t*) (uintptr_t) e->user_data;
|
||||
assert(req->type == UV_FS);
|
||||
|
||||
uv__req_unregister(loop, req);
|
||||
uv__req_unregister(loop);
|
||||
iou->in_flight--;
|
||||
|
||||
/* If the op is not supported by the kernel retry using the thread pool */
|
||||
@@ -1208,6 +1239,10 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
|
||||
}
|
||||
|
||||
|
||||
/* Only for EPOLL_CTL_ADD and EPOLL_CTL_MOD. EPOLL_CTL_DEL should always be
|
||||
* executed immediately, otherwise the file descriptor may have been closed
|
||||
* by the time the kernel starts the operation.
|
||||
*/
|
||||
static void uv__epoll_ctl_prep(int epollfd,
|
||||
struct uv__iou* ctl,
|
||||
struct epoll_event (*events)[256],
|
||||
@@ -1219,45 +1254,28 @@ static void uv__epoll_ctl_prep(int epollfd,
|
||||
uint32_t mask;
|
||||
uint32_t slot;
|
||||
|
||||
if (ctl->ringfd == -1) {
|
||||
if (!epoll_ctl(epollfd, op, fd, e))
|
||||
return;
|
||||
assert(op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD);
|
||||
assert(ctl->ringfd != -1);
|
||||
|
||||
if (op == EPOLL_CTL_DEL)
|
||||
return; /* Ignore errors, may be racing with another thread. */
|
||||
mask = ctl->sqmask;
|
||||
slot = (*ctl->sqtail)++ & mask;
|
||||
|
||||
if (op != EPOLL_CTL_ADD)
|
||||
abort();
|
||||
pe = &(*events)[slot];
|
||||
*pe = *e;
|
||||
|
||||
if (errno != EEXIST)
|
||||
abort();
|
||||
sqe = (uv__io_uring_sqe*)ctl->sqe;
|
||||
sqe = &sqe[slot];
|
||||
|
||||
/* File descriptor that's been watched before, update event mask. */
|
||||
if (!epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, e))
|
||||
return;
|
||||
memset(sqe, 0, sizeof(*sqe));
|
||||
sqe->addr = (uintptr_t) pe;
|
||||
sqe->fd = epollfd;
|
||||
sqe->len = op;
|
||||
sqe->off = fd;
|
||||
sqe->opcode = UV__IORING_OP_EPOLL_CTL;
|
||||
sqe->user_data = op | slot << 2 | (int64_t) fd << 32;
|
||||
|
||||
abort();
|
||||
} else {
|
||||
mask = ctl->sqmask;
|
||||
slot = (*ctl->sqtail)++ & mask;
|
||||
|
||||
pe = &(*events)[slot];
|
||||
*pe = *e;
|
||||
|
||||
sqe = (uv__io_uring_sqe*)ctl->sqe;
|
||||
sqe = &sqe[slot];
|
||||
|
||||
memset(sqe, 0, sizeof(*sqe));
|
||||
sqe->addr = (uintptr_t) pe;
|
||||
sqe->fd = epollfd;
|
||||
sqe->len = op;
|
||||
sqe->off = fd;
|
||||
sqe->opcode = UV__IORING_OP_EPOLL_CTL;
|
||||
sqe->user_data = op | slot << 2 | (int64_t) fd << 32;
|
||||
|
||||
if ((*ctl->sqhead & mask) == (*ctl->sqtail & mask))
|
||||
uv__epoll_ctl_flush(epollfd, ctl, events);
|
||||
}
|
||||
if ((*ctl->sqhead & mask) == (*ctl->sqtail & mask))
|
||||
uv__epoll_ctl_flush(epollfd, ctl, events);
|
||||
}
|
||||
|
||||
|
||||
@@ -1398,8 +1416,22 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
w->events = w->pevents;
|
||||
e.events = w->pevents;
|
||||
e.data.fd = w->fd;
|
||||
fd = w->fd;
|
||||
|
||||
uv__epoll_ctl_prep(epollfd, ctl, &prep, op, w->fd, &e);
|
||||
if (ctl->ringfd != -1) {
|
||||
uv__epoll_ctl_prep(epollfd, ctl, &prep, op, fd, &e);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!epoll_ctl(epollfd, op, fd, &e))
|
||||
continue;
|
||||
|
||||
assert(op == EPOLL_CTL_ADD);
|
||||
assert(errno == EEXIST);
|
||||
|
||||
/* File descriptor that's been watched before, update event mask. */
|
||||
if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &e))
|
||||
abort();
|
||||
}
|
||||
|
||||
inv.events = events;
|
||||
@@ -1487,8 +1519,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
*
|
||||
* Ignore all errors because we may be racing with another thread
|
||||
* when the file descriptor is closed.
|
||||
*
|
||||
* Perform EPOLL_CTL_DEL immediately instead of going through
|
||||
* io_uring's submit queue, otherwise the file descriptor may
|
||||
* be closed by the time the kernel starts the operation.
|
||||
*/
|
||||
uv__epoll_ctl_prep(epollfd, ctl, &prep, EPOLL_CTL_DEL, fd, pe);
|
||||
epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, pe);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1623,36 +1659,17 @@ done:
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
char buf[1024];
|
||||
const char* s;
|
||||
ssize_t n;
|
||||
long val;
|
||||
int fd;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
do
|
||||
fd = open("/proc/self/stat", O_RDONLY);
|
||||
while (fd == -1 && errno == EINTR);
|
||||
/* rss: 24th element */
|
||||
rc = uv__slurp("/proc/self/stat", buf, sizeof(buf));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
do
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
while (n == -1 && errno == EINTR);
|
||||
|
||||
uv__close(fd);
|
||||
if (n == -1)
|
||||
return UV__ERR(errno);
|
||||
buf[n] = '\0';
|
||||
|
||||
s = strchr(buf, ' ');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
|
||||
s += 1;
|
||||
if (*s != '(')
|
||||
goto err;
|
||||
|
||||
s = strchr(s, ')');
|
||||
/* find the last ')' */
|
||||
s = strrchr(buf, ')');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
|
||||
@@ -1664,9 +1681,7 @@ int uv_resident_set_memory(size_t* rss) {
|
||||
|
||||
errno = 0;
|
||||
val = strtol(s, NULL, 10);
|
||||
if (errno != 0)
|
||||
goto err;
|
||||
if (val < 0)
|
||||
if (val < 0 || errno != 0)
|
||||
goto err;
|
||||
|
||||
*rss = val * getpagesize();
|
||||
@@ -2271,6 +2286,136 @@ uint64_t uv_get_available_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
static int uv__get_cgroupv2_constrained_cpu(const char* cgroup,
|
||||
uv__cpu_constraint* constraint) {
|
||||
char path[256];
|
||||
char buf[1024];
|
||||
unsigned int weight;
|
||||
int cgroup_size;
|
||||
const char* cgroup_trimmed;
|
||||
char quota_buf[16];
|
||||
|
||||
if (strncmp(cgroup, "0::/", 4) != 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Trim ending \n by replacing it with a 0 */
|
||||
cgroup_trimmed = cgroup + sizeof("0::/") - 1; /* Skip the prefix "0::/" */
|
||||
cgroup_size = (int)strcspn(cgroup_trimmed, "\n"); /* Find the first slash */
|
||||
|
||||
/* Construct the path to the cpu.max file */
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.max", cgroup_size,
|
||||
cgroup_trimmed);
|
||||
|
||||
/* Read cpu.max */
|
||||
if (uv__slurp(path, buf, sizeof(buf)) < 0)
|
||||
return UV_EIO;
|
||||
|
||||
if (sscanf(buf, "%15s %lld", quota_buf, &constraint->period_length) != 2)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (strncmp(quota_buf, "max", 3) == 0)
|
||||
constraint->quota_per_period = LLONG_MAX;
|
||||
else if (sscanf(quota_buf, "%lld", &constraint->quota_per_period) != 1)
|
||||
return UV_EINVAL; // conversion failed
|
||||
|
||||
/* Construct the path to the cpu.weight file */
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.weight", cgroup_size,
|
||||
cgroup_trimmed);
|
||||
|
||||
/* Read cpu.weight */
|
||||
if (uv__slurp(path, buf, sizeof(buf)) < 0)
|
||||
return UV_EIO;
|
||||
|
||||
if (sscanf(buf, "%u", &weight) != 1)
|
||||
return UV_EINVAL;
|
||||
|
||||
constraint->proportions = (double)weight / 100.0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char* uv__cgroup1_find_cpu_controller(const char* cgroup,
|
||||
int* cgroup_size) {
|
||||
/* Seek to the cpu controller line. */
|
||||
char* cgroup_cpu = (char*)strstr(cgroup, ":cpu,");
|
||||
|
||||
if (cgroup_cpu != NULL) {
|
||||
/* Skip the controller prefix to the start of the cgroup path. */
|
||||
cgroup_cpu += sizeof(":cpu,") - 1;
|
||||
/* Determine the length of the cgroup path, excluding the newline. */
|
||||
*cgroup_size = (int)strcspn(cgroup_cpu, "\n");
|
||||
}
|
||||
|
||||
return cgroup_cpu;
|
||||
}
|
||||
|
||||
static int uv__get_cgroupv1_constrained_cpu(const char* cgroup,
|
||||
uv__cpu_constraint* constraint) {
|
||||
char path[256];
|
||||
char buf[1024];
|
||||
unsigned int shares;
|
||||
int cgroup_size;
|
||||
char* cgroup_cpu;
|
||||
|
||||
cgroup_cpu = uv__cgroup1_find_cpu_controller(cgroup, &cgroup_size);
|
||||
|
||||
if (cgroup_cpu == NULL)
|
||||
return UV_EIO;
|
||||
|
||||
/* Construct the path to the cpu.cfs_quota_us file */
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.cfs_quota_us",
|
||||
cgroup_size, cgroup_cpu);
|
||||
|
||||
if (uv__slurp(path, buf, sizeof(buf)) < 0)
|
||||
return UV_EIO;
|
||||
|
||||
if (sscanf(buf, "%lld", &constraint->quota_per_period) != 1)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Construct the path to the cpu.cfs_period_us file */
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.cfs_period_us",
|
||||
cgroup_size, cgroup_cpu);
|
||||
|
||||
/* Read cpu.cfs_period_us */
|
||||
if (uv__slurp(path, buf, sizeof(buf)) < 0)
|
||||
return UV_EIO;
|
||||
|
||||
if (sscanf(buf, "%lld", &constraint->period_length) != 1)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Construct the path to the cpu.shares file */
|
||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.shares", cgroup_size,
|
||||
cgroup_cpu);
|
||||
|
||||
/* Read cpu.shares */
|
||||
if (uv__slurp(path, buf, sizeof(buf)) < 0)
|
||||
return UV_EIO;
|
||||
|
||||
if (sscanf(buf, "%u", &shares) != 1)
|
||||
return UV_EINVAL;
|
||||
|
||||
constraint->proportions = (double)shares / 1024.0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv__get_constrained_cpu(uv__cpu_constraint* constraint) {
|
||||
char cgroup[1024];
|
||||
|
||||
/* Read the cgroup from /proc/self/cgroup */
|
||||
if (uv__slurp("/proc/self/cgroup", cgroup, sizeof(cgroup)) < 0)
|
||||
return UV_EIO;
|
||||
|
||||
/* Check if the system is using cgroup v2 by examining /proc/self/cgroup
|
||||
* The entry for cgroup v2 is always in the format "0::$PATH"
|
||||
* see https://docs.kernel.org/admin-guide/cgroup-v2.html */
|
||||
if (strncmp(cgroup, "0::/", 4) == 0)
|
||||
return uv__get_cgroupv2_constrained_cpu(cgroup, constraint);
|
||||
else
|
||||
return uv__get_cgroupv1_constrained_cpu(cgroup, constraint);
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct sysinfo info;
|
||||
char buf[128]; /* Large enough to hold all of /proc/loadavg. */
|
||||
|
||||
@@ -217,6 +217,14 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (option == UV_LOOP_USE_IO_URING_SQPOLL) {
|
||||
loop->flags |= UV_LOOP_ENABLE_IO_URING_SQPOLL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (option != UV_LOOP_BLOCK_SIGNAL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
|
||||
@@ -76,8 +76,13 @@ int uv_pipe_bind2(uv_pipe_t* handle,
|
||||
if (name == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* namelen==0 on Linux means autobind the listen socket in the abstract
|
||||
* socket namespace, see `man 7 unix` for details.
|
||||
*/
|
||||
#if !defined(__linux__)
|
||||
if (namelen == 0)
|
||||
return UV_EINVAL;
|
||||
#endif
|
||||
|
||||
if (includes_nul(name, namelen))
|
||||
return UV_EINVAL;
|
||||
@@ -344,8 +349,15 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
uv__peersockfunc func,
|
||||
char* buffer,
|
||||
size_t* size) {
|
||||
#if defined(__linux__)
|
||||
static const int is_linux = 1;
|
||||
#else
|
||||
static const int is_linux = 0;
|
||||
#endif
|
||||
struct sockaddr_un sa;
|
||||
socklen_t addrlen;
|
||||
size_t slop;
|
||||
char* p;
|
||||
int err;
|
||||
|
||||
addrlen = sizeof(sa);
|
||||
@@ -359,17 +371,20 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (sa.sun_path[0] == 0)
|
||||
/* Linux abstract namespace */
|
||||
slop = 1;
|
||||
if (is_linux && sa.sun_path[0] == '\0') {
|
||||
/* Linux abstract namespace. Not zero-terminated. */
|
||||
slop = 0;
|
||||
addrlen -= offsetof(struct sockaddr_un, sun_path);
|
||||
else
|
||||
#endif
|
||||
addrlen = strlen(sa.sun_path);
|
||||
} else {
|
||||
p = (char*)memchr(sa.sun_path, '\0', sizeof(sa.sun_path));
|
||||
if (p == NULL)
|
||||
p = ARRAY_END(sa.sun_path);
|
||||
addrlen = p - sa.sun_path;
|
||||
}
|
||||
|
||||
|
||||
if ((size_t)addrlen >= *size) {
|
||||
*size = addrlen + 1;
|
||||
if ((size_t)addrlen + slop > *size) {
|
||||
*size = addrlen + slop;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
@@ -487,7 +502,11 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||
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__)
|
||||
#if defined(__linux__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__NetBSD__)
|
||||
int flags = O_CLOEXEC;
|
||||
|
||||
if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE))
|
||||
|
||||
@@ -55,7 +55,8 @@
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) || \
|
||||
defined(__GNU__)
|
||||
# include <grp.h>
|
||||
#endif
|
||||
|
||||
@@ -63,11 +64,7 @@ extern char **environ;
|
||||
# include "zos-base.h"
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
#ifdef UV_HAVE_KQUEUE
|
||||
#include <sys/event.h>
|
||||
#else
|
||||
#define UV_USE_SIGCHLD
|
||||
|
||||
@@ -195,7 +195,7 @@ static void uv__signal_handler(int signum) {
|
||||
|
||||
for (handle = uv__signal_first_handle(signum);
|
||||
handle != NULL && handle->signum == signum;
|
||||
handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
|
||||
handle = RB_NEXT(uv__signal_tree_s, handle)) {
|
||||
int r;
|
||||
|
||||
msg.signum = signum;
|
||||
|
||||
@@ -457,7 +457,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
|
||||
assert(stream->flags & UV_HANDLE_CLOSED);
|
||||
|
||||
if (stream->connect_req) {
|
||||
uv__req_unregister(stream->loop, stream->connect_req);
|
||||
uv__req_unregister(stream->loop);
|
||||
stream->connect_req->cb(stream->connect_req, UV_ECANCELED);
|
||||
stream->connect_req = NULL;
|
||||
}
|
||||
@@ -642,7 +642,7 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
if ((stream->flags & UV_HANDLE_CLOSING) ||
|
||||
!(stream->flags & UV_HANDLE_SHUT)) {
|
||||
stream->shutdown_req = NULL;
|
||||
uv__req_unregister(stream->loop, req);
|
||||
uv__req_unregister(stream->loop);
|
||||
|
||||
err = 0;
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
@@ -698,7 +698,8 @@ static int uv__write_req_update(uv_stream_t* stream,
|
||||
|
||||
do {
|
||||
len = n < buf->len ? n : buf->len;
|
||||
buf->base += len;
|
||||
if (buf->len != 0)
|
||||
buf->base += len;
|
||||
buf->len -= len;
|
||||
buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */
|
||||
n -= len;
|
||||
@@ -912,7 +913,7 @@ static void uv__write_callbacks(uv_stream_t* stream) {
|
||||
q = uv__queue_head(&pq);
|
||||
req = uv__queue_data(q, uv_write_t, queue);
|
||||
uv__queue_remove(q);
|
||||
uv__req_unregister(stream->loop, req);
|
||||
uv__req_unregister(stream->loop);
|
||||
|
||||
if (req->bufs != NULL) {
|
||||
stream->write_queue_size -= uv__write_req_size(req);
|
||||
@@ -980,11 +981,13 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
|
||||
|
||||
static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
|
||||
struct cmsghdr* cmsg;
|
||||
char* p;
|
||||
char* pe;
|
||||
int fd;
|
||||
int err;
|
||||
size_t i;
|
||||
size_t count;
|
||||
|
||||
err = 0;
|
||||
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
|
||||
@@ -997,24 +1000,26 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
|
||||
assert(count % sizeof(fd) == 0);
|
||||
count /= sizeof(fd);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
memcpy(&fd, (char*) CMSG_DATA(cmsg) + i * sizeof(fd), sizeof(fd));
|
||||
/* Already has accepted fd, queue now */
|
||||
if (stream->accepted_fd != -1) {
|
||||
err = uv__stream_queue_fd(stream, fd);
|
||||
if (err != 0) {
|
||||
/* Close rest */
|
||||
for (; i < count; i++)
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
stream->accepted_fd = fd;
|
||||
p = (char*) CMSG_DATA(cmsg);
|
||||
pe = p + count * sizeof(fd);
|
||||
|
||||
while (p < pe) {
|
||||
memcpy(&fd, p, sizeof(fd));
|
||||
p += sizeof(fd);
|
||||
|
||||
if (err == 0) {
|
||||
if (stream->accepted_fd == -1)
|
||||
stream->accepted_fd = fd;
|
||||
else
|
||||
err = uv__stream_queue_fd(stream, fd);
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
uv__close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -1269,7 +1274,7 @@ static void uv__stream_connect(uv_stream_t* stream) {
|
||||
return;
|
||||
|
||||
stream->connect_req = NULL;
|
||||
uv__req_unregister(stream->loop, req);
|
||||
uv__req_unregister(stream->loop);
|
||||
|
||||
if (error < 0 || uv__queue_empty(&stream->write_queue)) {
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
|
||||
@@ -167,6 +167,12 @@ int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (flags & UV_TCP_REUSEPORT) {
|
||||
err = uv__sock_reuseport(tcp->io_watcher.fd);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifndef __OpenBSD__
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
@@ -452,6 +458,14 @@ int uv__tcp_nodelay(int fd, int on) {
|
||||
}
|
||||
|
||||
|
||||
#if (defined(UV__SOLARIS_11_4) && !UV__SOLARIS_11_4) || \
|
||||
(defined(__DragonFly__) && __DragonFly_version < 500702)
|
||||
/* DragonFlyBSD <500702 and Solaris <11.4 require millisecond units
|
||||
* for TCP keepalive options. */
|
||||
#define UV_KEEPALIVE_FACTOR(x) (x *= 1000)
|
||||
#else
|
||||
#define UV_KEEPALIVE_FACTOR(x)
|
||||
#endif
|
||||
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
|
||||
int idle;
|
||||
int intvl;
|
||||
@@ -467,8 +481,8 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
|
||||
if (!on)
|
||||
return 0;
|
||||
|
||||
if (delay == 0)
|
||||
return -1;
|
||||
if (delay < 1)
|
||||
return UV_EINVAL;
|
||||
|
||||
#ifdef __sun
|
||||
/* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual
|
||||
@@ -501,49 +515,53 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
|
||||
if (idle > 10*24*60*60)
|
||||
idle = 10*24*60*60;
|
||||
|
||||
UV_KEEPALIVE_FACTOR(idle);
|
||||
|
||||
/* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris
|
||||
* until version 11.4, but let's take a chance here. */
|
||||
#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
intvl = idle/3;
|
||||
intvl = 10; /* required at least 10 seconds */
|
||||
UV_KEEPALIVE_FACTOR(intvl);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
cnt = 3;
|
||||
cnt = 1; /* 1 retry, ensure (TCP_KEEPINTVL * TCP_KEEPCNT) is 10 seconds */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
/* Fall back to the first implementation of tcp-alive mechanism for older Solaris,
|
||||
* simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`.
|
||||
*/
|
||||
idle *= 1000; /* kernel expects milliseconds */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Note that the consequent probes will not be sent at equal intervals on Solaris,
|
||||
* but will be sent using the exponential backoff algorithm. */
|
||||
intvl = idle/3;
|
||||
cnt = 3;
|
||||
int time_to_abort = intvl * cnt;
|
||||
int time_to_abort = 10; /* 10 seconds */
|
||||
UV_KEEPALIVE_FACTOR(time_to_abort);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort)))
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
|
||||
#else /* !defined(__sun) */
|
||||
|
||||
idle = delay;
|
||||
UV_KEEPALIVE_FACTOR(idle);
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
|
||||
return UV__ERR(errno);
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
/* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &idle, sizeof(idle)))
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
|
||||
#ifdef TCP_KEEPINTVL
|
||||
intvl = 1; /* 1 second; same as default on Win32 */
|
||||
intvl = 1; /* 1 second; same as default on Win32 */
|
||||
UV_KEEPALIVE_FACTOR(intvl);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
@@ -612,7 +630,7 @@ void uv__tcp_close(uv_tcp_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__)
|
||||
#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
|
||||
int flags;
|
||||
|
||||
flags = type | SOCK_CLOEXEC;
|
||||
|
||||
@@ -337,6 +337,37 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
}
|
||||
|
||||
|
||||
void uv__tty_close(uv_tty_t* handle) {
|
||||
int expected;
|
||||
int fd;
|
||||
|
||||
fd = handle->io_watcher.fd;
|
||||
if (fd == -1)
|
||||
goto done;
|
||||
|
||||
/* This is used for uv_tty_reset_mode() */
|
||||
do
|
||||
expected = 0;
|
||||
while (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1));
|
||||
|
||||
if (fd == orig_termios_fd) {
|
||||
/* XXX(bnoordhuis) the tcsetattr is probably wrong when there are still
|
||||
* other uv_tty_t handles active that refer to the same tty/pty but it's
|
||||
* hard to recognize that particular situation without maintaining some
|
||||
* kind of process-global data structure, and that still won't work in a
|
||||
* multi-process setup.
|
||||
*/
|
||||
uv__tcsetattr(fd, TCSANOW, &orig_termios);
|
||||
orig_termios_fd = -1;
|
||||
}
|
||||
|
||||
atomic_store(&termios_spinlock, 0);
|
||||
|
||||
done:
|
||||
uv__stream_close((uv_stream_t*) handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
||||
struct winsize ws;
|
||||
int err;
|
||||
@@ -454,7 +485,7 @@ int uv_tty_reset_mode(void) {
|
||||
saved_errno = errno;
|
||||
|
||||
if (atomic_exchange(&termios_spinlock, 1))
|
||||
return UV_EBUSY; /* In uv_tty_set_mode(). */
|
||||
return UV_EBUSY; /* In uv_tty_set_mode() or uv__tty_close(). */
|
||||
|
||||
err = 0;
|
||||
if (orig_termios_fd != -1)
|
||||
|
||||
@@ -100,7 +100,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
|
||||
uv__queue_remove(q);
|
||||
|
||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||
uv__req_unregister(handle->loop, req);
|
||||
uv__req_unregister(handle->loop);
|
||||
|
||||
handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
|
||||
handle->send_queue_count--;
|
||||
@@ -141,14 +141,14 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
|
||||
if (revents & POLLIN)
|
||||
uv__udp_recvmsg(handle);
|
||||
|
||||
if (revents & POLLOUT) {
|
||||
if (revents & POLLOUT && !uv__is_closing(handle)) {
|
||||
uv__udp_sendmsg(handle);
|
||||
uv__udp_run_completed(handle);
|
||||
}
|
||||
}
|
||||
|
||||
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||
struct sockaddr_in6 peers[20];
|
||||
struct iovec iov[ARRAY_SIZE(peers)];
|
||||
struct mmsghdr msgs[ARRAY_SIZE(peers)];
|
||||
@@ -173,11 +173,18 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
||||
msgs[k].msg_hdr.msg_control = NULL;
|
||||
msgs[k].msg_hdr.msg_controllen = 0;
|
||||
msgs[k].msg_hdr.msg_flags = 0;
|
||||
msgs[k].msg_len = 0;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
do
|
||||
nread = recvmsg_x(handle->io_watcher.fd, msgs, chunks, MSG_DONTWAIT);
|
||||
while (nread == -1 && errno == EINTR);
|
||||
#else
|
||||
do
|
||||
nread = recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL);
|
||||
while (nread == -1 && errno == EINTR);
|
||||
#endif
|
||||
|
||||
if (nread < 1) {
|
||||
if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
@@ -204,9 +211,9 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
||||
handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE);
|
||||
}
|
||||
return nread;
|
||||
#else /* __linux__ || ____FreeBSD__ */
|
||||
#else /* __linux__ || ____FreeBSD__ || __APPLE__ */
|
||||
return UV_ENOSYS;
|
||||
#endif /* __linux__ || ____FreeBSD__ */
|
||||
#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */
|
||||
}
|
||||
|
||||
static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
@@ -275,8 +282,61 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
&& handle->recv_cb != NULL);
|
||||
}
|
||||
|
||||
static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
static void uv__udp_sendmsg_one(uv_udp_t* handle, uv_udp_send_t* req) {
|
||||
struct uv__queue* q;
|
||||
struct msghdr h;
|
||||
ssize_t size;
|
||||
|
||||
for (;;) {
|
||||
memset(&h, 0, sizeof h);
|
||||
if (req->addr.ss_family == AF_UNSPEC) {
|
||||
h.msg_name = NULL;
|
||||
h.msg_namelen = 0;
|
||||
} else {
|
||||
h.msg_name = &req->addr;
|
||||
if (req->addr.ss_family == AF_INET6)
|
||||
h.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
else if (req->addr.ss_family == AF_INET)
|
||||
h.msg_namelen = sizeof(struct sockaddr_in);
|
||||
else if (req->addr.ss_family == AF_UNIX)
|
||||
h.msg_namelen = sizeof(struct sockaddr_un);
|
||||
else {
|
||||
assert(0 && "unsupported address family");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
h.msg_iov = (struct iovec*) req->bufs;
|
||||
h.msg_iovlen = req->nbufs;
|
||||
|
||||
do
|
||||
size = sendmsg(handle->io_watcher.fd, &h, 0);
|
||||
while (size == -1 && errno == EINTR);
|
||||
|
||||
if (size == -1)
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
return;
|
||||
|
||||
req->status = (size == -1 ? UV__ERR(errno) : size);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
uv__queue_remove(&req->queue);
|
||||
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
|
||||
if (uv__queue_empty(&handle->write_queue))
|
||||
return;
|
||||
|
||||
q = uv__queue_head(&handle->write_queue);
|
||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||
static void uv__udp_sendmsg_many(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
struct mmsghdr h[20];
|
||||
struct mmsghdr* p;
|
||||
@@ -285,16 +345,11 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
size_t pkts;
|
||||
size_t i;
|
||||
|
||||
if (uv__queue_empty(&handle->write_queue))
|
||||
return;
|
||||
|
||||
write_queue_drain:
|
||||
for (pkts = 0, q = uv__queue_head(&handle->write_queue);
|
||||
pkts < ARRAY_SIZE(h) && q != &handle->write_queue;
|
||||
++pkts, q = uv__queue_head(q)) {
|
||||
assert(q != NULL);
|
||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
p = &h[pkts];
|
||||
memset(p, 0, sizeof(*p));
|
||||
@@ -318,9 +373,15 @@ write_queue_drain:
|
||||
h[pkts].msg_hdr.msg_iovlen = req->nbufs;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
do
|
||||
npkts = sendmsg_x(handle->io_watcher.fd, h, pkts, MSG_DONTWAIT);
|
||||
while (npkts == -1 && errno == EINTR);
|
||||
#else
|
||||
do
|
||||
npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0);
|
||||
while (npkts == -1 && errno == EINTR);
|
||||
#endif
|
||||
|
||||
if (npkts < 1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
@@ -328,10 +389,7 @@ write_queue_drain:
|
||||
for (i = 0, q = uv__queue_head(&handle->write_queue);
|
||||
i < pkts && q != &handle->write_queue;
|
||||
++i, q = uv__queue_head(&handle->write_queue)) {
|
||||
assert(q != NULL);
|
||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
req->status = UV__ERR(errno);
|
||||
uv__queue_remove(&req->queue);
|
||||
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
||||
@@ -346,10 +404,7 @@ write_queue_drain:
|
||||
for (i = 0, q = uv__queue_head(&handle->write_queue);
|
||||
i < (size_t)npkts && q != &handle->write_queue;
|
||||
++i, q = uv__queue_head(&handle->write_queue)) {
|
||||
assert(q != NULL);
|
||||
req = uv__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
|
||||
@@ -364,75 +419,48 @@ write_queue_drain:
|
||||
/* couldn't batch everything, continue sending (jump to avoid stack growth) */
|
||||
if (!uv__queue_empty(&handle->write_queue))
|
||||
goto write_queue_drain;
|
||||
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
#else /* __linux__ || ____FreeBSD__ */
|
||||
uv_udp_send_t* req;
|
||||
struct msghdr h;
|
||||
}
|
||||
#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */
|
||||
|
||||
static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
struct uv__queue* q;
|
||||
ssize_t size;
|
||||
uv_udp_send_t* req;
|
||||
|
||||
while (!uv__queue_empty(&handle->write_queue)) {
|
||||
q = uv__queue_head(&handle->write_queue);
|
||||
assert(q != NULL);
|
||||
if (uv__queue_empty(&handle->write_queue))
|
||||
return;
|
||||
|
||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
q = uv__queue_head(&handle->write_queue);
|
||||
req = uv__queue_data(q, uv_udp_send_t, queue);
|
||||
|
||||
memset(&h, 0, sizeof h);
|
||||
if (req->addr.ss_family == AF_UNSPEC) {
|
||||
h.msg_name = NULL;
|
||||
h.msg_namelen = 0;
|
||||
} else {
|
||||
h.msg_name = &req->addr;
|
||||
if (req->addr.ss_family == AF_INET6)
|
||||
h.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
else if (req->addr.ss_family == AF_INET)
|
||||
h.msg_namelen = sizeof(struct sockaddr_in);
|
||||
else if (req->addr.ss_family == AF_UNIX)
|
||||
h.msg_namelen = sizeof(struct sockaddr_un);
|
||||
else {
|
||||
assert(0 && "unsupported address family");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
h.msg_iov = (struct iovec*) req->bufs;
|
||||
h.msg_iovlen = req->nbufs;
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||
/* Use sendmmsg() if this send request contains more than one datagram OR
|
||||
* there is more than one send request (because that automatically implies
|
||||
* there is more than one datagram.)
|
||||
*/
|
||||
if (req->nbufs != 1 || &handle->write_queue != uv__queue_next(&req->queue))
|
||||
return uv__udp_sendmsg_many(handle);
|
||||
#endif
|
||||
|
||||
do {
|
||||
size = sendmsg(handle->io_watcher.fd, &h, 0);
|
||||
} while (size == -1 && errno == EINTR);
|
||||
|
||||
if (size == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
break;
|
||||
}
|
||||
|
||||
req->status = (size == -1 ? UV__ERR(errno) : size);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
uv__queue_remove(&req->queue);
|
||||
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
}
|
||||
#endif /* __linux__ || ____FreeBSD__ */
|
||||
return uv__udp_sendmsg_one(handle, req);
|
||||
}
|
||||
|
||||
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
|
||||
* refinements for programs that use multicast.
|
||||
* refinements for programs that use multicast. Therefore we preferentially
|
||||
* set SO_REUSEPORT over SO_REUSEADDR here, but we set SO_REUSEPORT only
|
||||
* when that socket option doesn't have the capability of load balancing.
|
||||
* Otherwise, we fall back to SO_REUSEADDR.
|
||||
*
|
||||
* Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
|
||||
* are different from the BSDs: it _shares_ the port rather than steal it
|
||||
* from the current listener. While useful, it's not something we can emulate
|
||||
* on other platforms so we don't enable it.
|
||||
* Linux as of 3.9, DragonflyBSD 3.6, AIX 7.2.5 have the SO_REUSEPORT socket
|
||||
* option but with semantics that are different from the BSDs: it _shares_
|
||||
* the port rather than steals it from the current listener. While useful,
|
||||
* it's not something we can emulate on other platforms so we don't enable it.
|
||||
*
|
||||
* zOS does not support getsockname with SO_REUSEPORT option when using
|
||||
* AF_UNIX.
|
||||
*/
|
||||
static int uv__set_reuse(int fd) {
|
||||
static int uv__sock_reuseaddr(int fd) {
|
||||
int yes;
|
||||
yes = 1;
|
||||
|
||||
@@ -449,7 +477,7 @@ static int uv__set_reuse(int fd) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \
|
||||
!defined(__sun__)
|
||||
!defined(__sun__) && !defined(__DragonFly__) && !defined(_AIX73)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
@@ -492,7 +520,8 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
int fd;
|
||||
|
||||
/* Check for bad flags. */
|
||||
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | UV_UDP_LINUX_RECVERR))
|
||||
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR |
|
||||
UV_UDP_REUSEPORT | UV_UDP_LINUX_RECVERR))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Cannot set IPv6-only mode on non-IPv6 socket. */
|
||||
@@ -515,7 +544,13 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
if (flags & UV_UDP_REUSEADDR) {
|
||||
err = uv__set_reuse(fd);
|
||||
err = uv__sock_reuseaddr(fd);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & UV_UDP_REUSEPORT) {
|
||||
err = uv__sock_reuseport(fd);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -722,7 +757,7 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
req->bufs = (uv_buf_t*)uv__malloc(nbufs * sizeof(bufs[0]));
|
||||
|
||||
if (req->bufs == NULL) {
|
||||
uv__req_unregister(handle->loop, req);
|
||||
uv__req_unregister(handle->loop);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
@@ -1015,7 +1050,7 @@ int uv__udp_init_ex(uv_loop_t* loop,
|
||||
|
||||
|
||||
int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||
if (handle->flags & UV_HANDLE_UDP_RECVMMSG)
|
||||
return 1;
|
||||
#endif
|
||||
@@ -1037,7 +1072,7 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = uv__set_reuse(sock);
|
||||
err = uv__sock_reuseaddr(sock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
@@ -231,13 +231,13 @@ void uv__threadpool_cleanup(void);
|
||||
#define uv__has_active_reqs(loop) \
|
||||
((loop)->active_reqs.count > 0)
|
||||
|
||||
#define uv__req_register(loop, req) \
|
||||
#define uv__req_register(loop) \
|
||||
do { \
|
||||
(loop)->active_reqs.count++; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__req_unregister(loop, req) \
|
||||
#define uv__req_unregister(loop) \
|
||||
do { \
|
||||
assert(uv__has_active_reqs(loop)); \
|
||||
(loop)->active_reqs.count--; \
|
||||
@@ -347,7 +347,7 @@ void uv__threadpool_cleanup(void);
|
||||
#define uv__req_init(loop, req, typ) \
|
||||
do { \
|
||||
UV_REQ_INIT(req, typ); \
|
||||
uv__req_register(loop, req); \
|
||||
uv__req_register(loop); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
@@ -398,7 +398,6 @@ void uv__metrics_set_provider_entry_time(uv_loop_t* loop);
|
||||
struct uv__iou {
|
||||
uint32_t* sqhead;
|
||||
uint32_t* sqtail;
|
||||
uint32_t* sqarray;
|
||||
uint32_t sqmask;
|
||||
uint32_t* sqflags;
|
||||
uint32_t* cqhead;
|
||||
@@ -413,7 +412,6 @@ struct uv__iou {
|
||||
size_t sqelen;
|
||||
int ringfd;
|
||||
uint32_t in_flight;
|
||||
uint32_t flags;
|
||||
};
|
||||
#endif /* __linux__ */
|
||||
|
||||
|
||||
@@ -69,7 +69,6 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
}
|
||||
|
||||
switch (sys_errno) {
|
||||
case ERROR_NOACCESS: return UV_EACCES;
|
||||
case WSAEACCES: return UV_EACCES;
|
||||
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
|
||||
case ERROR_CANT_ACCESS_FILE: return UV_EACCES;
|
||||
@@ -78,6 +77,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
|
||||
case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
|
||||
case WSAEWOULDBLOCK: return UV_EAGAIN;
|
||||
case ERROR_NO_DATA: return UV_EAGAIN;
|
||||
case WSAEALREADY: return UV_EALREADY;
|
||||
case ERROR_INVALID_FLAGS: return UV_EBADF;
|
||||
case ERROR_INVALID_HANDLE: return UV_EBADF;
|
||||
@@ -95,7 +95,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case WSAECONNRESET: return UV_ECONNRESET;
|
||||
case ERROR_ALREADY_EXISTS: return UV_EEXIST;
|
||||
case ERROR_FILE_EXISTS: return UV_EEXIST;
|
||||
case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
|
||||
case ERROR_NOACCESS: return UV_EFAULT;
|
||||
case WSAEFAULT: return UV_EFAULT;
|
||||
case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
|
||||
case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
|
||||
@@ -126,6 +126,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
|
||||
case WSAEMFILE: return UV_EMFILE;
|
||||
case WSAEMSGSIZE: return UV_EMSGSIZE;
|
||||
case ERROR_BUFFER_OVERFLOW: return UV_ENAMETOOLONG;
|
||||
case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
|
||||
case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
|
||||
case WSAENETUNREACH: return UV_ENETUNREACH;
|
||||
@@ -157,7 +158,6 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case ERROR_ACCESS_DENIED: return UV_EPERM;
|
||||
case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
|
||||
case ERROR_BAD_PIPE: return UV_EPIPE;
|
||||
case ERROR_NO_DATA: return UV_EPIPE;
|
||||
case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
|
||||
case WSAESHUTDOWN: return UV_EPIPE;
|
||||
case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
|
||||
@@ -168,6 +168,16 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case ERROR_INVALID_FUNCTION: return UV_EISDIR;
|
||||
case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
|
||||
case WSAESOCKTNOSUPPORT: return UV_ESOCKTNOSUPPORT;
|
||||
case ERROR_BAD_EXE_FORMAT: return UV_EFTYPE;
|
||||
default: return UV_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
int uv_translate_write_sys_error(int sys_errno) {
|
||||
switch (sys_errno) {
|
||||
case ERROR_BROKEN_PIPE: return UV_EPIPE;
|
||||
case ERROR_NO_DATA: return UV_EPIPE;
|
||||
default:
|
||||
return uv_translate_sys_error(sys_errno);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,7 +563,25 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
}
|
||||
} else {
|
||||
err = GET_REQ_ERROR(req);
|
||||
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
|
||||
/*
|
||||
* Check whether the ERROR_ACCESS_DENIED is caused by the watched directory
|
||||
* being actually deleted (not an actual error) or a legit error. Retrieve
|
||||
* FileStandardInfo to check whether the directory is pending deletion.
|
||||
*/
|
||||
FILE_STANDARD_INFO info;
|
||||
if (err == ERROR_ACCESS_DENIED &&
|
||||
handle->dirw != NULL &&
|
||||
GetFileInformationByHandleEx(handle->dir_handle,
|
||||
FileStandardInfo,
|
||||
&info,
|
||||
sizeof(info)) &&
|
||||
info.Directory &&
|
||||
info.DeletePending) {
|
||||
uv__convert_utf16_to_utf8(handle->dirw, -1, &filename);
|
||||
handle->cb(handle, filename, UV_RENAME, 0);
|
||||
} else {
|
||||
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
|
||||
}
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
|
||||
@@ -49,6 +49,17 @@
|
||||
#define UV_FS_FREE_PTR 0x0008
|
||||
#define UV_FS_CLEANEDUP 0x0010
|
||||
|
||||
#ifndef FILE_DISPOSITION_DELETE
|
||||
#define FILE_DISPOSITION_DELETE 0x0001
|
||||
#endif /* FILE_DISPOSITION_DELETE */
|
||||
|
||||
#ifndef FILE_DISPOSITION_POSIX_SEMANTICS
|
||||
#define FILE_DISPOSITION_POSIX_SEMANTICS 0x0002
|
||||
#endif /* FILE_DISPOSITION_POSIX_SEMANTICS */
|
||||
|
||||
#ifndef FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE
|
||||
#define FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE 0x0010
|
||||
#endif /* FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE */
|
||||
|
||||
#define INIT(subtype) \
|
||||
do { \
|
||||
@@ -61,7 +72,7 @@
|
||||
#define POST \
|
||||
do { \
|
||||
if (cb != NULL) { \
|
||||
uv__req_register(loop, req); \
|
||||
uv__req_register(loop); \
|
||||
uv__work_submit(loop, \
|
||||
&req->work_req, \
|
||||
UV__WORK_FAST_IO, \
|
||||
@@ -100,13 +111,14 @@
|
||||
return; \
|
||||
}
|
||||
|
||||
#define MILLION ((int64_t) 1000 * 1000)
|
||||
#define BILLION ((int64_t) 1000 * 1000 * 1000)
|
||||
#define NSEC_PER_TICK 100
|
||||
#define TICKS_PER_SEC ((int64_t) 1e9 / NSEC_PER_TICK)
|
||||
static const int64_t WIN_TO_UNIX_TICK_OFFSET = 11644473600 * TICKS_PER_SEC;
|
||||
|
||||
static void uv__filetime_to_timespec(uv_timespec_t *ts, int64_t filetime) {
|
||||
filetime -= 116444736 * BILLION;
|
||||
ts->tv_sec = (long) (filetime / (10 * MILLION));
|
||||
ts->tv_nsec = (long) ((filetime - ts->tv_sec * 10 * MILLION) * 100U);
|
||||
filetime -= WIN_TO_UNIX_TICK_OFFSET;
|
||||
ts->tv_sec = filetime / TICKS_PER_SEC;
|
||||
ts->tv_nsec = (filetime % TICKS_PER_SEC) * NSEC_PER_TICK;
|
||||
if (ts->tv_nsec < 0) {
|
||||
ts->tv_sec -= 1;
|
||||
ts->tv_nsec += 1e9;
|
||||
@@ -115,7 +127,7 @@ static void uv__filetime_to_timespec(uv_timespec_t *ts, int64_t filetime) {
|
||||
|
||||
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
|
||||
do { \
|
||||
int64_t bigtime = ((time) * 10 * MILLION + 116444736 * BILLION); \
|
||||
int64_t bigtime = ((time) * TICKS_PER_SEC + WIN_TO_UNIX_TICK_OFFSET); \
|
||||
(filetime_ptr)->dwLowDateTime = (uint64_t) bigtime & 0xFFFFFFFF; \
|
||||
(filetime_ptr)->dwHighDateTime = (uint64_t) bigtime >> 32; \
|
||||
} while(0)
|
||||
@@ -139,6 +151,16 @@ static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGE
|
||||
|
||||
static DWORD uv__allocation_granularity;
|
||||
|
||||
typedef enum {
|
||||
FS__STAT_PATH_SUCCESS,
|
||||
FS__STAT_PATH_ERROR,
|
||||
FS__STAT_PATH_TRY_SLOW
|
||||
} fs__stat_path_return_t;
|
||||
|
||||
INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf);
|
||||
INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf,
|
||||
FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat);
|
||||
|
||||
|
||||
void uv__fs_init(void) {
|
||||
SYSTEM_INFO system_info;
|
||||
@@ -1059,27 +1081,20 @@ void fs__write(uv_fs_t* req) {
|
||||
error = ERROR_INVALID_FLAGS;
|
||||
}
|
||||
|
||||
SET_REQ_WIN32_ERROR(req, error);
|
||||
SET_REQ_UV_ERROR(req, uv_translate_write_sys_error(error), error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fs__rmdir(uv_fs_t* req) {
|
||||
int result = _wrmdir(req->file.pathw);
|
||||
if (result == -1)
|
||||
SET_REQ_WIN32_ERROR(req, _doserrno);
|
||||
else
|
||||
SET_REQ_RESULT(req, 0);
|
||||
}
|
||||
|
||||
|
||||
void fs__unlink(uv_fs_t* req) {
|
||||
static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) {
|
||||
const WCHAR* pathw = req->file.pathw;
|
||||
HANDLE handle;
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
FILE_DISPOSITION_INFORMATION disposition;
|
||||
FILE_DISPOSITION_INFORMATION_EX disposition_ex;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
NTSTATUS status;
|
||||
DWORD error;
|
||||
|
||||
handle = CreateFileW(pathw,
|
||||
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
|
||||
@@ -1100,10 +1115,18 @@ void fs__unlink(uv_fs_t* req) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
/* Do not allow deletion of directories, unless it is a symlink. When the
|
||||
* path refers to a non-symlink directory, report EPERM as mandated by
|
||||
* POSIX.1. */
|
||||
if (isrmdir && !(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
/* Error if we're in rmdir mode but it is not a dir.
|
||||
* TODO: change it to UV_NOTDIR in v2. */
|
||||
SET_REQ_UV_ERROR(req, UV_ENOENT, ERROR_DIRECTORY);
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isrmdir && (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
/* If not explicitly allowed, do not allow deletion of directories, unless
|
||||
* it is a symlink. When the path refers to a non-symlink directory, report
|
||||
* EPERM as mandated by POSIX.1. */
|
||||
|
||||
/* Check if it is a reparse point. If it's not, it's a normal directory. */
|
||||
if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||
@@ -1115,7 +1138,7 @@ void fs__unlink(uv_fs_t* req) {
|
||||
/* Read the reparse point and check if it is a valid symlink. If not, don't
|
||||
* unlink. */
|
||||
if (fs__readlink_handle(handle, NULL, NULL) < 0) {
|
||||
DWORD error = GetLastError();
|
||||
error = GetLastError();
|
||||
if (error == ERROR_SYMLINK_NOT_SUPPORTED)
|
||||
error = ERROR_ACCESS_DENIED;
|
||||
SET_REQ_WIN32_ERROR(req, error);
|
||||
@@ -1124,42 +1147,77 @@ void fs__unlink(uv_fs_t* req) {
|
||||
}
|
||||
}
|
||||
|
||||
if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
|
||||
/* Remove read-only attribute */
|
||||
FILE_BASIC_INFORMATION basic = { 0 };
|
||||
/* Try posix delete first */
|
||||
disposition_ex.Flags = FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS |
|
||||
FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE;
|
||||
|
||||
basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
|
||||
FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
status = pNtSetInformationFile(handle,
|
||||
&iosb,
|
||||
&basic,
|
||||
sizeof basic,
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to set the delete flag. */
|
||||
disposition.DeleteFile = TRUE;
|
||||
status = pNtSetInformationFile(handle,
|
||||
&iosb,
|
||||
&disposition,
|
||||
sizeof disposition,
|
||||
FileDispositionInformation);
|
||||
&disposition_ex,
|
||||
sizeof disposition_ex,
|
||||
FileDispositionInformationEx);
|
||||
if (NT_SUCCESS(status)) {
|
||||
SET_REQ_SUCCESS(req);
|
||||
} else {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
|
||||
/* If status == STATUS_CANNOT_DELETE here, given we set
|
||||
* FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE, STATUS_CANNOT_DELETE can only mean
|
||||
* that there is an existing mapped view to the file, preventing delete.
|
||||
* STATUS_CANNOT_DELETE maps to UV_EACCES so it's not specifically worth handling */
|
||||
error = pRtlNtStatusToDosError(status);
|
||||
if (error == ERROR_NOT_SUPPORTED /* filesystem does not support posix deletion */ ||
|
||||
error == ERROR_INVALID_PARAMETER /* pre Windows 10 error */ ||
|
||||
error == ERROR_INVALID_FUNCTION /* pre Windows 10 1607 error */) {
|
||||
/* posix delete not supported so try fallback */
|
||||
if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
|
||||
/* Remove read-only attribute */
|
||||
FILE_BASIC_INFORMATION basic = { 0 };
|
||||
|
||||
basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
|
||||
FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
status = pNtSetInformationFile(handle,
|
||||
&iosb,
|
||||
&basic,
|
||||
sizeof basic,
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to set the delete flag. */
|
||||
disposition.DeleteFile = TRUE;
|
||||
status = pNtSetInformationFile(handle,
|
||||
&iosb,
|
||||
&disposition,
|
||||
sizeof disposition,
|
||||
FileDispositionInformation);
|
||||
if (NT_SUCCESS(status)) {
|
||||
SET_REQ_SUCCESS(req);
|
||||
} else {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
|
||||
}
|
||||
} else {
|
||||
SET_REQ_WIN32_ERROR(req, error);
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
|
||||
static void fs__rmdir(uv_fs_t* req) {
|
||||
fs__unlink_rmdir(req, /*isrmdir*/1);
|
||||
}
|
||||
|
||||
|
||||
static void fs__unlink(uv_fs_t* req) {
|
||||
fs__unlink_rmdir(req, /*isrmdir*/0);
|
||||
}
|
||||
|
||||
|
||||
void fs__mkdir(uv_fs_t* req) {
|
||||
/* TODO: use req->mode. */
|
||||
if (CreateDirectoryW(req->file.pathw, NULL)) {
|
||||
@@ -1596,12 +1654,12 @@ void fs__readdir(uv_fs_t* req) {
|
||||
goto error;
|
||||
|
||||
/* Copy file type. */
|
||||
if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||
dent.d_type = UV__DT_DIR;
|
||||
if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0)
|
||||
dent.d_type = UV__DT_CHAR;
|
||||
else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
|
||||
dent.d_type = UV__DT_LINK;
|
||||
else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0)
|
||||
dent.d_type = UV__DT_CHAR;
|
||||
else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||
dent.d_type = UV__DT_DIR;
|
||||
else
|
||||
dent.d_type = UV__DT_FILE;
|
||||
|
||||
@@ -1630,6 +1688,43 @@ void fs__closedir(uv_fs_t* req) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
}
|
||||
|
||||
INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path,
|
||||
uv_stat_t* statbuf, int do_lstat) {
|
||||
FILE_STAT_BASIC_INFORMATION stat_info;
|
||||
|
||||
// Check if the new fast API is available.
|
||||
if (!pGetFileInformationByName) {
|
||||
return FS__STAT_PATH_TRY_SLOW;
|
||||
}
|
||||
|
||||
// Check if the API call fails.
|
||||
if (!pGetFileInformationByName(path, FileStatBasicByNameInfo, &stat_info,
|
||||
sizeof(stat_info))) {
|
||||
switch(GetLastError()) {
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
case ERROR_NOT_READY:
|
||||
case ERROR_BAD_NET_NAME:
|
||||
/* These errors aren't worth retrying with the slow path. */
|
||||
return FS__STAT_PATH_ERROR;
|
||||
}
|
||||
return FS__STAT_PATH_TRY_SLOW;
|
||||
}
|
||||
|
||||
// A file handle is needed to get st_size for links.
|
||||
if ((stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||
return FS__STAT_PATH_TRY_SLOW;
|
||||
}
|
||||
|
||||
if (stat_info.DeviceType == FILE_DEVICE_NULL) {
|
||||
fs__stat_assign_statbuf_null(statbuf);
|
||||
return FS__STAT_PATH_SUCCESS;
|
||||
}
|
||||
|
||||
fs__stat_assign_statbuf(statbuf, stat_info, do_lstat);
|
||||
return FS__STAT_PATH_SUCCESS;
|
||||
}
|
||||
|
||||
INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
int do_lstat) {
|
||||
size_t target_length = 0;
|
||||
@@ -1638,6 +1733,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
FILE_FS_VOLUME_INFORMATION volume_info;
|
||||
NTSTATUS nt_status;
|
||||
IO_STATUS_BLOCK io_status;
|
||||
FILE_STAT_BASIC_INFORMATION stat_info;
|
||||
|
||||
nt_status = pNtQueryVolumeInformationFile(handle,
|
||||
&io_status,
|
||||
@@ -1653,13 +1749,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
|
||||
/* If it's NUL device set fields as reasonable as possible and return. */
|
||||
if (device_info.DeviceType == FILE_DEVICE_NULL) {
|
||||
memset(statbuf, 0, sizeof(uv_stat_t));
|
||||
statbuf->st_mode = _S_IFCHR;
|
||||
statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
|
||||
((_S_IREAD | _S_IWRITE) >> 6);
|
||||
statbuf->st_nlink = 1;
|
||||
statbuf->st_blksize = 4096;
|
||||
statbuf->st_rdev = FILE_DEVICE_NULL << 16;
|
||||
fs__stat_assign_statbuf_null(statbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1683,14 +1773,65 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
|
||||
/* Buffer overflow (a warning status code) is expected here. */
|
||||
if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
|
||||
statbuf->st_dev = 0;
|
||||
stat_info.VolumeSerialNumber.QuadPart = 0;
|
||||
} else if (NT_ERROR(nt_status)) {
|
||||
SetLastError(pRtlNtStatusToDosError(nt_status));
|
||||
return -1;
|
||||
} else {
|
||||
statbuf->st_dev = volume_info.VolumeSerialNumber;
|
||||
stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber;
|
||||
}
|
||||
|
||||
stat_info.DeviceType = device_info.DeviceType;
|
||||
stat_info.FileAttributes = file_info.BasicInformation.FileAttributes;
|
||||
stat_info.NumberOfLinks = file_info.StandardInformation.NumberOfLinks;
|
||||
stat_info.FileId.QuadPart =
|
||||
file_info.InternalInformation.IndexNumber.QuadPart;
|
||||
stat_info.ChangeTime.QuadPart =
|
||||
file_info.BasicInformation.ChangeTime.QuadPart;
|
||||
stat_info.CreationTime.QuadPart =
|
||||
file_info.BasicInformation.CreationTime.QuadPart;
|
||||
stat_info.LastAccessTime.QuadPart =
|
||||
file_info.BasicInformation.LastAccessTime.QuadPart;
|
||||
stat_info.LastWriteTime.QuadPart =
|
||||
file_info.BasicInformation.LastWriteTime.QuadPart;
|
||||
stat_info.AllocationSize.QuadPart =
|
||||
file_info.StandardInformation.AllocationSize.QuadPart;
|
||||
|
||||
if (do_lstat &&
|
||||
(file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||
/*
|
||||
* If reading the link fails, the reparse point is not a symlink and needs
|
||||
* to be treated as a regular file. The higher level lstat function will
|
||||
* detect this failure and retry without do_lstat if appropriate.
|
||||
*/
|
||||
if (fs__readlink_handle(handle, NULL, &target_length) != 0) {
|
||||
fs__stat_assign_statbuf(statbuf, stat_info, do_lstat);
|
||||
return -1;
|
||||
}
|
||||
stat_info.EndOfFile.QuadPart = target_length;
|
||||
} else {
|
||||
stat_info.EndOfFile.QuadPart =
|
||||
file_info.StandardInformation.EndOfFile.QuadPart;
|
||||
}
|
||||
|
||||
fs__stat_assign_statbuf(statbuf, stat_info, do_lstat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) {
|
||||
memset(statbuf, 0, sizeof(uv_stat_t));
|
||||
statbuf->st_mode = _S_IFCHR;
|
||||
statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
|
||||
((_S_IREAD | _S_IWRITE) >> 6);
|
||||
statbuf->st_nlink = 1;
|
||||
statbuf->st_blksize = 4096;
|
||||
statbuf->st_rdev = FILE_DEVICE_NULL << 16;
|
||||
}
|
||||
|
||||
INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf,
|
||||
FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat) {
|
||||
statbuf->st_dev = stat_info.VolumeSerialNumber.QuadPart;
|
||||
|
||||
/* Todo: st_mode should probably always be 0666 for everyone. We might also
|
||||
* want to report 0777 if the file is a .exe or a directory.
|
||||
*
|
||||
@@ -1722,50 +1863,43 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
* target. Otherwise, reparse points must be treated as regular files.
|
||||
*/
|
||||
if (do_lstat &&
|
||||
(file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||
/*
|
||||
* If reading the link fails, the reparse point is not a symlink and needs
|
||||
* to be treated as a regular file. The higher level lstat function will
|
||||
* detect this failure and retry without do_lstat if appropriate.
|
||||
*/
|
||||
if (fs__readlink_handle(handle, NULL, &target_length) != 0)
|
||||
return -1;
|
||||
(stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||
statbuf->st_mode |= S_IFLNK;
|
||||
statbuf->st_size = target_length;
|
||||
statbuf->st_size = stat_info.EndOfFile.QuadPart;
|
||||
}
|
||||
|
||||
if (statbuf->st_mode == 0) {
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
if (stat_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
statbuf->st_mode |= _S_IFDIR;
|
||||
statbuf->st_size = 0;
|
||||
} else {
|
||||
statbuf->st_mode |= _S_IFREG;
|
||||
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
|
||||
statbuf->st_size = stat_info.EndOfFile.QuadPart;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
if (stat_info.FileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
|
||||
else
|
||||
statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
|
||||
((_S_IREAD | _S_IWRITE) >> 6);
|
||||
|
||||
uv__filetime_to_timespec(&statbuf->st_atim,
|
||||
file_info.BasicInformation.LastAccessTime.QuadPart);
|
||||
stat_info.LastAccessTime.QuadPart);
|
||||
uv__filetime_to_timespec(&statbuf->st_ctim,
|
||||
file_info.BasicInformation.ChangeTime.QuadPart);
|
||||
stat_info.ChangeTime.QuadPart);
|
||||
uv__filetime_to_timespec(&statbuf->st_mtim,
|
||||
file_info.BasicInformation.LastWriteTime.QuadPart);
|
||||
stat_info.LastWriteTime.QuadPart);
|
||||
uv__filetime_to_timespec(&statbuf->st_birthtim,
|
||||
file_info.BasicInformation.CreationTime.QuadPart);
|
||||
stat_info.CreationTime.QuadPart);
|
||||
|
||||
statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
|
||||
statbuf->st_ino = stat_info.FileId.QuadPart;
|
||||
|
||||
/* st_blocks contains the on-disk allocation size in 512-byte units. */
|
||||
statbuf->st_blocks =
|
||||
(uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9;
|
||||
(uint64_t) stat_info.AllocationSize.QuadPart >> 9;
|
||||
|
||||
statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
|
||||
statbuf->st_nlink = stat_info.NumberOfLinks;
|
||||
|
||||
/* The st_blksize is supposed to be the 'optimal' number of bytes for reading
|
||||
* and writing to the disk. That is, for any definition of 'optimal' - it's
|
||||
@@ -1797,8 +1931,6 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
statbuf->st_uid = 0;
|
||||
statbuf->st_rdev = 0;
|
||||
statbuf->st_gen = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1820,6 +1952,17 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
|
||||
DWORD flags;
|
||||
DWORD ret;
|
||||
|
||||
// If new API exists, try to use it.
|
||||
switch (fs__stat_path(path, statbuf, do_lstat)) {
|
||||
case FS__STAT_PATH_SUCCESS:
|
||||
return 0;
|
||||
case FS__STAT_PATH_ERROR:
|
||||
return GetLastError();
|
||||
case FS__STAT_PATH_TRY_SLOW:
|
||||
break;
|
||||
}
|
||||
|
||||
// If the new API does not exist, use the old API.
|
||||
flags = FILE_FLAG_BACKUP_SEMANTICS;
|
||||
if (do_lstat)
|
||||
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||
@@ -2426,16 +2569,17 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
|
||||
|
||||
path_buf[path_buf_len++] = path[i];
|
||||
}
|
||||
path_buf[path_buf_len++] = L'\\';
|
||||
if (add_slash)
|
||||
path_buf[path_buf_len++] = L'\\';
|
||||
len = path_buf_len - start;
|
||||
|
||||
/* Insert null terminator */
|
||||
path_buf[path_buf_len++] = L'\0';
|
||||
|
||||
/* Set the info about the substitute name */
|
||||
buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
|
||||
buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
|
||||
|
||||
/* Insert null terminator */
|
||||
path_buf[path_buf_len++] = L'\0';
|
||||
|
||||
/* Copy the print name of the target path */
|
||||
start = path_buf_len;
|
||||
add_slash = 0;
|
||||
@@ -2453,18 +2597,18 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
|
||||
path_buf[path_buf_len++] = path[i];
|
||||
}
|
||||
len = path_buf_len - start;
|
||||
if (len == 2) {
|
||||
if (len == 2 || add_slash) {
|
||||
path_buf[path_buf_len++] = L'\\';
|
||||
len++;
|
||||
}
|
||||
|
||||
/* Insert another null terminator */
|
||||
path_buf[path_buf_len++] = L'\0';
|
||||
|
||||
/* Set the info about the print name */
|
||||
buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
|
||||
buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
|
||||
|
||||
/* Insert another null terminator */
|
||||
path_buf[path_buf_len++] = L'\0';
|
||||
|
||||
/* Calculate how much buffer space was actually used */
|
||||
used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
|
||||
path_buf_len * sizeof(WCHAR);
|
||||
@@ -2833,7 +2977,7 @@ static void uv__fs_done(struct uv__work* w, int status) {
|
||||
uv_fs_t* req;
|
||||
|
||||
req = container_of(w, uv_fs_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
assert(req->result == 0);
|
||||
|
||||
@@ -71,10 +71,9 @@ int uv__getaddrinfo_translate_error(int sys_err) {
|
||||
DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
|
||||
#endif
|
||||
|
||||
|
||||
/* Adjust size value to be multiple of 4. Use to keep pointer aligned.
|
||||
* Do we need different versions of this for different architectures? */
|
||||
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
|
||||
static size_t align_offset(size_t off, size_t alignment) {
|
||||
return ((off + alignment - 1) / alignment) * alignment;
|
||||
}
|
||||
|
||||
#ifndef NDIS_IF_MAX_STRING_SIZE
|
||||
#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
|
||||
@@ -103,17 +102,7 @@ static void uv__getaddrinfo_work(struct uv__work* w) {
|
||||
* Each size calculation is adjusted to avoid unaligned pointers.
|
||||
*/
|
||||
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
uv_getaddrinfo_t* req;
|
||||
size_t addrinfo_len = 0;
|
||||
ssize_t name_len = 0;
|
||||
size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
|
||||
struct addrinfoW* addrinfow_ptr;
|
||||
struct addrinfo* addrinfo_ptr;
|
||||
char* alloc_ptr = NULL;
|
||||
char* cur_ptr = NULL;
|
||||
int r;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
uv_getaddrinfo_t* req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
|
||||
/* release input parameter memory */
|
||||
uv__free(req->alloc);
|
||||
@@ -126,34 +115,44 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
}
|
||||
|
||||
if (req->retcode == 0) {
|
||||
char* alloc_ptr = NULL;
|
||||
size_t cur_off = 0;
|
||||
size_t addrinfo_len;
|
||||
/* Convert addrinfoW to addrinfo. First calculate required length. */
|
||||
addrinfow_ptr = req->addrinfow;
|
||||
struct addrinfoW* addrinfow_ptr = req->addrinfow;
|
||||
while (addrinfow_ptr != NULL) {
|
||||
addrinfo_len += addrinfo_struct_len +
|
||||
ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
|
||||
cur_off = align_offset(cur_off, sizeof(void*));
|
||||
cur_off += sizeof(struct addrinfo);
|
||||
/* TODO: This alignment could be smaller, if we could
|
||||
portably get the alignment for sockaddr. */
|
||||
cur_off = align_offset(cur_off, sizeof(void*));
|
||||
cur_off += addrinfow_ptr->ai_addrlen;
|
||||
if (addrinfow_ptr->ai_canonname != NULL) {
|
||||
name_len = uv_utf16_length_as_wtf8((const uint16_t*)addrinfow_ptr->ai_canonname, -1);
|
||||
ssize_t name_len =
|
||||
uv_utf16_length_as_wtf8((const uint16_t*)addrinfow_ptr->ai_canonname, -1);
|
||||
if (name_len < 0) {
|
||||
req->retcode = name_len;
|
||||
goto complete;
|
||||
}
|
||||
addrinfo_len += ALIGNED_SIZE(name_len + 1);
|
||||
cur_off += name_len + 1;
|
||||
}
|
||||
addrinfow_ptr = addrinfow_ptr->ai_next;
|
||||
}
|
||||
|
||||
/* allocate memory for addrinfo results */
|
||||
addrinfo_len = cur_off;
|
||||
alloc_ptr = (char*)uv__malloc(addrinfo_len);
|
||||
|
||||
/* do conversions */
|
||||
if (alloc_ptr != NULL) {
|
||||
cur_ptr = alloc_ptr;
|
||||
struct addrinfo *addrinfo_ptr = (struct addrinfo *)alloc_ptr;
|
||||
cur_off = 0;
|
||||
addrinfow_ptr = req->addrinfow;
|
||||
|
||||
while (addrinfow_ptr != NULL) {
|
||||
for (;;) {
|
||||
cur_off += sizeof(struct addrinfo);
|
||||
assert(cur_off <= addrinfo_len);
|
||||
/* copy addrinfo struct data */
|
||||
assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
|
||||
addrinfo_ptr = (struct addrinfo*)cur_ptr;
|
||||
addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
|
||||
addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
|
||||
addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
|
||||
@@ -163,35 +162,38 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
addrinfo_ptr->ai_addr = NULL;
|
||||
addrinfo_ptr->ai_next = NULL;
|
||||
|
||||
cur_ptr += addrinfo_struct_len;
|
||||
|
||||
/* copy sockaddr */
|
||||
if (addrinfo_ptr->ai_addrlen > 0) {
|
||||
assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
|
||||
alloc_ptr + addrinfo_len);
|
||||
memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
|
||||
addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
|
||||
cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
|
||||
cur_off = align_offset(cur_off, sizeof(void *));
|
||||
addrinfo_ptr->ai_addr = (struct sockaddr *)(alloc_ptr + cur_off);
|
||||
cur_off += addrinfo_ptr->ai_addrlen;
|
||||
assert(cur_off <= addrinfo_len);
|
||||
memcpy(addrinfo_ptr->ai_addr,
|
||||
addrinfow_ptr->ai_addr,
|
||||
addrinfo_ptr->ai_addrlen);
|
||||
}
|
||||
|
||||
/* convert canonical name to UTF-8 */
|
||||
if (addrinfow_ptr->ai_canonname != NULL) {
|
||||
name_len = alloc_ptr + addrinfo_len - cur_ptr;
|
||||
r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname,
|
||||
-1,
|
||||
cur_ptr,
|
||||
(size_t*)&name_len);
|
||||
ssize_t name_len = addrinfo_len - cur_off;
|
||||
addrinfo_ptr->ai_canonname = alloc_ptr + cur_off;
|
||||
int r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname,
|
||||
-1,
|
||||
addrinfo_ptr->ai_canonname,
|
||||
(size_t*)&name_len);
|
||||
assert(r == 0);
|
||||
addrinfo_ptr->ai_canonname = cur_ptr;
|
||||
cur_ptr += ALIGNED_SIZE(name_len + 1);
|
||||
cur_off += name_len + 1;
|
||||
assert(cur_off <= addrinfo_len);
|
||||
}
|
||||
assert(cur_ptr <= alloc_ptr + addrinfo_len);
|
||||
|
||||
/* set next ptr */
|
||||
addrinfow_ptr = addrinfow_ptr->ai_next;
|
||||
if (addrinfow_ptr != NULL) {
|
||||
addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
|
||||
}
|
||||
if (addrinfow_ptr == NULL)
|
||||
break;
|
||||
cur_off = align_offset(cur_off, sizeof(void *));
|
||||
struct addrinfo *next_addrinfo_ptr = (struct addrinfo *)(alloc_ptr + cur_off);
|
||||
addrinfo_ptr->ai_next = next_addrinfo_ptr;
|
||||
addrinfo_ptr = next_addrinfo_ptr;
|
||||
}
|
||||
req->addrinfo = (struct addrinfo*)alloc_ptr;
|
||||
} else {
|
||||
@@ -206,7 +208,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
}
|
||||
|
||||
complete:
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
|
||||
/* finally do callback with converted result */
|
||||
if (req->getaddrinfo_cb)
|
||||
@@ -242,10 +244,12 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
char hostname_ascii[256];
|
||||
size_t off = 0;
|
||||
size_t nodesize = 0;
|
||||
size_t servicesize = 0;
|
||||
size_t serviceoff = 0;
|
||||
size_t hintssize = 0;
|
||||
char* alloc_ptr = NULL;
|
||||
size_t hintoff = 0;
|
||||
ssize_t rc;
|
||||
|
||||
if (req == NULL || (node == NULL && service == NULL)) {
|
||||
@@ -268,6 +272,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
return rc;
|
||||
nodesize = strlen(hostname_ascii) + 1;
|
||||
node = hostname_ascii;
|
||||
off += nodesize * sizeof(WCHAR);
|
||||
}
|
||||
|
||||
if (service != NULL) {
|
||||
@@ -275,27 +280,28 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
servicesize = rc;
|
||||
off = align_offset(off, sizeof(WCHAR));
|
||||
serviceoff = off;
|
||||
off += servicesize * sizeof(WCHAR);
|
||||
}
|
||||
|
||||
if (hints != NULL) {
|
||||
hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
|
||||
off = align_offset(off, sizeof(void *));
|
||||
hintoff = off;
|
||||
hintssize = sizeof(struct addrinfoW);
|
||||
off += hintssize;
|
||||
}
|
||||
|
||||
/* allocate memory for inputs, and partition it as needed */
|
||||
alloc_ptr = (char*)uv__malloc(ALIGNED_SIZE(nodesize * sizeof(WCHAR)) +
|
||||
ALIGNED_SIZE(servicesize * sizeof(WCHAR)) +
|
||||
hintssize);
|
||||
if (!alloc_ptr)
|
||||
req->alloc = (char*)uv__malloc(off);
|
||||
if (!req->alloc)
|
||||
return UV_ENOMEM;
|
||||
|
||||
/* save alloc_ptr now so we can free if error */
|
||||
req->alloc = (void*) alloc_ptr;
|
||||
|
||||
/* Convert node string to UTF16 into allocated memory and save pointer in the
|
||||
* request. The node here has been converted to ascii. */
|
||||
if (node != NULL) {
|
||||
req->node = (WCHAR*) alloc_ptr;
|
||||
uv_wtf8_to_utf16(node, (uint16_t*) alloc_ptr, nodesize);
|
||||
alloc_ptr += ALIGNED_SIZE(nodesize * sizeof(WCHAR));
|
||||
req->node = (WCHAR*) req->alloc;
|
||||
uv_wtf8_to_utf16(node, (uint16_t*)req->node, nodesize);
|
||||
} else {
|
||||
req->node = NULL;
|
||||
}
|
||||
@@ -303,16 +309,15 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
/* Convert service string to UTF16 into allocated memory and save pointer in
|
||||
* the req. */
|
||||
if (service != NULL) {
|
||||
req->service = (WCHAR*) alloc_ptr;
|
||||
uv_wtf8_to_utf16(service, (uint16_t*) alloc_ptr, servicesize);
|
||||
alloc_ptr += ALIGNED_SIZE(servicesize * sizeof(WCHAR));
|
||||
req->service = (WCHAR*) ((char*) req->alloc + serviceoff);
|
||||
uv_wtf8_to_utf16(service, (uint16_t*)req->service, servicesize);
|
||||
} else {
|
||||
req->service = NULL;
|
||||
}
|
||||
|
||||
/* copy hints to allocated memory and save pointer in req */
|
||||
if (hints != NULL) {
|
||||
req->addrinfow = (struct addrinfoW*) alloc_ptr;
|
||||
req->addrinfow = (struct addrinfoW*) ((char*) req->alloc + hintoff);
|
||||
req->addrinfow->ai_family = hints->ai_family;
|
||||
req->addrinfow->ai_socktype = hints->ai_socktype;
|
||||
req->addrinfow->ai_protocol = hints->ai_protocol;
|
||||
@@ -325,7 +330,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
req->addrinfow = NULL;
|
||||
}
|
||||
|
||||
uv__req_register(loop, req);
|
||||
uv__req_register(loop);
|
||||
|
||||
if (getaddrinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
|
||||
@@ -82,7 +82,7 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) {
|
||||
char* service;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
uv__req_unregister(req->loop);
|
||||
host = service = NULL;
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
@@ -124,7 +124,7 @@ int uv_getnameinfo(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
UV_REQ_INIT(req, UV_GETNAMEINFO);
|
||||
uv__req_register(loop, req);
|
||||
uv__req_register(loop);
|
||||
|
||||
req->getnameinfo_cb = getnameinfo_cb;
|
||||
req->flags = flags;
|
||||
|
||||
@@ -330,4 +330,6 @@ void uv__wake_all_loops(void);
|
||||
*/
|
||||
void uv__init_detect_system_wakeup(void);
|
||||
|
||||
int uv_translate_write_sys_error(int sys_errno);
|
||||
|
||||
#endif /* UV_WIN_INTERNAL_H_ */
|
||||
|
||||
@@ -108,8 +108,8 @@ static int includes_nul(const char *s, size_t n) {
|
||||
}
|
||||
|
||||
|
||||
static void uv__unique_pipe_name(char* ptr, char* name, size_t size) {
|
||||
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
|
||||
static void uv__unique_pipe_name(unsigned long long ptr, char* name, size_t size) {
|
||||
snprintf(name, size, "\\\\?\\pipe\\uv\\%llu-%lu", ptr, GetCurrentProcessId());
|
||||
}
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ static void close_pipe(uv_pipe_t* pipe) {
|
||||
|
||||
static int uv__pipe_server(
|
||||
HANDLE* pipeHandle_ptr, DWORD access,
|
||||
char* name, size_t nameSize, char* random) {
|
||||
char* name, size_t nameSize, unsigned long long random) {
|
||||
HANDLE pipeHandle;
|
||||
int err;
|
||||
|
||||
@@ -251,7 +251,7 @@ static int uv__pipe_server(
|
||||
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) {
|
||||
int inherit_client, unsigned long long random) {
|
||||
/* allowed flags are: UV_READABLE_PIPE | UV_WRITABLE_PIPE | UV_NONBLOCK_PIPE */
|
||||
char pipe_name[64];
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
@@ -359,7 +359,12 @@ int uv_pipe(uv_file fds[2], int read_flags, int write_flags) {
|
||||
/* 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]);
|
||||
err = uv__create_pipe_pair(&readh,
|
||||
&writeh,
|
||||
read_flags,
|
||||
write_flags,
|
||||
0,
|
||||
(uintptr_t) &fds[0]);
|
||||
if (err != 0)
|
||||
return err;
|
||||
temp[0] = _open_osfhandle((intptr_t) readh, 0);
|
||||
@@ -423,7 +428,7 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
err = uv__create_pipe_pair(&server_pipe, &client_pipe,
|
||||
server_flags, client_flags, 1, (char*) server_pipe);
|
||||
server_flags, client_flags, 1, (uintptr_t) server_pipe);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
@@ -669,15 +674,10 @@ void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
handle->pipe.conn.ipc_xfer_queue_length = 0;
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
|
||||
UnregisterWait(handle->read_req.wait_handle);
|
||||
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (handle->read_req.event_handle != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
assert(handle->read_req.wait_handle == INVALID_HANDLE_VALUE);
|
||||
if (handle->read_req.event_handle != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)
|
||||
@@ -870,7 +870,7 @@ void uv_pipe_connect(uv_connect_t* req,
|
||||
SET_REQ_ERROR(req, err);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -961,7 +961,7 @@ int uv_pipe_connect2(uv_connect_t* req,
|
||||
goto error;
|
||||
}
|
||||
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
handle->reqs_pending++;
|
||||
|
||||
return 0;
|
||||
@@ -976,7 +976,7 @@ int uv_pipe_connect2(uv_connect_t* req,
|
||||
SET_REQ_SUCCESS(req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
@@ -994,7 +994,7 @@ error:
|
||||
SET_REQ_ERROR(req, err);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1419,13 +1419,12 @@ static void uv__pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
if (req->wait_handle == INVALID_HANDLE_VALUE) {
|
||||
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->event_handle, post_completion_read_wait, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
goto error;
|
||||
}
|
||||
assert(req->wait_handle == INVALID_HANDLE_VALUE);
|
||||
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->event_handle, post_completion_read_wait, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1453,16 +1452,16 @@ int uv__pipe_read_start(uv_pipe_t* handle,
|
||||
handle->read_cb = read_cb;
|
||||
handle->alloc_cb = alloc_cb;
|
||||
|
||||
if (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");
|
||||
}
|
||||
}
|
||||
|
||||
/* If reading was stopped and then started again, there could still be a read
|
||||
* request pending. */
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1640,7 +1639,7 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
req->u.io.queued_bytes = 0;
|
||||
}
|
||||
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
handle->reqs_pending++;
|
||||
handle->stream.conn.write_reqs_pending++;
|
||||
POST_COMPLETION_FOR_REQ(loop, req);
|
||||
@@ -1688,7 +1687,7 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
handle->reqs_pending++;
|
||||
handle->stream.conn.write_reqs_pending++;
|
||||
return 0;
|
||||
@@ -1715,13 +1714,13 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->event_handle, post_completion_write_wait, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
handle->reqs_pending++;
|
||||
handle->stream.conn.write_reqs_pending++;
|
||||
|
||||
@@ -1891,7 +1890,7 @@ 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,
|
||||
int error, uv_buf_t buf) {
|
||||
DWORD error, uv_buf_t buf) {
|
||||
if (error == ERROR_BROKEN_PIPE) {
|
||||
uv__pipe_read_eof(loop, handle, buf);
|
||||
} else {
|
||||
@@ -1921,17 +1920,25 @@ static void uv__pipe_queue_ipc_xfer_info(
|
||||
/* Read an exact number of bytes from a pipe. If an error or end-of-file is
|
||||
* encountered before the requested number of bytes are read, an error is
|
||||
* returned. */
|
||||
static int uv__pipe_read_exactly(HANDLE h, void* buffer, DWORD count) {
|
||||
DWORD bytes_read, bytes_read_now;
|
||||
static DWORD uv__pipe_read_exactly(uv_pipe_t* handle, void* buffer, DWORD count) {
|
||||
uv_read_t* req;
|
||||
DWORD bytes_read;
|
||||
DWORD bytes_read_now;
|
||||
|
||||
bytes_read = 0;
|
||||
while (bytes_read < count) {
|
||||
if (!ReadFile(h,
|
||||
req = &handle->read_req;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
|
||||
if (!ReadFile(handle->handle,
|
||||
(char*) buffer + bytes_read,
|
||||
count - bytes_read,
|
||||
&bytes_read_now,
|
||||
NULL)) {
|
||||
return GetLastError();
|
||||
&req->u.io.overlapped)) {
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
return GetLastError();
|
||||
if (!GetOverlappedResult(handle->handle, &req->u.io.overlapped, &bytes_read_now, TRUE))
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
bytes_read += bytes_read_now;
|
||||
@@ -1942,16 +1949,19 @@ static int uv__pipe_read_exactly(HANDLE h, void* buffer, DWORD count) {
|
||||
}
|
||||
|
||||
|
||||
static DWORD uv__pipe_read_data(uv_loop_t* loop,
|
||||
uv_pipe_t* handle,
|
||||
DWORD suggested_bytes,
|
||||
DWORD max_bytes) {
|
||||
DWORD bytes_read;
|
||||
static int uv__pipe_read_data(uv_loop_t* loop,
|
||||
uv_pipe_t* handle,
|
||||
DWORD* bytes_read, /* inout argument */
|
||||
DWORD max_bytes) {
|
||||
uv_buf_t buf;
|
||||
uv_read_t* req;
|
||||
DWORD r;
|
||||
DWORD bytes_available;
|
||||
int more;
|
||||
|
||||
/* Ask the user for a buffer to read data into. */
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, suggested_bytes, &buf);
|
||||
handle->alloc_cb((uv_handle_t*) handle, *bytes_read, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
return 0; /* Break out of read loop. */
|
||||
@@ -1960,33 +1970,77 @@ static DWORD uv__pipe_read_data(uv_loop_t* loop,
|
||||
/* Ensure we read at most the smaller of:
|
||||
* (a) the length of the user-allocated buffer.
|
||||
* (b) the maximum data length as specified by the `max_bytes` argument.
|
||||
* (c) the amount of data that can be read non-blocking
|
||||
*/
|
||||
if (max_bytes > buf.len)
|
||||
max_bytes = buf.len;
|
||||
|
||||
/* 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);
|
||||
return 0; /* Break out of read loop. */
|
||||
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
|
||||
/* The user failed to supply a pipe that can be used non-blocking or with
|
||||
* threads. Try to estimate the amount of data that is safe to read without
|
||||
* blocking, in a race-y way however. */
|
||||
bytes_available = 0;
|
||||
if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &bytes_available, NULL)) {
|
||||
r = GetLastError();
|
||||
} else {
|
||||
if (max_bytes > bytes_available)
|
||||
max_bytes = bytes_available;
|
||||
*bytes_read = 0;
|
||||
if (max_bytes == 0 || ReadFile(handle->handle, buf.base, max_bytes, bytes_read, NULL))
|
||||
r = ERROR_SUCCESS;
|
||||
else
|
||||
r = GetLastError();
|
||||
}
|
||||
more = max_bytes < bytes_available;
|
||||
} else {
|
||||
/* Read into the user buffer.
|
||||
* Prepare an Event so that we can cancel if it doesn't complete immediately.
|
||||
*/
|
||||
req = &handle->read_req;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
|
||||
if (ReadFile(handle->handle, buf.base, max_bytes, bytes_read, &req->u.io.overlapped)) {
|
||||
r = ERROR_SUCCESS;
|
||||
} else {
|
||||
r = GetLastError();
|
||||
*bytes_read = 0;
|
||||
if (r == ERROR_IO_PENDING) {
|
||||
r = CancelIoEx(handle->handle, &req->u.io.overlapped);
|
||||
assert(r || GetLastError() == ERROR_NOT_FOUND);
|
||||
if (GetOverlappedResult(handle->handle, &req->u.io.overlapped, bytes_read, TRUE)) {
|
||||
r = ERROR_SUCCESS;
|
||||
} else {
|
||||
r = GetLastError();
|
||||
*bytes_read = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
more = *bytes_read == max_bytes;
|
||||
}
|
||||
|
||||
/* Call the read callback. */
|
||||
handle->read_cb((uv_stream_t*) handle, bytes_read, &buf);
|
||||
if (r == ERROR_SUCCESS || r == ERROR_OPERATION_ABORTED)
|
||||
handle->read_cb((uv_stream_t*) handle, *bytes_read, &buf);
|
||||
else
|
||||
uv__pipe_read_error_or_eof(loop, handle, r, buf);
|
||||
|
||||
return bytes_read;
|
||||
return more;
|
||||
}
|
||||
|
||||
|
||||
static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
uint32_t* data_remaining = &handle->pipe.conn.ipc_data_frame.payload_remaining;
|
||||
int err;
|
||||
static int uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
uint32_t* data_remaining;
|
||||
DWORD err;
|
||||
DWORD more;
|
||||
DWORD bytes_read;
|
||||
|
||||
data_remaining = &handle->pipe.conn.ipc_data_frame.payload_remaining;
|
||||
|
||||
if (*data_remaining > 0) {
|
||||
/* Read frame data payload. */
|
||||
DWORD bytes_read =
|
||||
uv__pipe_read_data(loop, handle, *data_remaining, *data_remaining);
|
||||
bytes_read = *data_remaining;
|
||||
more = uv__pipe_read_data(loop, handle, &bytes_read, bytes_read);
|
||||
*data_remaining -= bytes_read;
|
||||
return bytes_read;
|
||||
|
||||
} else {
|
||||
/* Start of a new IPC frame. */
|
||||
@@ -1997,7 +2051,7 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
|
||||
/* Read the IPC frame header. */
|
||||
err = uv__pipe_read_exactly(
|
||||
handle->handle, &frame_header, sizeof frame_header);
|
||||
handle, &frame_header, sizeof frame_header);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
@@ -2033,21 +2087,24 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
|
||||
/* If no socket xfer info follows, return here. Data will be read in a
|
||||
* subsequent invocation of uv__pipe_read_ipc(). */
|
||||
if (xfer_type == UV__IPC_SOCKET_XFER_NONE)
|
||||
return sizeof frame_header; /* Number of bytes read. */
|
||||
if (xfer_type != UV__IPC_SOCKET_XFER_NONE) {
|
||||
/* Read transferred socket information. */
|
||||
err = uv__pipe_read_exactly(handle, &xfer_info, sizeof xfer_info);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
/* Read transferred socket information. */
|
||||
err = uv__pipe_read_exactly(handle->handle, &xfer_info, sizeof xfer_info);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
/* Store the pending socket info. */
|
||||
uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info);
|
||||
|
||||
/* Return number of bytes read. */
|
||||
return sizeof frame_header + sizeof xfer_info;
|
||||
/* Store the pending socket info. */
|
||||
uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return whether the caller should immediately try another read call to get
|
||||
* more data. Calling uv__pipe_read_exactly will hang if there isn't data
|
||||
* available, so we cannot do this unless we are guaranteed not to reach that.
|
||||
*/
|
||||
more = *data_remaining > 0;
|
||||
return more;
|
||||
|
||||
invalid:
|
||||
/* Invalid frame. */
|
||||
err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */
|
||||
@@ -2061,12 +2118,20 @@ error:
|
||||
void uv__process_pipe_read_req(uv_loop_t* loop,
|
||||
uv_pipe_t* handle,
|
||||
uv_req_t* req) {
|
||||
DWORD err;
|
||||
DWORD more;
|
||||
DWORD bytes_requested;
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
handle->flags &= ~(UV_HANDLE_READ_PENDING | UV_HANDLE_CANCELLATION_PENDING);
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
eof_timer_stop(handle);
|
||||
|
||||
if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
|
||||
UnregisterWait(handle->read_req.wait_handle);
|
||||
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* At this point, we're done with bookkeeping. If the user has stopped
|
||||
* reading the pipe in the meantime, there is nothing left to do, since there
|
||||
* is no callback that we can call. */
|
||||
@@ -2075,7 +2140,7 @@ void uv__process_pipe_read_req(uv_loop_t* loop,
|
||||
|
||||
if (!REQ_SUCCESS(req)) {
|
||||
/* An error occurred doing the zero-read. */
|
||||
DWORD err = GET_REQ_ERROR(req);
|
||||
err = GET_REQ_ERROR(req);
|
||||
|
||||
/* If the read was cancelled by uv__pipe_interrupt_read(), the request may
|
||||
* indicate an ERROR_OPERATION_ABORTED error. This error isn't relevant to
|
||||
@@ -2086,34 +2151,18 @@ void uv__process_pipe_read_req(uv_loop_t* loop,
|
||||
} else {
|
||||
/* The zero-read completed without error, indicating there is data
|
||||
* available in the kernel buffer. */
|
||||
DWORD avail;
|
||||
|
||||
/* 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_);
|
||||
|
||||
/* Read until we've either read all the bytes available, or the 'reading'
|
||||
* flag is cleared. */
|
||||
while (avail > 0 && handle->flags & UV_HANDLE_READING) {
|
||||
while (handle->flags & UV_HANDLE_READING) {
|
||||
bytes_requested = 65536;
|
||||
/* Depending on the type of pipe, read either IPC frames or raw data. */
|
||||
DWORD bytes_read =
|
||||
handle->ipc ? uv__pipe_read_ipc(loop, handle)
|
||||
: uv__pipe_read_data(loop, handle, avail, (DWORD) -1);
|
||||
if (handle->ipc)
|
||||
more = uv__pipe_read_ipc(loop, handle);
|
||||
else
|
||||
more = uv__pipe_read_data(loop, handle, &bytes_requested, INT32_MAX);
|
||||
|
||||
/* If no bytes were read, treat this as an indication that an error
|
||||
* occurred, and break out of the read loop. */
|
||||
if (bytes_read == 0)
|
||||
if (more == 0)
|
||||
break;
|
||||
|
||||
/* It is possible that more bytes were read than we thought were
|
||||
* available. To prevent `avail` from underflowing, break out of the loop
|
||||
* if this is the case. */
|
||||
if (bytes_read > avail)
|
||||
break;
|
||||
|
||||
/* Recompute the number of bytes available. */
|
||||
avail -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2134,17 +2183,15 @@ void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
assert(handle->write_queue_size >= req->u.io.queued_bytes);
|
||||
handle->write_queue_size -= req->u.io.queued_bytes;
|
||||
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
UNREGISTER_HANDLE_REQ(loop, handle);
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
if (req->wait_handle != INVALID_HANDLE_VALUE) {
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
if (req->wait_handle != INVALID_HANDLE_VALUE) {
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
|
||||
err = GET_REQ_ERROR(req);
|
||||
@@ -2221,7 +2268,7 @@ void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
UNREGISTER_HANDLE_REQ(loop, handle);
|
||||
|
||||
err = 0;
|
||||
if (REQ_SUCCESS(req)) {
|
||||
@@ -2253,7 +2300,7 @@ void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
|
||||
/* Clear the shutdown_req field so we don't go here again. */
|
||||
handle->stream.conn.shutdown_req = NULL;
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
UNREGISTER_HANDLE_REQ(loop, handle);
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* Already closing. Cancel the shutdown. */
|
||||
|
||||
@@ -46,12 +46,12 @@
|
||||
#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
|
||||
*((unsigned char*) (buffer) + sizeof(int) + fd)
|
||||
|
||||
#define CHILD_STDIO_HANDLE(buffer, fd) \
|
||||
*((HANDLE*) ((unsigned char*) (buffer) + \
|
||||
sizeof(int) + \
|
||||
sizeof(unsigned char) * \
|
||||
CHILD_STDIO_COUNT((buffer)) + \
|
||||
sizeof(HANDLE) * (fd)))
|
||||
#define CHILD_STDIO_HANDLE(buffer, fd) \
|
||||
((void*) ((unsigned char*) (buffer) + \
|
||||
sizeof(int) + \
|
||||
sizeof(unsigned char) * \
|
||||
CHILD_STDIO_COUNT((buffer)) + \
|
||||
sizeof(HANDLE) * (fd)))
|
||||
|
||||
|
||||
/* CRT file descriptor mode flags */
|
||||
@@ -194,7 +194,7 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
CHILD_STDIO_COUNT(buffer) = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
|
||||
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
|
||||
memset(CHILD_STDIO_HANDLE(buffer, i), 0xFF, sizeof(HANDLE));
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
@@ -215,14 +215,15 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
* handles in the stdio buffer are initialized with.
|
||||
* INVALID_HANDLE_VALUE, which should be okay. */
|
||||
if (i <= 2) {
|
||||
HANDLE nul;
|
||||
DWORD access = (i == 0) ? FILE_GENERIC_READ :
|
||||
FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
||||
|
||||
err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
|
||||
access);
|
||||
err = uv__create_nul_handle(&nul, access);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
memcpy(CHILD_STDIO_HANDLE(buffer, i), &nul, sizeof(HANDLE));
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
|
||||
}
|
||||
break;
|
||||
@@ -247,7 +248,7 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
|
||||
memcpy(CHILD_STDIO_HANDLE(buffer, i), &child_pipe, sizeof(HANDLE));
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
|
||||
break;
|
||||
}
|
||||
@@ -263,7 +264,7 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
* error. */
|
||||
if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
|
||||
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
|
||||
memset(CHILD_STDIO_HANDLE(buffer, i), 0xFF, sizeof(HANDLE));
|
||||
break;
|
||||
}
|
||||
goto error;
|
||||
@@ -298,7 +299,7 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
|
||||
memcpy(CHILD_STDIO_HANDLE(buffer, i), &child_handle, sizeof(HANDLE));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -334,7 +335,7 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
|
||||
memcpy(CHILD_STDIO_HANDLE(buffer, i), &child_handle, sizeof(HANDLE));
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
|
||||
break;
|
||||
}
|
||||
@@ -359,7 +360,7 @@ void uv__stdio_destroy(BYTE* buffer) {
|
||||
|
||||
count = CHILD_STDIO_COUNT(buffer);
|
||||
for (i = 0; i < count; i++) {
|
||||
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
|
||||
HANDLE handle = uv__stdio_handle(buffer, i);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle);
|
||||
}
|
||||
@@ -374,7 +375,7 @@ void uv__stdio_noinherit(BYTE* buffer) {
|
||||
|
||||
count = CHILD_STDIO_COUNT(buffer);
|
||||
for (i = 0; i < count; i++) {
|
||||
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
|
||||
HANDLE handle = uv__stdio_handle(buffer, i);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
|
||||
}
|
||||
@@ -412,5 +413,7 @@ WORD uv__stdio_size(BYTE* buffer) {
|
||||
|
||||
|
||||
HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
|
||||
return CHILD_STDIO_HANDLE(buffer, fd);
|
||||
HANDLE handle;
|
||||
memcpy(&handle, CHILD_STDIO_HANDLE(buffer, fd), sizeof(HANDLE));
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include <signal.h>
|
||||
#include <limits.h>
|
||||
#include <wchar.h>
|
||||
#include <malloc.h> /* _alloca */
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
@@ -597,11 +596,9 @@ error:
|
||||
}
|
||||
|
||||
|
||||
int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
|
||||
static int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
|
||||
const wchar_t* a_eq;
|
||||
const wchar_t* b_eq;
|
||||
wchar_t* A;
|
||||
wchar_t* B;
|
||||
int nb;
|
||||
int r;
|
||||
|
||||
@@ -616,27 +613,8 @@ int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
|
||||
assert(b_eq);
|
||||
nb = b_eq - b;
|
||||
|
||||
A = (wchar_t*)_alloca((na+1) * sizeof(wchar_t));
|
||||
B = (wchar_t*)_alloca((nb+1) * sizeof(wchar_t));
|
||||
|
||||
r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
|
||||
assert(r==na);
|
||||
A[na] = L'\0';
|
||||
r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
|
||||
assert(r==nb);
|
||||
B[nb] = L'\0';
|
||||
|
||||
for (;;) {
|
||||
wchar_t AA = *A++;
|
||||
wchar_t BB = *B++;
|
||||
if (AA < BB) {
|
||||
return -1;
|
||||
} else if (AA > BB) {
|
||||
return 1;
|
||||
} else if (!AA && !BB) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
r = CompareStringOrdinal(a, na, b, nb, /*case insensitive*/TRUE);
|
||||
return r - CSTR_EQUAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -675,6 +653,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
WCHAR* dst_copy;
|
||||
WCHAR** ptr_copy;
|
||||
WCHAR** env_copy;
|
||||
char* p;
|
||||
size_t required_vars_value_len[ARRAY_SIZE(required_vars)];
|
||||
|
||||
/* first pass: determine size in UTF-16 */
|
||||
@@ -690,11 +669,13 @@ 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 == NULL && env_len > 0) {
|
||||
len = env_block_count * sizeof(WCHAR*);
|
||||
p = (char*)uv__malloc(len + env_len * sizeof(WCHAR));
|
||||
if (p == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
env_copy = (WCHAR**)_alloca(env_block_count * sizeof(WCHAR*));
|
||||
env_copy = (WCHAR**) &p[0];
|
||||
dst_copy = (WCHAR*) &p[len];
|
||||
|
||||
ptr = dst_copy;
|
||||
ptr_copy = env_copy;
|
||||
@@ -744,7 +725,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
/* final pass: copy, in sort order, and inserting required variables */
|
||||
dst = (WCHAR*)uv__malloc((1+env_len) * sizeof(WCHAR));
|
||||
if (!dst) {
|
||||
uv__free(dst_copy);
|
||||
uv__free(p);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
@@ -789,7 +770,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
assert(env_len == (size_t) (ptr - dst));
|
||||
*ptr = L'\0';
|
||||
|
||||
uv__free(dst_copy);
|
||||
uv__free(p);
|
||||
*dst_ptr = dst;
|
||||
return 0;
|
||||
}
|
||||
@@ -1185,16 +1166,34 @@ static int uv__kill(HANDLE process_handle, int signum) {
|
||||
/* Unconditionally terminate the process. On Windows, killed processes
|
||||
* normally return 1. */
|
||||
int err;
|
||||
DWORD status;
|
||||
|
||||
if (TerminateProcess(process_handle, 1))
|
||||
return 0;
|
||||
|
||||
/* If the process already exited before TerminateProcess was called,.
|
||||
/* If the process already exited before TerminateProcess was called,
|
||||
* TerminateProcess will fail with ERROR_ACCESS_DENIED. */
|
||||
err = GetLastError();
|
||||
if (err == ERROR_ACCESS_DENIED &&
|
||||
WaitForSingleObject(process_handle, 0) == WAIT_OBJECT_0) {
|
||||
return UV_ESRCH;
|
||||
if (err == ERROR_ACCESS_DENIED) {
|
||||
/* First check using GetExitCodeProcess() with status different from
|
||||
* STILL_ACTIVE (259). This check can be set incorrectly by the process,
|
||||
* though that is uncommon. */
|
||||
if (GetExitCodeProcess(process_handle, &status) &&
|
||||
status != STILL_ACTIVE) {
|
||||
return UV_ESRCH;
|
||||
}
|
||||
|
||||
/* But the process could have exited with code == STILL_ACTIVE, use then
|
||||
* WaitForSingleObject with timeout zero. This is prone to a race
|
||||
* condition as it could return WAIT_TIMEOUT because the handle might
|
||||
* not have been signaled yet.That would result in returning the wrong
|
||||
* error code here (UV_EACCES instead of UV_ESRCH), but we cannot fix
|
||||
* the kernel synchronization issue that TerminateProcess is
|
||||
* inconsistent with WaitForSingleObject with just the APIs available to
|
||||
* us in user space. */
|
||||
if (WaitForSingleObject(process_handle, 0) == WAIT_OBJECT_0) {
|
||||
return UV_ESRCH;
|
||||
}
|
||||
}
|
||||
|
||||
return uv_translate_sys_error(err);
|
||||
@@ -1202,6 +1201,14 @@ static int uv__kill(HANDLE process_handle, int signum) {
|
||||
|
||||
case 0: {
|
||||
/* Health check: is the process still alive? */
|
||||
DWORD status;
|
||||
|
||||
if (!GetExitCodeProcess(process_handle, &status))
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
if (status != STILL_ACTIVE)
|
||||
return UV_ESRCH;
|
||||
|
||||
switch (WaitForSingleObject(process_handle, 0)) {
|
||||
case WAIT_OBJECT_0:
|
||||
return UV_ESRCH;
|
||||
|
||||
@@ -53,16 +53,16 @@
|
||||
(uv__ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
|
||||
|
||||
|
||||
#define REGISTER_HANDLE_REQ(loop, handle, req) \
|
||||
#define REGISTER_HANDLE_REQ(loop, handle) \
|
||||
do { \
|
||||
INCREASE_ACTIVE_COUNT((loop), (handle)); \
|
||||
uv__req_register((loop), (req)); \
|
||||
uv__req_register((loop)); \
|
||||
} while (0)
|
||||
|
||||
#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
|
||||
#define UNREGISTER_HANDLE_REQ(loop, handle) \
|
||||
do { \
|
||||
DECREASE_ACTIVE_COUNT((loop), (handle)); \
|
||||
uv__req_unregister((loop), (req)); \
|
||||
uv__req_unregister((loop)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
|
||||
INLINE static uv_req_t* uv__overlapped_to_req(OVERLAPPED* overlapped) {
|
||||
return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
|
||||
return container_of(overlapped, uv_req_t, u.io.overlapped);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ int uv__signal_dispatch(int signum) {
|
||||
|
||||
for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
|
||||
handle != NULL && handle->signum == signum;
|
||||
handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
|
||||
handle = RB_NEXT(uv_signal_tree_s, handle)) {
|
||||
unsigned long previous = InterlockedExchange(
|
||||
(volatile LONG*) &handle->pending_signum, signum);
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ int uv_write(uv_write_t* req,
|
||||
case UV_NAMED_PIPE:
|
||||
err = uv__pipe_write(
|
||||
loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb);
|
||||
break;
|
||||
return uv_translate_write_sys_error(err);
|
||||
case UV_TTY:
|
||||
err = uv__tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
|
||||
break;
|
||||
@@ -164,7 +164,7 @@ int uv_write2(uv_write_t* req,
|
||||
|
||||
err = uv__pipe_write(
|
||||
loop, req, (uv_pipe_t*) handle, bufs, nbufs, send_handle, cb);
|
||||
return uv_translate_sys_error(err);
|
||||
return uv_translate_write_sys_error(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
|
||||
handle->flags &= ~UV_HANDLE_WRITABLE;
|
||||
handle->stream.conn.shutdown_req = req;
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
|
||||
if (handle->stream.conn.write_reqs_pending == 0) {
|
||||
if (handle->type == UV_NAMED_PIPE)
|
||||
|
||||
@@ -58,11 +58,17 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
if (enable && setsockopt(socket,
|
||||
IPPROTO_TCP,
|
||||
TCP_KEEPALIVE,
|
||||
(const char*)&delay,
|
||||
sizeof delay) == -1) {
|
||||
if (!enable)
|
||||
return 0;
|
||||
|
||||
if (delay < 1)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setsockopt(socket,
|
||||
IPPROTO_TCP,
|
||||
TCP_KEEPALIVE,
|
||||
(const char*)&delay,
|
||||
sizeof delay) == -1) {
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
@@ -206,7 +212,7 @@ void uv__process_tcp_shutdown_req(uv_loop_t* loop, uv_tcp_t* stream, uv_shutdown
|
||||
assert(stream->flags & UV_HANDLE_CONNECTION);
|
||||
|
||||
stream->stream.conn.shutdown_req = NULL;
|
||||
UNREGISTER_HANDLE_REQ(loop, stream, req);
|
||||
UNREGISTER_HANDLE_REQ(loop, stream);
|
||||
|
||||
err = 0;
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
@@ -286,6 +292,12 @@ static int uv__tcp_try_bind(uv_tcp_t* handle,
|
||||
DWORD err;
|
||||
int r;
|
||||
|
||||
/* There is no SO_REUSEPORT on Windows, Windows only knows SO_REUSEADDR.
|
||||
* so we just return an error directly when UV_TCP_REUSEPORT is requested
|
||||
* for binding the socket. */
|
||||
if (flags & UV_TCP_REUSEPORT)
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
|
||||
if (handle->socket == INVALID_SOCKET) {
|
||||
SOCKET sock;
|
||||
|
||||
@@ -822,7 +834,7 @@ out:
|
||||
if (handle->delayed_error != 0) {
|
||||
/* Process the req without IOCP. */
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
return 0;
|
||||
}
|
||||
@@ -838,12 +850,12 @@ out:
|
||||
if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
|
||||
/* Process the req without IOCP. */
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
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++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
} else {
|
||||
return WSAGetLastError();
|
||||
}
|
||||
@@ -913,14 +925,14 @@ int uv__tcp_write(uv_loop_t* loop,
|
||||
req->u.io.queued_bytes = 0;
|
||||
handle->reqs_pending++;
|
||||
handle->stream.conn.write_reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
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);
|
||||
handle->reqs_pending++;
|
||||
handle->stream.conn.write_reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
handle->write_queue_size += req->u.io.queued_bytes;
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
|
||||
!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
@@ -934,7 +946,7 @@ int uv__tcp_write(uv_loop_t* loop,
|
||||
req->u.io.queued_bytes = 0;
|
||||
handle->reqs_pending++;
|
||||
handle->stream.conn.write_reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
}
|
||||
@@ -1105,7 +1117,7 @@ void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
assert(handle->write_queue_size >= req->u.io.queued_bytes);
|
||||
handle->write_queue_size -= req->u.io.queued_bytes;
|
||||
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
UNREGISTER_HANDLE_REQ(loop, handle);
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
if (req->wait_handle != INVALID_HANDLE_VALUE) {
|
||||
@@ -1197,7 +1209,7 @@ void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
UNREGISTER_HANDLE_REQ(loop, handle);
|
||||
|
||||
err = 0;
|
||||
if (handle->delayed_error) {
|
||||
@@ -1551,11 +1563,6 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
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;
|
||||
|
||||
@@ -32,45 +32,23 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
|
||||
DWORD result;
|
||||
HANDLE existing_event, created_event;
|
||||
typedef void (*uv__once_cb)(void);
|
||||
|
||||
created_event = CreateEvent(NULL, 1, 0, NULL);
|
||||
if (created_event == 0) {
|
||||
/* Could fail in a low-memory situation? */
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
typedef struct {
|
||||
uv__once_cb callback;
|
||||
} uv__once_data_t;
|
||||
|
||||
existing_event = InterlockedCompareExchangePointer(&guard->event,
|
||||
created_event,
|
||||
NULL);
|
||||
static BOOL WINAPI uv__once_inner(INIT_ONCE *once, void* param, void** context) {
|
||||
uv__once_data_t* data = (uv__once_data_t*)param;
|
||||
|
||||
if (existing_event == NULL) {
|
||||
/* We won the race */
|
||||
callback();
|
||||
data->callback();
|
||||
|
||||
result = SetEvent(created_event);
|
||||
assert(result);
|
||||
guard->ran = 1;
|
||||
|
||||
} else {
|
||||
/* We lost the race. Destroy the event we created and wait for the existing
|
||||
* one to become signaled. */
|
||||
CloseHandle(created_event);
|
||||
result = WaitForSingleObject(existing_event, INFINITE);
|
||||
assert(result == WAIT_OBJECT_0);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void uv_once(uv_once_t* guard, void (*callback)(void)) {
|
||||
/* Fast case - avoid WaitForSingleObject. */
|
||||
if (guard->ran) {
|
||||
return;
|
||||
}
|
||||
|
||||
uv__once_inner(guard, callback);
|
||||
void uv_once(uv_once_t* guard, uv__once_cb callback) {
|
||||
uv__once_data_t data = { .callback = callback };
|
||||
InitOnceExecuteOnce(&guard->init_once, uv__once_inner, (void*) &data, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2187,7 +2187,7 @@ int uv__tty_write(uv_loop_t* loop,
|
||||
|
||||
handle->reqs_pending++;
|
||||
handle->stream.conn.write_reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
|
||||
req->u.io.queued_bytes = 0;
|
||||
|
||||
@@ -2223,7 +2223,7 @@ void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
int err;
|
||||
|
||||
handle->write_queue_size -= req->u.io.queued_bytes;
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
UNREGISTER_HANDLE_REQ(loop, handle);
|
||||
|
||||
if (req->cb) {
|
||||
err = GET_REQ_ERROR(req);
|
||||
@@ -2267,7 +2267,7 @@ void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown
|
||||
assert(req);
|
||||
|
||||
stream->stream.conn.shutdown_req = NULL;
|
||||
UNREGISTER_HANDLE_REQ(loop, stream, req);
|
||||
UNREGISTER_HANDLE_REQ(loop, stream);
|
||||
|
||||
/* TTY shutdown is really just a no-op */
|
||||
if (req->cb) {
|
||||
@@ -2384,8 +2384,8 @@ static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) {
|
||||
/* Make sure to not overwhelm the system with resize events */
|
||||
Sleep(33);
|
||||
WaitForSingleObject(uv__tty_console_resized, INFINITE);
|
||||
uv__tty_console_signal_resize();
|
||||
ResetEvent(uv__tty_console_resized);
|
||||
uv__tty_console_signal_resize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -200,6 +200,12 @@ static int uv__udp_maybe_bind(uv_udp_t* handle,
|
||||
if (handle->flags & UV_HANDLE_BOUND)
|
||||
return 0;
|
||||
|
||||
/* There is no SO_REUSEPORT on Windows, Windows only knows SO_REUSEADDR.
|
||||
* so we just return an error directly when UV_UDP_REUSEPORT is requested
|
||||
* for binding the socket. */
|
||||
if (flags & UV_UDP_REUSEPORT)
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
|
||||
if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
|
||||
/* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
@@ -376,7 +382,7 @@ static int uv__send(uv_udp_send_t* req,
|
||||
handle->reqs_pending++;
|
||||
handle->send_queue_size += req->u.io.queued_bytes;
|
||||
handle->send_queue_count++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
uv__insert_pending_req(loop, (uv_req_t*)req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||
/* Request queued by the kernel. */
|
||||
@@ -384,7 +390,7 @@ static int uv__send(uv_udp_send_t* req,
|
||||
handle->reqs_pending++;
|
||||
handle->send_queue_size += req->u.io.queued_bytes;
|
||||
handle->send_queue_count++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
REGISTER_HANDLE_REQ(loop, handle);
|
||||
} else {
|
||||
/* Send failed due to an error. */
|
||||
return WSAGetLastError();
|
||||
@@ -527,7 +533,7 @@ void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
handle->send_queue_size -= req->u.io.queued_bytes;
|
||||
handle->send_queue_count--;
|
||||
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
UNREGISTER_HANDLE_REQ(loop, handle);
|
||||
|
||||
if (req->cb) {
|
||||
err = 0;
|
||||
|
||||
@@ -326,25 +326,19 @@ uv_pid_t uv_os_getpid(void) {
|
||||
|
||||
|
||||
uv_pid_t uv_os_getppid(void) {
|
||||
int parent_pid = -1;
|
||||
HANDLE handle;
|
||||
PROCESSENTRY32 pe;
|
||||
DWORD current_pid = GetCurrentProcessId();
|
||||
NTSTATUS nt_status;
|
||||
PROCESS_BASIC_INFORMATION basic_info;
|
||||
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
|
||||
if (Process32First(handle, &pe)) {
|
||||
do {
|
||||
if (pe.th32ProcessID == current_pid) {
|
||||
parent_pid = pe.th32ParentProcessID;
|
||||
break;
|
||||
}
|
||||
} while( Process32Next(handle, &pe));
|
||||
nt_status = pNtQueryInformationProcess(GetCurrentProcess(),
|
||||
ProcessBasicInformation,
|
||||
&basic_info,
|
||||
sizeof(basic_info),
|
||||
NULL);
|
||||
if (NT_SUCCESS(nt_status)) {
|
||||
return basic_info.InheritedFromUniqueProcessId;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return parent_pid;
|
||||
}
|
||||
|
||||
|
||||
@@ -522,19 +516,23 @@ int uv_uptime(double* uptime) {
|
||||
|
||||
|
||||
unsigned int uv_available_parallelism(void) {
|
||||
SYSTEM_INFO info;
|
||||
unsigned rc;
|
||||
DWORD_PTR procmask;
|
||||
DWORD_PTR sysmask;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
/* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
|
||||
* with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
|
||||
*/
|
||||
GetSystemInfo(&info);
|
||||
count = 0;
|
||||
if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask))
|
||||
for (i = 0; i < 8 * sizeof(procmask); i++)
|
||||
count += 1 & (procmask >> i);
|
||||
|
||||
rc = info.dwNumberOfProcessors;
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
if (count > 0)
|
||||
return count;
|
||||
|
||||
return rc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -953,8 +951,13 @@ int uv_os_homedir(char* buffer, size_t* size) {
|
||||
r = uv_os_getenv("USERPROFILE", buffer, size);
|
||||
|
||||
/* Don't return an error if USERPROFILE was not found. */
|
||||
if (r != UV_ENOENT)
|
||||
if (r != UV_ENOENT) {
|
||||
/* USERPROFILE is empty or invalid */
|
||||
if (r == 0 && *size < 3) {
|
||||
return UV_ENOENT;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* USERPROFILE is not set, so call uv_os_get_passwd() */
|
||||
r = uv_os_get_passwd(&pwd);
|
||||
@@ -991,6 +994,12 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
if (len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* tmp path is empty or invalid */
|
||||
if (len < 3) {
|
||||
return UV_ENOENT;
|
||||
}
|
||||
|
||||
/* Include space for terminating null char. */
|
||||
len += 1;
|
||||
path = (wchar_t*)uv__malloc(len * sizeof(wchar_t));
|
||||
@@ -1270,6 +1279,9 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
len = GetEnvironmentVariableW(name_w, var, varlen);
|
||||
|
||||
if (len == 0)
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
|
||||
if (len < varlen)
|
||||
break;
|
||||
|
||||
@@ -1291,15 +1303,8 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
uv__free(name_w);
|
||||
name_w = NULL;
|
||||
|
||||
if (len == 0) {
|
||||
r = GetLastError();
|
||||
if (r != ERROR_SUCCESS) {
|
||||
r = uv_translate_sys_error(r);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
r = uv__copy_utf16_to_utf8(var, len, buffer, size);
|
||||
if (r == 0)
|
||||
r = uv__copy_utf16_to_utf8(var, len, buffer, size);
|
||||
|
||||
fail:
|
||||
|
||||
@@ -1539,20 +1544,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
|
||||
os_info.dwOSVersionInfoSize = sizeof(os_info);
|
||||
os_info.szCSDVersion[0] = L'\0';
|
||||
|
||||
/* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
|
||||
if RtlGetVersion() is not available. */
|
||||
if (pRtlGetVersion) {
|
||||
pRtlGetVersion(&os_info);
|
||||
} else {
|
||||
/* Silence GetVersionEx() deprecation warning. */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
if (GetVersionExW(&os_info) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
pRtlGetVersion(&os_info);
|
||||
|
||||
/* Populate the version field. */
|
||||
version_size = 0;
|
||||
|
||||
@@ -48,12 +48,16 @@ sSetWinEventHook pSetWinEventHook;
|
||||
/* ws2_32.dll function pointer */
|
||||
uv_sGetHostNameW pGetHostNameW;
|
||||
|
||||
/* api-ms-win-core-file-l2-1-4.dll function pointer */
|
||||
sGetFileInformationByName pGetFileInformationByName;
|
||||
|
||||
void uv__winapi_init(void) {
|
||||
HMODULE ntdll_module;
|
||||
HMODULE powrprof_module;
|
||||
HMODULE user32_module;
|
||||
HMODULE kernel32_module;
|
||||
HMODULE ws2_32_module;
|
||||
HMODULE api_win_core_file_module;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
@@ -99,7 +103,7 @@ void uv__winapi_init(void) {
|
||||
|
||||
pNtQueryDirectoryFile = (sNtQueryDirectoryFile)
|
||||
GetProcAddress(ntdll_module, "NtQueryDirectoryFile");
|
||||
if (pNtQueryVolumeInformationFile == NULL) {
|
||||
if (pNtQueryDirectoryFile == NULL) {
|
||||
uv_fatal_error(GetLastError(), "GetProcAddress");
|
||||
}
|
||||
|
||||
@@ -144,4 +148,10 @@ void uv__winapi_init(void) {
|
||||
ws2_32_module,
|
||||
"GetHostNameW");
|
||||
}
|
||||
|
||||
api_win_core_file_module = GetModuleHandleA("api-ms-win-core-file-l2-1-4.dll");
|
||||
if (api_win_core_file_module != NULL) {
|
||||
pGetFileInformationByName = (sGetFileInformationByName)GetProcAddress(
|
||||
api_win_core_file_module, "GetFileInformationByName");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4125,6 +4125,31 @@ typedef const UNICODE_STRING *PCUNICODE_STRING;
|
||||
# define DEVICE_TYPE DWORD
|
||||
#endif
|
||||
|
||||
#ifndef NTDDI_WIN11_ZN
|
||||
# define NTDDI_WIN11_ZN 0x0A00000E
|
||||
#endif
|
||||
|
||||
/* API is defined in newer SDKS */
|
||||
#if (NTDDI_VERSION < NTDDI_WIN11_ZN)
|
||||
typedef struct _FILE_STAT_BASIC_INFORMATION {
|
||||
LARGE_INTEGER FileId;
|
||||
LARGE_INTEGER CreationTime;
|
||||
LARGE_INTEGER LastAccessTime;
|
||||
LARGE_INTEGER LastWriteTime;
|
||||
LARGE_INTEGER ChangeTime;
|
||||
LARGE_INTEGER AllocationSize;
|
||||
LARGE_INTEGER EndOfFile;
|
||||
ULONG FileAttributes;
|
||||
ULONG ReparseTag;
|
||||
ULONG NumberOfLinks;
|
||||
ULONG DeviceType;
|
||||
ULONG DeviceCharacteristics;
|
||||
ULONG Reserved;
|
||||
FILE_ID_128 FileId128;
|
||||
LARGE_INTEGER VolumeSerialNumber;
|
||||
} FILE_STAT_BASIC_INFORMATION;
|
||||
#endif
|
||||
|
||||
/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
|
||||
* not.
|
||||
*/
|
||||
@@ -4224,6 +4249,15 @@ typedef enum _FILE_INFORMATION_CLASS {
|
||||
FileNumaNodeInformation,
|
||||
FileStandardLinkInformation,
|
||||
FileRemoteProtocolInformation,
|
||||
FileRenameInformationBypassAccessCheck,
|
||||
FileLinkInformationBypassAccessCheck,
|
||||
FileVolumeNameInformation,
|
||||
FileIdInformation,
|
||||
FileIdExtdDirectoryInformation,
|
||||
FileReplaceCompletionInformation,
|
||||
FileHardLinkFullIdInformation,
|
||||
FileIdExtdBothDirectoryInformation,
|
||||
FileDispositionInformationEx, /* based on https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-_file_information_class */
|
||||
FileMaximumInformation
|
||||
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
|
||||
|
||||
@@ -4323,6 +4357,10 @@ typedef struct _FILE_DISPOSITION_INFORMATION {
|
||||
BOOLEAN DeleteFile;
|
||||
} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
|
||||
|
||||
typedef struct _FILE_DISPOSITION_INFORMATION_EX {
|
||||
DWORD Flags;
|
||||
} FILE_DISPOSITION_INFORMATION_EX, *PFILE_DISPOSITION_INFORMATION_EX;
|
||||
|
||||
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
|
||||
ULONG NamedPipeType;
|
||||
ULONG NamedPipeConfiguration;
|
||||
@@ -4427,6 +4465,14 @@ typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION {
|
||||
ULONG ByteOffsetForPartitionAlignment;
|
||||
} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;
|
||||
|
||||
typedef struct _PROCESS_BASIC_INFORMATION {
|
||||
PVOID Reserved1;
|
||||
PVOID PebBaseAddress;
|
||||
PVOID Reserved2[2];
|
||||
ULONG_PTR UniqueProcessId;
|
||||
ULONG_PTR InheritedFromUniqueProcessId;
|
||||
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
|
||||
|
||||
typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
|
||||
LARGE_INTEGER IdleTime;
|
||||
LARGE_INTEGER KernelTime;
|
||||
@@ -4440,6 +4486,10 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
|
||||
# define SystemProcessorPerformanceInformation 8
|
||||
#endif
|
||||
|
||||
#ifndef ProcessBasicInformation
|
||||
# define ProcessBasicInformation 0
|
||||
#endif
|
||||
|
||||
#ifndef ProcessConsoleHostProcess
|
||||
# define ProcessConsoleHostProcess 49
|
||||
#endif
|
||||
@@ -4739,6 +4789,24 @@ typedef struct _TCP_INITIAL_RTO_PARAMETERS {
|
||||
# define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17)
|
||||
#endif
|
||||
|
||||
/* from winnt.h */
|
||||
/* API is defined in newer SDKS */
|
||||
#if (NTDDI_VERSION < NTDDI_WIN11_ZN)
|
||||
typedef enum _FILE_INFO_BY_NAME_CLASS {
|
||||
FileStatByNameInfo,
|
||||
FileStatLxByNameInfo,
|
||||
FileCaseSensitiveByNameInfo,
|
||||
FileStatBasicByNameInfo,
|
||||
MaximumFileInfoByNameClass
|
||||
} FILE_INFO_BY_NAME_CLASS;
|
||||
#endif
|
||||
|
||||
typedef BOOL(WINAPI* sGetFileInformationByName)(
|
||||
PCWSTR FileName,
|
||||
FILE_INFO_BY_NAME_CLASS FileInformationClass,
|
||||
PVOID FileInfoBuffer,
|
||||
ULONG FileInfoBufferSize);
|
||||
|
||||
/* Ntdll function pointers */
|
||||
extern sRtlGetVersion pRtlGetVersion;
|
||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
@@ -4759,6 +4827,9 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi
|
||||
/* User32.dll function pointer */
|
||||
extern sSetWinEventHook pSetWinEventHook;
|
||||
|
||||
/* api-ms-win-core-file-l2-1-4.dll function pointers */
|
||||
extern sGetFileInformationByName pGetFileInformationByName;
|
||||
|
||||
/* ws2_32.dll function pointer */
|
||||
/* mingw doesn't have this definition, so let's declare it here locally */
|
||||
typedef int (WINAPI *uv_sGetHostNameW)
|
||||
|
||||
Reference in New Issue
Block a user