[upstream_utils] Upgrade to libuv 1.49.0 (#7129)

This commit is contained in:
Tyler Veness
2024-09-27 12:00:54 -07:00
committed by GitHub
parent f0a1955fd7
commit eab93f4fdc
57 changed files with 2209 additions and 1272 deletions

View File

@@ -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.0"
libuv = Lib(name, url, tag, copy_upstream_src)
libuv.main()

View File

@@ -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 b7981d6194969b74751b97747cfc7bc1d679536b..0ad8026905453e27fff8f720913fdda2544baef2 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

View File

@@ -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 d8c09f5e41ff96dae4d0df9982f227eaac3c8576..d9f868b13b4fa2c340c542fe567b4193cf079748 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 529c783e6e93200e52dab98ea9a3c1e0aea557ce..0bf3736cd682e43beedcf4c701a147787f1329fc 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)) {
@@ -396,8 +396,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 96c8b1dfe060e896f768493448ec20cfb9203592..cfb0c6eebf2fb231f610020be35187a488127477 100644
--- a/src/unix/linux.c
+++ b/src/unix/linux.c
@@ -2294,7 +2294,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 b90d2368aa769cb66f9367e97f004fa8bd4da3c0..a4b47fe5ec4135059b8e08be6a232ddd7798bebe 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 8226369294299fd2a9d7d05a91d3d711015b7fd0..43ea270e618fd9fd0c0cb30981a3425967b6dbcd 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 @@

View File

@@ -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 0bf3736cd682e43beedcf4c701a147787f1329fc..c1ead096f7d43b9e7a0daf8de2b65cc82bec7eaf 100644
--- a/src/unix/internal.h
+++ b/src/unix/internal.h
@@ -233,6 +233,8 @@ struct uv__statx {
@@ -241,6 +241,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 a4b47fe5ec4135059b8e08be6a232ddd7798bebe..af07d092a65909ac4948c679b95468eef549ccca 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 @@

View File

@@ -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) {

View File

@@ -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());

View File

@@ -1,21 +1,21 @@
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
index bc97ec54c4fcc60ec51583b5f8b87582265d4ff6..ce63d0ac8c4d761a8765ffcaa7ce1516c9d2485a 100644
--- a/src/unix/async.c
+++ b/src/unix/async.c
@@ -26,7 +26,6 @@
@@ -32,10 +32,10 @@ index 0ff2669e30a628dbb2df9e28ba14b38cf14114e5..fef4ae93343edc0341179a1c4739dcd8
+#include <atomic>
+
static void uv__async_send(uv_loop_t* loop);
static int uv__async_start(uv_loop_t* loop);
static void uv__cpu_relax(void);
@@ -63,14 +64,14 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
#if UV__KQUEUE_EVFILT_USER
static uv_once_t kqueue_runtime_detection_guard = UV_ONCE_INIT;
static int kqueue_evfilt_user_support = 1;
@@ -91,14 +92,14 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
int uv_async_send(uv_async_t* handle) {
@@ -55,7 +55,7 @@ index 0ff2669e30a628dbb2df9e28ba14b38cf14114e5..fef4ae93343edc0341179a1c4739dcd8
return 0;
/* Set the loop to busy. */
@@ -90,12 +91,12 @@ int uv_async_send(uv_async_t* handle) {
@@ -118,12 +119,12 @@ int uv_async_send(uv_async_t* handle) {
/* Wait for the busy flag to clear before closing.
* Only call this from the event loop thread. */
static void uv__async_spin(uv_async_t* handle) {
@@ -72,7 +72,7 @@ index 0ff2669e30a628dbb2df9e28ba14b38cf14114e5..fef4ae93343edc0341179a1c4739dcd8
/* Set the pending flag first, so no new events will be added by other
* threads after this function returns. */
@@ -135,7 +136,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
@@ -165,7 +166,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
struct uv__queue queue;
struct uv__queue* q;
uv_async_t* h;
@@ -81,7 +81,7 @@ index 0ff2669e30a628dbb2df9e28ba14b38cf14114e5..fef4ae93343edc0341179a1c4739dcd8
assert(w == &loop->async_io_watcher);
@@ -166,7 +167,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
@@ -202,7 +203,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
uv__queue_insert_tail(&loop->async_handles, q);
/* Atomically fetch and clear pending flag */
@@ -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 d9f868b13b4fa2c340c542fe567b4193cf079748..6c701c0c5a89bc851c709b1a13f1a79210ac0a00 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 77f3a17ad3d102f0aa2860eaf88602fe9555bc4e..49a7d52b5651e0c73a147da2167d8acb6bfbc940 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,57 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
}
#endif /* O_CLOEXEC */
@@ -869,10 +871,10 @@ static int uv__is_cifs_or_smb(int fd) {
@@ -459,19 +460,19 @@ 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...
*/
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");
@@ -479,7 +480,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,
@@ -494,7 +495,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);
}
@@ -503,7 +504,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);
}
@@ -980,10 +981,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 +222,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,
@@ -1002,7 +1003,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 +231,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,
@@ -1526,14 +1527,14 @@ static int uv__fs_statx(int fd,
uv_stat_t* buf) {
STATIC_ASSERT(UV_ENOSYS != -1);
#ifdef __linux__
@@ -190,7 +248,7 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
return UV_ENOSYS;
dirfd = AT_FDCWD;
@@ -1423,7 +1425,7 @@ static int uv__fs_statx(int fd,
@@ -1567,7 +1568,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 +258,7 @@ index 22f31f7285c995c981aca0fa5125bc70aeedc151..75c3093cb7cd6998637c31348265e929
}
diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c
index c307e6631eefb1effb0e0c304eb400e0cb8d984e..bd09ac39dda916dd5a7d664979ce5735586fd7e3 100644
index 2dd3b2156f363c73e4ba3ebc7e52367c85f654a8..6f0e06476a65f0d9ed92b28c1b932d17d98dfaa2 100644
--- a/src/unix/kqueue.c
+++ b/src/unix/kqueue.c
@@ -37,6 +37,8 @@
@@ -230,7 +288,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,
@@ -609,7 +611,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 +297,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) {
@@ -645,7 +647,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 +307,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 cfb0c6eebf2fb231f610020be35187a488127477..be72054ab6513dce8099caeb4dca5083dfbef9df 100644
--- a/src/unix/linux.c
+++ b/src/unix/linux.c
@@ -27,7 +27,6 @@
@@ -319,7 +377,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,
@@ -777,8 +778,8 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
if (iou->ringfd == -1)
return NULL;
@@ -330,7 +388,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,
@@ -807,12 +808,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 +405,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) {
@@ -1153,8 +1154,8 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
int rc;
head = *iou->cqhead;
@@ -358,7 +416,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) {
@@ -1192,15 +1193,15 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
nevents++;
}
@@ -378,7 +436,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
if (flags & UV__IORING_SQ_CQ_OVERFLOW) {
do
@@ -1583,7 +1584,7 @@ update_timeout:
@@ -1604,7 +1605,7 @@ update_timeout:
}
uint64_t uv__hrtime(uv_clocktype_t type) {
@@ -387,7 +445,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
struct timespec t;
clock_t clock_id;
@@ -1599,7 +1600,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
@@ -1620,7 +1621,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
if (type != UV_CLOCK_FAST)
goto done;
@@ -396,7 +454,7 @@ index 09b02cd5df6c32a954cbed817111cf3c1874c3db..e0c4902385edac10ac31bc5075a85a45
if (clock_id != -1)
goto done;
@@ -1608,7 +1609,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
@@ -1629,7 +1630,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
if (t.tv_nsec <= 1 * 1000 * 1000)
clock_id = CLOCK_MONOTONIC_COARSE;
@@ -406,7 +464,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 +507,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 339e5f37323ce3819bea555ee3bb5fa7216d016d..50bbc874c115b552851d9b12b807332aeefcd3ee 100644
--- a/src/uv-common.h
+++ b/src/uv-common.h
@@ -32,15 +32,13 @@

View File

@@ -1,14 +1,14 @@
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 be72054ab6513dce8099caeb4dca5083dfbef9df..322873f6f0e8954d2c5b572ef87fcbc74d7b12c1 100644
--- a/src/unix/linux.c
+++ b/src/unix/linux.c
@@ -2098,7 +2098,7 @@ static uint64_t uv__read_uint64(const char* filename) {

View File

@@ -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;

View File

@@ -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 af07d092a65909ac4948c679b95468eef549ccca..69a413eab4caa2aee4137411d17f630eea138975 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,
@@ -1844,7 +1844,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) {

View File

@@ -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

View File

@@ -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)

View File

@@ -31,7 +31,7 @@
*/
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 48
#define UV_VERSION_MINOR 49
#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""

View File

@@ -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. */

View File

@@ -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;

View File

@@ -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;

View File

@@ -39,6 +39,34 @@
#include <atomic>
#if UV__KQUEUE_EVFILT_USER
static uv_once_t kqueue_runtime_detection_guard = UV_ONCE_INIT;
static int kqueue_evfilt_user_support = 1;
static void uv__kqueue_runtime_detection(void) {
int kq;
struct kevent ev[2];
struct timespec timeout = {0, 0};
/* Perform the runtime detection to ensure that kqueue with
* EVFILT_USER actually works. */
kq = kqueue();
EV_SET(ev, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER,
EV_ADD | EV_CLEAR, 0, 0, 0);
EV_SET(ev + 1, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER,
0, NOTE_TRIGGER, 0, 0);
if (kevent(kq, ev, 2, ev, 1, &timeout) < 1 ||
ev[0].filter != EVFILT_USER ||
ev[0].ident != UV__KQUEUE_EVFILT_USER_IDENT ||
ev[0].flags & EV_ERROR)
/* If we wind up here, we can assume that EVFILT_USER is defined but
* broken on the current system. */
kqueue_evfilt_user_support = 0;
uv__close(kq);
}
#endif
static void uv__async_send(uv_loop_t* loop);
static int uv__async_start(uv_loop_t* loop);
static void uv__cpu_relax(void);
@@ -131,8 +159,10 @@ void uv__async_close(uv_async_t* handle) {
static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
#ifndef __linux__
char buf[1024];
ssize_t r;
#endif
struct uv__queue queue;
struct uv__queue* q;
uv_async_t* h;
@@ -140,7 +170,12 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
assert(w == &loop->async_io_watcher);
#ifndef __linux__
#if UV__KQUEUE_EVFILT_USER
for (;!kqueue_evfilt_user_support;) {
#else
for (;;) {
#endif
r = read(w->fd, buf, sizeof(buf));
if (r == sizeof(buf))
@@ -157,6 +192,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
abort();
}
#endif /* !__linux__ */
uv__queue_move(&loop->async_handles, &queue);
while (!uv__queue_empty(&queue)) {
@@ -180,34 +216,58 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
static void uv__async_send(uv_loop_t* loop) {
const void* buf;
ssize_t len;
int fd;
int r;
ssize_t r;
#ifdef __linux__
uint64_t val;
buf = "";
len = 1;
fd = loop->async_wfd;
fd = loop->async_io_watcher.fd; /* eventfd */
for (val = 1; /* empty */; val = 1) {
r = write(fd, &val, sizeof(uint64_t));
if (r < 0) {
/* When EAGAIN occurs, the eventfd counter hits the maximum value of the unsigned 64-bit.
* We need to first drain the eventfd and then write again.
*
* Check out https://man7.org/linux/man-pages/man2/eventfd.2.html for details.
*/
if (errno == EAGAIN) {
/* It's ready to retry. */
if (read(fd, &val, sizeof(uint64_t)) > 0 || errno == EAGAIN) {
continue;
}
}
/* Unknown error occurs. */
break;
}
return;
}
#else
#if UV__KQUEUE_EVFILT_USER
struct kevent ev;
#if defined(__linux__)
if (fd == -1) {
static const uint64_t val = 1;
buf = &val;
len = sizeof(val);
fd = loop->async_io_watcher.fd; /* eventfd */
if (kqueue_evfilt_user_support) {
fd = loop->async_io_watcher.fd; /* magic number for EVFILT_USER */
EV_SET(&ev, fd, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0);
r = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL);
if (r == 0)
return;
else
abort();
}
#endif
fd = loop->async_wfd; /* write end of the pipe */
do
r = write(fd, buf, len);
r = write(fd, "x", 1);
while (r == -1 && errno == EINTR);
if (r == len)
if (r == 1)
return;
if (r == -1)
if (errno == EAGAIN || errno == EWOULDBLOCK)
return;
#endif
abort();
}
@@ -216,6 +276,9 @@ static void uv__async_send(uv_loop_t* loop) {
static int uv__async_start(uv_loop_t* loop) {
int pipefd[2];
int err;
#if UV__KQUEUE_EVFILT_USER
struct kevent ev;
#endif
if (loop->async_io_watcher.fd != -1)
return 0;
@@ -227,6 +290,36 @@ static int uv__async_start(uv_loop_t* loop) {
pipefd[0] = err;
pipefd[1] = -1;
#elif UV__KQUEUE_EVFILT_USER
uv_once(&kqueue_runtime_detection_guard, uv__kqueue_runtime_detection);
if (kqueue_evfilt_user_support) {
/* In order not to break the generic pattern of I/O polling, a valid
* file descriptor is required to take up a room in loop->watchers,
* thus we create one for that, but this fd will not be actually used,
* it's just a placeholder and magic number which is going to be closed
* during the cleanup, as other FDs. */
err = uv__open_cloexec("/dev/null", O_RDONLY);
if (err < 0)
return err;
pipefd[0] = err;
pipefd[1] = -1;
/* When using EVFILT_USER event to wake up the kqueue, this event must be
* registered beforehand. Otherwise, calling kevent() to issue an
* unregistered EVFILT_USER event will get an ENOENT.
* Since uv__async_send() may happen before uv__io_poll() with multi-threads,
* we can't defer this registration of EVFILT_USER event as we did for other
* events, but must perform it right away. */
EV_SET(&ev, err, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0);
err = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL);
if (err < 0)
return UV__ERR(errno);
} else {
err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
if (err < 0)
return err;
}
#else
err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
if (err < 0)
@@ -237,6 +330,13 @@ static int uv__async_start(uv_loop_t* loop) {
uv__io_start(loop, &loop->async_io_watcher, POLLIN);
loop->async_wfd = pipefd[1];
#if UV__KQUEUE_EVFILT_USER
/* Prevent the EVFILT_USER event from being added to kqueue redundantly
* and mistakenly later in uv__io_poll(). */
if (kqueue_evfilt_user_support)
loop->async_io_watcher.events = loop->async_io_watcher.pevents;
#endif
return 0;
}

View File

@@ -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:
@@ -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;
@@ -1686,10 +1697,14 @@ int uv_thread_setpriority(uv_thread_t tid, int priority) {
param.sched_priority = prio;
r = pthread_setschedparam(tid, policy, &param);
if (r != 0)
return UV__ERR(errno);
return UV__ERR(errno);
}
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 *cpuset) {
int rc;
cpuid_t i;
rc = 0;
for (i = 0;; i++) {
int r = cpuset_isset(cpu, 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;
}

View File

@@ -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) {

View 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_ */

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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,118 @@ 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...
*/
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 +536,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 +794,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 +1074,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 +1227,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 +1240,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 +1318,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 +1764,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 +1776,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,

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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) {

View File

@@ -35,6 +35,10 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#if defined(__APPLE__) || defined(__DragonFly__) || \
defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/event.h>
#endif
#define uv__msan_unpoison(p, n) \
do { \
@@ -71,8 +75,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 +164,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 +253,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 +298,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);
@@ -474,4 +486,44 @@ 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
#ifdef __sun
#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
#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
/* EVFILT_USER is available since OS X 10.6, DragonFlyBSD 4.0,
* FreeBSD 8.1, and NetBSD 10.0.
*
* Note that even though EVFILT_USER is defined on the current system,
* it may still fail to work at runtime somehow. In that case, we fall
* back to pipe-based signaling.
*/
#define UV__KQUEUE_EVFILT_USER 1
/* Magic number of identifier used for EVFILT_USER during runtime detection.
* There are no Google hits for this number when I create it. That way,
* people will be directed here if this number gets printed due to some
* kqueue error and they google for help. */
#define UV__KQUEUE_EVFILT_USER_IDENT 0x1e7e7711
#else
#define UV__KQUEUE_EVFILT_USER 0
#endif
#endif /* UV_UNIX_INTERNAL_H_ */

View File

@@ -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);
@@ -336,6 +369,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
continue;
}
#if UV__KQUEUE_EVFILT_USER
if (ev->filter == EVFILT_USER) {
w = &loop->async_io_watcher;
assert(fd == w->fd);
uv__metrics_update_idle_time(loop);
w->cb(loop, w, w->events);
nevents++;
continue;
}
#endif
if (ev->filter == EVFILT_VNODE) {
assert(w->events == POLLIN);
assert(w->pevents == POLLIN);

View File

@@ -623,7 +623,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 +637,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 +646,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 +713,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 +758,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 +798,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;
@@ -1156,7 +1166,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 +1218,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 +1233,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);
}
@@ -1397,9 +1394,29 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
w->events = w->pevents;
e.events = w->pevents;
if (w == &loop->async_io_watcher)
/* Enable edge-triggered mode on async_io_watcher(eventfd),
* so that we're able to eliminate the overhead of reading
* the eventfd via system call on each event loop wakeup.
*/
e.events |= EPOLLET;
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 +1504,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 +1644,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 +1666,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 +2271,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. */

View File

@@ -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;

View File

@@ -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))

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)

View File

@@ -78,6 +78,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;
@@ -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,7 @@ 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;
}
}

View File

@@ -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) {

View File

@@ -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;
@@ -1064,22 +1086,15 @@ void fs__write(uv_fs_t* req) {
}
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,17 @@ 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 */
SET_REQ_UV_ERROR(req, UV_ENOTDIR, 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 +1137,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 +1146,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)) {
@@ -1185,7 +1242,7 @@ void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) {
size_t len;
uint64_t v;
char* path;
path = (char*)req->path;
len = wcslen(req->file.pathw);
ep = req->file.pathw + len;
@@ -1630,6 +1687,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 +1732,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 +1748,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 +1772,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 +1862,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 +1930,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 +1951,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;
@@ -2833,7 +2975,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);

View File

@@ -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,37 @@ 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 *));
addrinfo_ptr = (struct addrinfo *)(alloc_ptr + cur_off);
addrinfo_ptr->ai_next = addrinfo_ptr;
}
req->addrinfo = (struct addrinfo*)alloc_ptr;
} else {
@@ -206,7 +207,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 +243,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 +271,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 +279,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 +308,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 +329,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,

View File

@@ -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;

View File

@@ -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,28 @@ 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);
}
/* 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;
more = 1;
}
/* Return whether the caller should immediately try another read call to get
* more data. */
if (more && *data_remaining == 0) {
/* TODO: use PeekNamedPipe to see if it is really worth trying to do
* another ReadFile call. */
}
return more;
invalid:
/* Invalid frame. */
err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */
@@ -2061,12 +2122,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 +2144,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 +2155,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 +2187,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 +2272,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 +2304,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. */

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) {
@@ -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");
}
}

View File

@@ -4125,6 +4125,24 @@ typedef const UNICODE_STRING *PCUNICODE_STRING;
# define DEVICE_TYPE DWORD
#endif
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;
/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
* not.
*/
@@ -4224,6 +4242,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 +4350,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 +4458,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 +4479,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 +4782,21 @@ typedef struct _TCP_INITIAL_RTO_PARAMETERS {
# define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17)
#endif
/* from winnt.h */
typedef enum _FILE_INFO_BY_NAME_CLASS {
FileStatByNameInfo,
FileStatLxByNameInfo,
FileCaseSensitiveByNameInfo,
FileStatBasicByNameInfo,
MaximumFileInfoByNameClass
} FILE_INFO_BY_NAME_CLASS;
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 +4817,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)