[wpinet] Upgrade to libuv 1.46.0 (#5446)

This commit is contained in:
Tyler Veness
2023-07-14 18:55:32 -07:00
committed by GitHub
parent aaea85ff16
commit 3c4b58ae1e
82 changed files with 6721 additions and 5048 deletions

View File

@@ -0,0 +1,190 @@
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)"
This reverts commit 748d894e82abcdfff7429cf745003e182c47f163.
---
CMakeLists.txt | 5 +-
configure.ac | 2 +-
include/uv/win.h | 1 -
src/win/process.c | 116 ----------------------------------------------
4 files changed, 2 insertions(+), 122 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 93733dd04783436cc1f1a801133e67e315f4af8d..0958dfb1bd93311cd0e20506311e1e41774c5fa4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -183,10 +183,7 @@ if(WIN32)
advapi32
iphlpapi
userenv
- ws2_32
- dbghelp
- ole32
- uuid)
+ ws2_32)
list(APPEND uv_sources
src/win/async.c
src/win/core.c
diff --git a/configure.ac b/configure.ac
index deb083605de639e896df83882715ddca25340fa3..76177a4bc8e5f17bc1e062af3a9028d2dfc76dc9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false])
AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])])
AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])])
AS_CASE([$host_os],[mingw*], [
- LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32 -ldbghelp -lole32 -luuid"
+ LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32"
])
AS_CASE([$host_os], [solaris2.10], [
CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS"
diff --git a/include/uv/win.h b/include/uv/win.h
index 6f8c47298e407bcb0151cf383a8370b71074f03e..eb74776978340a4910194bae35a9da6493e8c0a6 100644
--- a/include/uv/win.h
+++ b/include/uv/win.h
@@ -91,7 +91,6 @@ typedef struct pollfd {
* variants (Linux and Darwin)
*/
#define SIGHUP 1
-#define SIGQUIT 3
#define SIGKILL 9
#define SIGWINCH 28
diff --git a/src/win/process.c b/src/win/process.c
index 3e451e2291d6ed200ec258e874becbbea22bbc27..ed44adc67c6d52785a199206d9ba0357e2d0b045 100644
--- a/src/win/process.c
+++ b/src/win/process.c
@@ -32,9 +32,6 @@
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
-#include <dbghelp.h>
-#include <shlobj.h>
-#include <psapi.h> /* GetModuleBaseNameW */
#define SIGKILL 9
@@ -1197,120 +1194,7 @@ static int uv__kill(HANDLE process_handle, int signum) {
return UV_EINVAL;
}
- /* Create a dump file for the targeted process, if the registry key
- * `HKLM:Software\Microsoft\Windows\Windows Error Reporting\LocalDumps`
- * exists. The location of the dumps can be influenced by the `DumpFolder`
- * sub-key, which has a default value of `%LOCALAPPDATA%\CrashDumps`, see [0]
- * for more detail. Note that if the dump folder does not exist, we attempt
- * to create it, to match behavior with WER itself.
- * [0]: https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps */
- if (signum == SIGQUIT) {
- HKEY registry_key;
- DWORD pid, ret;
- WCHAR basename[MAX_PATH];
-
- /* Get target process name. */
- GetModuleBaseNameW(process_handle, NULL, &basename[0], sizeof(basename));
-
- /* Get PID of target process. */
- pid = GetProcessId(process_handle);
-
- /* Get LocalDumps directory path. */
- ret = RegOpenKeyExW(
- HKEY_LOCAL_MACHINE,
- L"SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps",
- 0,
- KEY_QUERY_VALUE,
- &registry_key);
- if (ret == ERROR_SUCCESS) {
- HANDLE hDumpFile = NULL;
- WCHAR dump_folder[MAX_PATH], dump_name[MAX_PATH];
- DWORD dump_folder_len = sizeof(dump_folder), key_type = 0;
- ret = RegGetValueW(registry_key,
- NULL,
- L"DumpFolder",
- RRF_RT_ANY,
- &key_type,
- (PVOID) dump_folder,
- &dump_folder_len);
- if (ret != ERROR_SUCCESS) {
- /* Default value for `dump_folder` is `%LOCALAPPDATA%\CrashDumps`. */
- WCHAR* localappdata;
- SHGetKnownFolderPath(&FOLDERID_LocalAppData, 0, NULL, &localappdata);
- _snwprintf_s(dump_folder,
- sizeof(dump_folder),
- _TRUNCATE,
- L"%ls\\CrashDumps",
- localappdata);
- CoTaskMemFree(localappdata);
- }
- RegCloseKey(registry_key);
-
- /* Create dump folder if it doesn't already exist. */
- CreateDirectoryW(dump_folder, NULL);
-
- /* Construct dump filename from process name and PID. */
- _snwprintf_s(dump_name,
- sizeof(dump_name),
- _TRUNCATE,
- L"%ls\\%ls.%d.dmp",
- dump_folder,
- basename,
- pid);
-
- hDumpFile = CreateFileW(dump_name,
- GENERIC_WRITE,
- 0,
- NULL,
- CREATE_NEW,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (hDumpFile != INVALID_HANDLE_VALUE) {
- DWORD dump_options, sym_options;
- FILE_DISPOSITION_INFO DeleteOnClose = { TRUE };
-
- /* If something goes wrong while writing it out, delete the file. */
- SetFileInformationByHandle(hDumpFile,
- FileDispositionInfo,
- &DeleteOnClose,
- sizeof(DeleteOnClose));
-
- /* Tell wine to dump ELF modules as well. */
- sym_options = SymGetOptions();
- SymSetOptions(sym_options | 0x40000000);
-
-/* MiniDumpWithAvxXStateContext might be undef in server2012r2 or mingw < 12 */
-#ifndef MiniDumpWithAvxXStateContext
-#define MiniDumpWithAvxXStateContext 0x00200000
-#endif
- /* We default to a fairly complete dump. In the future, we may want to
- * allow clients to customize what kind of dump to create. */
- dump_options = MiniDumpWithFullMemory |
- MiniDumpIgnoreInaccessibleMemory |
- MiniDumpWithAvxXStateContext;
-
- if (MiniDumpWriteDump(process_handle,
- pid,
- hDumpFile,
- dump_options,
- NULL,
- NULL,
- NULL)) {
- /* Don't delete the file on close if we successfully wrote it out. */
- FILE_DISPOSITION_INFO DontDeleteOnClose = { FALSE };
- SetFileInformationByHandle(hDumpFile,
- FileDispositionInfo,
- &DontDeleteOnClose,
- sizeof(DontDeleteOnClose));
- }
- SymSetOptions(sym_options);
- CloseHandle(hDumpFile);
- }
- }
- }
-
switch (signum) {
- case SIGQUIT:
case SIGTERM:
case SIGKILL:
case SIGINT: {

View File

@@ -1,365 +0,0 @@
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 02/10] Fix warnings
---
include/uv/win.h | 5 +++
src/idna.c | 2 +-
src/inet.c | 4 ++
src/threadpool.c | 4 ++
src/unix/core.c | 12 ++++-
src/unix/darwin.c | 106 +++++++++++++++++++++++---------------------
src/unix/internal.h | 4 +-
src/unix/thread.c | 6 ---
src/uv-common.c | 8 ++++
src/win/fs-event.c | 2 +
src/win/fs.c | 2 +
src/win/pipe.c | 2 +
src/win/process.c | 2 +
src/win/tty.c | 2 +
14 files changed, 99 insertions(+), 62 deletions(-)
diff --git a/include/uv/win.h b/include/uv/win.h
index 56a4cf1151cd9262062d79c3676b83a287757426..10d5e8f169b04e9d48c87e3760320dba5cd310ce 100644
--- a/include/uv/win.h
+++ b/include/uv/win.h
@@ -201,11 +201,16 @@ typedef int (WSAAPI* LPFN_WSARECVFROM)
LPWSAOVERLAPPED overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+#pragma warning(push)
+#pragma warning(disable : 28251)
+
#ifndef _NTDEF_
typedef LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;
#endif
+#pragma warning(pop)
+
#ifndef RTL_CONDITION_VARIABLE_INIT
typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE;
#endif
diff --git a/src/idna.c b/src/idna.c
index 93d982ca018f2d39d9c0ffab07998c2c637029eb..36a39a089019fb4c2a35ec84516658c392eec0a3 100644
--- a/src/idna.c
+++ b/src/idna.c
@@ -106,7 +106,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
char** d, char* de) {
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
const char* ss;
- unsigned c;
+ unsigned c = 0;
unsigned h;
unsigned k;
unsigned n;
diff --git a/src/inet.c b/src/inet.c
index ca8b6ac8b69779655f69da758aa63d810332c800..1b190255ed5f4813428dbb3ba81a50cfd26c5bf1 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -27,6 +27,10 @@
#include "uv.h"
#include "uv-common.h"
+#ifdef _WIN32
+#pragma warning(disable : 6001)
+#endif
+
#define UV__INET_ADDRSTRLEN 16
#define UV__INET6_ADDRSTRLEN 46
diff --git a/src/threadpool.c b/src/threadpool.c
index 1241ace1cc304c14bf1b79cc2a588c1a50ef4507..718972c33b968ad123e6c8afac230f17282830a8 100644
--- a/src/threadpool.c
+++ b/src/threadpool.c
@@ -27,6 +27,10 @@
#include <stdlib.h>
+#ifdef _WIN32
+#pragma warning(disable: 6001 6011)
+#endif
+
#define MAX_THREADPOOL_SIZE 1024
static uv_once_t once = UV_ONCE_INIT;
diff --git a/src/unix/core.c b/src/unix/core.c
index 6353b0e3cc9448aa35dc2ccc9b259277b3fae9a5..223c55131b1ca01696792d9305ab33f0d21af73c 100644
--- a/src/unix/core.c
+++ b/src/unix/core.c
@@ -544,6 +544,16 @@ int uv__accept(int sockfd) {
return peerfd;
}
+#if defined(__APPLE__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
+#if defined(__LP64__)
+ extern "C" int close$NOCANCEL(int);
+#else
+ extern "C" int close$NOCANCEL$UNIX2003(int);
+#endif
+#pragma GCC diagnostic pop
+#endif
/* 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.
@@ -558,10 +568,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
- extern int close$NOCANCEL(int);
return close$NOCANCEL(fd);
#else
- extern int close$NOCANCEL$UNIX2003(int);
return close$NOCANCEL$UNIX2003(fd);
#endif
#pragma GCC diagnostic pop
diff --git a/src/unix/darwin.c b/src/unix/darwin.c
index 5fbf734218fa17cc61c03402c8b1dd6b66110ecb..eeb35720f55bf26363a064443bd02fb9aae682a4 100644
--- a/src/unix/darwin.c
+++ b/src/unix/darwin.c
@@ -253,64 +253,68 @@ static int uv__get_cpu_speed(uint64_t* speed) {
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
- kr = pIOMasterPort(MACH_PORT_NULL, &mach_port);
- assert(kr == KERN_SUCCESS);
- CFMutableDictionaryRef classes_to_match
- = pIOServiceMatching("IOPlatformDevice");
- kr = pIOServiceGetMatchingServices(mach_port, classes_to_match, &it);
- assert(kr == KERN_SUCCESS);
- service = pIOIteratorNext(it);
-
- CFStringRef device_type_str = S("device_type");
- CFStringRef clock_frequency_str = S("clock-frequency");
-
- while (service != 0) {
- CFDataRef data;
- data = pIORegistryEntryCreateCFProperty(service,
- device_type_str,
- NULL,
- 0);
- if (data) {
- const UInt8* raw = pCFDataGetBytePtr(data);
- if (strncmp((char*)raw, "cpu", 3) == 0 ||
- strncmp((char*)raw, "processor", 9) == 0) {
- CFDataRef freq_ref;
- freq_ref = pIORegistryEntryCreateCFProperty(service,
- clock_frequency_str,
- NULL,
- 0);
- if (freq_ref) {
- const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref);
- CFIndex len = pCFDataGetLength(freq_ref);
- if (len == 8)
- memcpy(speed, freq_ref_ptr, 8);
- else if (len == 4) {
- uint32_t v;
- memcpy(&v, freq_ref_ptr, 4);
- *speed = v;
- } else {
- *speed = 0;
- }
+ // Braces ensure goto doesn't jump into device_type_str's and
+ // clock_frequency_str's lifetimes after their initialization
+ {
+ kr = pIOMasterPort(MACH_PORT_NULL, &mach_port);
+ assert(kr == KERN_SUCCESS);
+ CFMutableDictionaryRef classes_to_match
+ = pIOServiceMatching("IOPlatformDevice");
+ kr = pIOServiceGetMatchingServices(mach_port, classes_to_match, &it);
+ assert(kr == KERN_SUCCESS);
+ service = pIOIteratorNext(it);
- pCFRelease(freq_ref);
- pCFRelease(data);
- break;
+ CFStringRef device_type_str = S("device_type");
+ CFStringRef clock_frequency_str = S("clock-frequency");
+
+ while (service != 0) {
+ CFDataRef data;
+ data = pIORegistryEntryCreateCFProperty(service,
+ device_type_str,
+ NULL,
+ 0);
+ if (data) {
+ const UInt8* raw = pCFDataGetBytePtr(data);
+ if (strncmp((char*)raw, "cpu", 3) == 0 ||
+ strncmp((char*)raw, "processor", 9) == 0) {
+ CFDataRef freq_ref;
+ freq_ref = pIORegistryEntryCreateCFProperty(service,
+ clock_frequency_str,
+ NULL,
+ 0);
+ if (freq_ref) {
+ const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref);
+ CFIndex len = pCFDataGetLength(freq_ref);
+ if (len == 8)
+ memcpy(speed, freq_ref_ptr, 8);
+ else if (len == 4) {
+ uint32_t v;
+ memcpy(&v, freq_ref_ptr, 4);
+ *speed = v;
+ } else {
+ *speed = 0;
+ }
+
+ pCFRelease(freq_ref);
+ pCFRelease(data);
+ break;
+ }
}
+ pCFRelease(data);
}
- pCFRelease(data);
- }
- service = pIOIteratorNext(it);
- }
+ service = pIOIteratorNext(it);
+ }
- pIOObjectRelease(it);
+ pIOObjectRelease(it);
- err = 0;
+ err = 0;
- if (device_type_str != NULL)
- pCFRelease(device_type_str);
- if (clock_frequency_str != NULL)
- pCFRelease(clock_frequency_str);
+ if (device_type_str != NULL)
+ pCFRelease(device_type_str);
+ if (clock_frequency_str != NULL)
+ pCFRelease(clock_frequency_str);
+ }
out:
if (core_foundation_handle != NULL)
diff --git a/src/unix/internal.h b/src/unix/internal.h
index cee35c2106aed2990e28ab7d32335061fe7d6d47..f9d1666d8b2104b7437f11c4e0d9c4ae82ff0e31 100644
--- a/src/unix/internal.h
+++ b/src/unix/internal.h
@@ -312,8 +312,8 @@ UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
}
-UV_UNUSED(static char* uv__basename_r(const char* path)) {
- char* s;
+UV_UNUSED(static const char* uv__basename_r(const char* path)) {
+ const char* s;
s = strrchr(path, '/');
if (s == NULL)
diff --git a/src/unix/thread.c b/src/unix/thread.c
index 759cd0c28518928127837ba82cbf8e761c6223d3..64726bd618b930e1aa7e1de3cbceb8aa712ff617 100644
--- a/src/unix/thread.c
+++ b/src/unix/thread.c
@@ -244,12 +244,6 @@ int uv_thread_create_ex(uv_thread_t* tid,
size_t stack_size;
size_t min_stack_size;
- /* Used to squelch a -Wcast-function-type warning. */
- union {
- void (*in)(void*);
- void* (*out)(void*);
- } f;
-
stack_size =
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
diff --git a/src/uv-common.c b/src/uv-common.c
index dfb606e3e842ccb3b2d9327e2b3048c4cfdd0314..49026c03c53a0779a051b8f6bd5809961f5c54e2 100644
--- a/src/uv-common.c
+++ b/src/uv-common.c
@@ -758,6 +758,10 @@ void uv__fs_readdir_cleanup(uv_fs_t* req) {
}
}
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wvarargs"
+#endif
int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
va_list ap;
@@ -771,6 +775,10 @@ int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
return err;
}
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
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 150467313d576bfe2966b55f3d8cffa23cbb8ea3..3244a4e4320d7ce98f226b49b2634c65de89c213 100644
--- a/src/win/fs-event.c
+++ b/src/win/fs-event.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <errno.h>
#include <stdio.h>
diff --git a/src/win/fs.c b/src/win/fs.c
index 8374012f0e9ee094eed5db19e5f7d12286052d70..f71b3c04487a949690fdfd8a6975fd8648acc793 100644
--- a/src/win/fs.c
+++ b/src/win/fs.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <stdlib.h>
#include <direct.h>
diff --git a/src/win/pipe.c b/src/win/pipe.c
index cd77061a079094b11350a01ddd364e15fa3078bc..f413a72dab5c9d58bfbc768152314dc347f7469d 100644
--- a/src/win/pipe.c
+++ b/src/win/pipe.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <io.h>
#include <stdio.h>
diff --git a/src/win/process.c b/src/win/process.c
index e857db3e98eb24f8de12e6b6d90ae3905cc49ce7..a49016f65601c0127b4c0ba5b538e2556314eb46 100644
--- a/src/win/process.c
+++ b/src/win/process.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <io.h>
#include <stdio.h>
diff --git a/src/win/tty.c b/src/win/tty.c
index 267ca64519963ff87b2404f08a60c111e25b89c2..d75226681c2653dc2a5118756b72e0b601cf9701 100644
--- a/src/win/tty.c
+++ b/src/win/tty.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <io.h>
#include <string.h>

View File

@@ -0,0 +1,297 @@
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
---
include/uv/win.h | 5 +++++
src/idna.c | 2 +-
src/inet.c | 4 ++++
src/threadpool.c | 4 ++++
src/unix/core.c | 12 ++++++++++--
src/unix/internal.h | 4 ++--
src/unix/linux.c | 15 ++++++++++++---
src/unix/thread.c | 6 ------
src/uv-common.c | 8 ++++++++
src/win/fs-event.c | 2 ++
src/win/fs.c | 2 ++
src/win/pipe.c | 2 ++
src/win/process.c | 2 ++
src/win/thread.c | 4 ++--
src/win/tty.c | 2 ++
15 files changed, 58 insertions(+), 16 deletions(-)
diff --git a/include/uv/win.h b/include/uv/win.h
index eb74776978340a4910194bae35a9da6493e8c0a6..6d0afe69e7dd4caf4c9459e548fe75cf0c51b501 100644
--- a/include/uv/win.h
+++ b/include/uv/win.h
@@ -201,11 +201,16 @@ typedef int (WSAAPI* LPFN_WSARECVFROM)
LPWSAOVERLAPPED overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+#pragma warning(push)
+#pragma warning(disable : 28251)
+
#ifndef _NTDEF_
typedef LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;
#endif
+#pragma warning(pop)
+
#ifndef RTL_CONDITION_VARIABLE_INIT
typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE;
#endif
diff --git a/src/idna.c b/src/idna.c
index 93d982ca018f2d39d9c0ffab07998c2c637029eb..36a39a089019fb4c2a35ec84516658c392eec0a3 100644
--- a/src/idna.c
+++ b/src/idna.c
@@ -106,7 +106,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
char** d, char* de) {
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
const char* ss;
- unsigned c;
+ unsigned c = 0;
unsigned h;
unsigned k;
unsigned n;
diff --git a/src/inet.c b/src/inet.c
index dd94bea3886ca37945fcad7909d765e3700e3c21..71c9e5b774d64d505e6c6d6ed2637178b8532d4d 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -22,6 +22,10 @@
#include "uv.h"
#include "uv-common.h"
+#ifdef _WIN32
+#pragma warning(disable : 6001)
+#endif
+
#define UV__INET_ADDRSTRLEN 16
#define UV__INET6_ADDRSTRLEN 46
diff --git a/src/threadpool.c b/src/threadpool.c
index f572de5aaf1a1b150e58c7b989949441cac279c4..aa282af468935b680140295a175e503ca82d8fa4 100644
--- a/src/threadpool.c
+++ b/src/threadpool.c
@@ -27,6 +27,10 @@
#include <stdlib.h>
+#ifdef _WIN32
+#pragma warning(disable: 6001 6011)
+#endif
+
#define MAX_THREADPOOL_SIZE 1024
static uv_once_t once = UV_ONCE_INIT;
diff --git a/src/unix/core.c b/src/unix/core.c
index 28c036f94f3e76717afa651451969f128c5a573c..268fc9652f437eb0d0cda2a9e0b06b9e91eb9742 100644
--- a/src/unix/core.c
+++ b/src/unix/core.c
@@ -575,6 +575,16 @@ int uv__accept(int sockfd) {
return peerfd;
}
+#if defined(__APPLE__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
+#if defined(__LP64__)
+ extern "C" int close$NOCANCEL(int);
+#else
+ extern "C" int close$NOCANCEL$UNIX2003(int);
+#endif
+#pragma GCC diagnostic pop
+#endif
/* 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.
@@ -589,10 +599,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
- extern int close$NOCANCEL(int);
return close$NOCANCEL(fd);
#else
- extern int close$NOCANCEL$UNIX2003(int);
return close$NOCANCEL$UNIX2003(fd);
#endif
#pragma GCC diagnostic pop
diff --git a/src/unix/internal.h b/src/unix/internal.h
index fe5885136039d5332623467b86bf52cd4b32ca0f..98c437dcadec5b5106d697e82d5394d459f55e47 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)) {
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
}
-UV_UNUSED(static char* uv__basename_r(const char* path)) {
- char* s;
+UV_UNUSED(static const char* uv__basename_r(const char* path)) {
+ const char* s;
s = strrchr(path, '/');
if (s == NULL)
diff --git a/src/unix/linux.c b/src/unix/linux.c
index 9173850bd158eaf9c41deca38f9ba84762a027a1..157443792f1216c83b4221c3810d17c81c5913c4 100644
--- a/src/unix/linux.c
+++ b/src/unix/linux.c
@@ -1718,7 +1718,11 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) {
return UV__ERR(errno);
}
- fgets(buf, sizeof(buf), fp); /* Skip first line. */
+ /* Skip first line. */
+ if (!fgets(buf, sizeof(buf), fp)) {
+ uv__free(cpus);
+ return UV__ERR(errno);
+ }
for (;;) {
memset(&t, 0, sizeof(t));
@@ -1729,7 +1733,10 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) {
if (n != 7)
break;
- fgets(buf, sizeof(buf), fp); /* Skip rest of line. */
+ /* Skip rest of line. */
+ if (!fgets(buf, sizeof(buf), fp)) {
+ break;
+ }
if (cpu >= ARRAY_SIZE(*cpus))
continue;
@@ -1809,7 +1816,9 @@ nocpuinfo:
if (fp == NULL)
continue;
- fscanf(fp, "%llu", &(*cpus)[cpu].freq);
+ if (0 > fscanf(fp, "%llu", &(*cpus)[cpu].freq)) {
+ (*cpus)[cpu].freq = 0llu;
+ }
fclose(fp);
fp = NULL;
}
diff --git a/src/unix/thread.c b/src/unix/thread.c
index 531c6211bb4321e5f11031a0644b4e3ab9174396..f8600947e3e7df015c4302af4feee740707b2c46 100644
--- a/src/unix/thread.c
+++ b/src/unix/thread.c
@@ -137,12 +137,6 @@ int uv_thread_create_ex(uv_thread_t* tid,
size_t stack_size;
size_t min_stack_size;
- /* Used to squelch a -Wcast-function-type warning. */
- union {
- void (*in)(void*);
- void* (*out)(void*);
- } f;
-
stack_size =
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
diff --git a/src/uv-common.c b/src/uv-common.c
index c04f93596ab1f730576256d86e216ccb7f258b72..cd10b36b4a393e325ea03b93eb9897193ca9800b 100644
--- a/src/uv-common.c
+++ b/src/uv-common.c
@@ -799,6 +799,10 @@ void uv__fs_readdir_cleanup(uv_fs_t* req) {
}
}
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wvarargs"
+#endif
int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
va_list ap;
@@ -812,6 +816,10 @@ int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
return err;
}
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
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 150467313d576bfe2966b55f3d8cffa23cbb8ea3..3244a4e4320d7ce98f226b49b2634c65de89c213 100644
--- a/src/win/fs-event.c
+++ b/src/win/fs-event.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <errno.h>
#include <stdio.h>
diff --git a/src/win/fs.c b/src/win/fs.c
index 328c8f2e0513562b53c948ffea59d0841e14b264..565c05fff13c2e6e74091c1da7b31636d7fd370d 100644
--- a/src/win/fs.c
+++ b/src/win/fs.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <stdlib.h>
#include <direct.h>
diff --git a/src/win/pipe.c b/src/win/pipe.c
index c1739efe82b8755999145860b4da6b50c73518a2..258d6a684c67f154096a25e7226f1a7d08b93d5b 100644
--- a/src/win/pipe.c
+++ b/src/win/pipe.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <io.h>
#include <stdio.h>
diff --git a/src/win/process.c b/src/win/process.c
index b383e8b405db56d413985b38df216d09c58ec4a0..2b1b46259959867482079962d0ea44246a42e7cb 100644
--- a/src/win/process.c
+++ b/src/win/process.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <io.h>
#include <stdio.h>
diff --git a/src/win/thread.c b/src/win/thread.c
index 57f1698f595e2410a51044f7f228b5a235206819..03b33e9b4de6fe2532095d717a8639e8df454cce 100644
--- a/src/win/thread.c
+++ b/src/win/thread.c
@@ -204,8 +204,8 @@ int uv_thread_setaffinity(uv_thread_t* tid,
threadmask = 0;
for (i = 0; i < cpumasksize; i++) {
if (cpumask[i]) {
- if (procmask & (1 << i))
- threadmask |= 1 << i;
+ if (procmask & (1LL << i))
+ threadmask |= 1LL << i;
else
return UV_EINVAL;
}
diff --git a/src/win/tty.c b/src/win/tty.c
index 7e1f15544b177382a774300f832bc982d85bd62b..abbe1315883257d6825b794344dcd4cba9514097 100644
--- a/src/win/tty.c
+++ b/src/win/tty.c
@@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include <assert.h>
#include <io.h>
#include <string.h>

View File

@@ -1,21 +1,20 @@
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 03/10] Preprocessor cleanup
Subject: [PATCH 04/10] Preprocessor cleanup
---
include/uv.h | 18 +-----------------
include/uv.h | 12 ------------
include/uv/unix.h | 8 --------
include/uv/win.h | 6 +-----
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(+), 30 deletions(-)
7 files changed, 14 insertions(+), 20 deletions(-)
diff --git a/include/uv.h b/include/uv.h
index ee1c94ccd389915ea7572cce044256a7788025ad..dbaeb1e9dcca2f5170221b14494dba18c6425f6d 100644
index 02397dd0fdd43d51f86c0dde9a62046702f12bdb..d5342b0d52232bbf83825948cc6bc09e5d74a4c7 100644
--- a/include/uv.h
+++ b/include/uv.h
@@ -23,9 +23,6 @@
@@ -28,20 +27,7 @@ index ee1c94ccd389915ea7572cce044256a7788025ad..dbaeb1e9dcca2f5170221b14494dba18
#if defined(BUILDING_UV_SHARED) && defined(USING_UV_SHARED)
#error "Define either BUILDING_UV_SHARED or USING_UV_SHARED, not both."
@@ -56,11 +53,7 @@ extern "C" {
#include <stddef.h>
#include <stdio.h>
-#if defined(_MSC_VER) && _MSC_VER < 1600
-# include "uv/stdint-msvc2008.h"
-#else
-# include <stdint.h>
-#endif
+#include <stdint.h>
#if defined(_WIN32)
# include "uv/win.h"
@@ -767,16 +760,10 @@ UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
@@ -796,16 +793,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);
@@ -57,8 +43,8 @@ index ee1c94ccd389915ea7572cce044256a7788025ad..dbaeb1e9dcca2f5170221b14494dba18
-
UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
/*
@@ -1844,7 +1831,4 @@ UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
enum {
@@ -1906,7 +1897,4 @@ UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS
#undef UV__ERR
@@ -67,7 +53,7 @@ index ee1c94ccd389915ea7572cce044256a7788025ad..dbaeb1e9dcca2f5170221b14494dba18
-#endif
#endif /* UV_H */
diff --git a/include/uv/unix.h b/include/uv/unix.h
index 420be86c6f9984486c6420ff710c9dbcad09e411..256fef37692da6c5dc9f7bb7d21c576b41a36b8c 100644
index 09f88a5674280d762c094d956e5dec6971c6a33e..e334cabe0280ef94bacbb1171049c71f17bf56ff 100644
--- a/include/uv/unix.h
+++ b/include/uv/unix.h
@@ -47,14 +47,6 @@
@@ -85,28 +71,11 @@ index 420be86c6f9984486c6420ff710c9dbcad09e411..256fef37692da6c5dc9f7bb7d21c576b
#elif defined(__APPLE__)
# include "uv/darwin.h"
#elif defined(__DragonFly__) || \
diff --git a/include/uv/win.h b/include/uv/win.h
index 10d5e8f169b04e9d48c87e3760320dba5cd310ce..0a33366f3f4b51dbf70691623efe1343ee6b2547 100644
--- a/include/uv/win.h
+++ b/include/uv/win.h
@@ -60,11 +60,7 @@ typedef struct pollfd {
#include <fcntl.h>
#include <sys/stat.h>
-#if defined(_MSC_VER) && _MSC_VER < 1600
-# include "uv/stdint-msvc2008.h"
-#else
-# include <stdint.h>
-#endif
+#include <stdint.h>
#include "uv/tree.h"
#include "uv/threadpool.h"
diff --git a/src/unix/internal.h b/src/unix/internal.h
index f9d1666d8b2104b7437f11c4e0d9c4ae82ff0e31..2b6541576bdc977e3b5a15dca4d3ad4410b4a54f 100644
index 98c437dcadec5b5106d697e82d5394d459f55e47..854d98a16a74c45e0b6cb92b17782de6803f6e28 100644
--- a/src/unix/internal.h
+++ b/src/unix/internal.h
@@ -192,6 +192,8 @@ struct uv__stream_queued_fds_s {
@@ -233,6 +233,8 @@ struct uv__statx {
#if defined(__linux__) && O_NDELAY != O_NONBLOCK
#undef uv__nonblock
#define uv__nonblock uv__nonblock_fcntl
@@ -116,22 +85,22 @@ index f9d1666d8b2104b7437f11c4e0d9c4ae82ff0e31..2b6541576bdc977e3b5a15dca4d3ad44
/* core */
diff --git a/src/win/fs.c b/src/win/fs.c
index f71b3c04487a949690fdfd8a6975fd8648acc793..71c9b1693bb17e168fb04192c8939c25e03a617d 100644
index 565c05fff13c2e6e74091c1da7b31636d7fd370d..f415ddc2c39d09eea317fc857777acce1ce7d13e 100644
--- a/src/win/fs.c
+++ b/src/win/fs.c
@@ -38,6 +38,7 @@
#include "handle-inl.h"
#include "fs-fd-hash-inl.h"
@@ -40,6 +40,7 @@
#include <winioctl.h>
+#pragma comment(lib, "Advapi32.lib")
#define UV_FS_FREE_PATHS 0x0002
#define UV_FS_FREE_PTR 0x0008
diff --git a/src/win/tty.c b/src/win/tty.c
index d75226681c2653dc2a5118756b72e0b601cf9701..9753784dc0118a12ef45060bf9af673bfaa838d0 100644
index abbe1315883257d6825b794344dcd4cba9514097..9bb3d9e830c901122da5e521e0c6b032dfd5044c 100644
--- a/src/win/tty.c
+++ b/src/win/tty.c
@@ -42,6 +42,8 @@
@@ -37,6 +37,8 @@
#include "stream-inl.h"
#include "req-inl.h"
@@ -141,10 +110,10 @@ index d75226681c2653dc2a5118756b72e0b601cf9701..9753784dc0118a12ef45060bf9af673b
# define InterlockedOr _InterlockedOr
#endif
diff --git a/src/win/util.c b/src/win/util.c
index c655f532dbcc6c63516027caf1453ca4ef817cff..7a5dd2ef99ba335a146635b61f8d3eba7ff5ef75 100644
index 1cfd7b2caf0d4ad1a6a66df9406c21f4e2b69b04..af18cfa6c106c5de0996e4fff9b4127aaa3b576b 100644
--- a/src/win/util.c
+++ b/src/win/util.c
@@ -63,12 +63,20 @@
@@ -64,12 +64,20 @@
/* A RtlGenRandom() by any other name... */

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 04/10] Cleanup problematic language
Subject: [PATCH 05/10] 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 b41505258ff822ef31c62f4a44438b5525a02065..ed81e26a8dcbad52bc31fbd1964ab6de4ea85d13 100644
index d099bdb3b677212d21e06ac7bb1031c8e5386499..1bd217b5a15eed13a8349c479b53471dd36ca216 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) {
@@ -18,7 +18,7 @@ index b41505258ff822ef31c62f4a44438b5525a02065..ed81e26a8dcbad52bc31fbd1964ab6de
-static int uv__tty_is_slave(const int fd) {
+static int uv__tty_is_peripheral(const int fd) {
int result;
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#if defined(__linux__) || defined(__FreeBSD__)
int dummy;
@@ -91,15 +91,16 @@ static int uv__tty_is_slave(const int fd) {
result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;

View File

@@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Tue, 26 Apr 2022 15:26:03 -0400
Subject: [PATCH 05/10] Use roborio time
---
src/unix/linux-core.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c
index 85f3fc0170288577d2e39030dc728de9a694a752..12ed7ff1129ebeb1c11beeca584bd0519c1e1fe6 100644
--- a/src/unix/linux-core.c
+++ b/src/unix/linux-core.c
@@ -67,6 +67,10 @@
# define CLOCK_MONOTONIC_COARSE 6
#endif
+#ifdef __FRC_ROBORIO__
+#include "wpi/timestamp.h"
+#endif
+
/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
* include that file because it conflicts with <time.h>. We'll just have to
* define it ourselves.
@@ -118,6 +122,9 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
uint64_t uv__hrtime(uv_clocktype_t type) {
+#ifdef __FRC_ROBORIO__
+ return wpi::Now() * 1000u;
+#else
static clock_t fast_clock_id = -1;
struct timespec t;
clock_t clock_id;
@@ -151,6 +158,7 @@ done:
return 0; /* Not really possible. */
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
+#endif
}

View File

@@ -6,11 +6,10 @@ Subject: [PATCH 06/10] Style / comments cleanup
---
src/fs-poll.c | 1 +
src/unix/core.c | 1 +
src/unix/thread.c | 3 +--
src/uv-common.c | 1 +
src/win/process.c | 1 -
src/win/winsock.c | 1 +
6 files changed, 5 insertions(+), 3 deletions(-)
5 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/fs-poll.c b/src/fs-poll.c
index 5a39daed095502b2db34f23fcaf0ab04f31f96ff..1a7ca70d62c71f6eaef2b9985796cc46a6438869 100644
@@ -25,10 +24,10 @@ index 5a39daed095502b2db34f23fcaf0ab04f31f96ff..1a7ca70d62c71f6eaef2b9985796cc46
uv_fs_poll_t* parent_handle;
int busy_polling;
diff --git a/src/unix/core.c b/src/unix/core.c
index 223c55131b1ca01696792d9305ab33f0d21af73c..4c23f608c842bdcb09d621374a0ccb0bda79166e 100644
index 268fc9652f437eb0d0cda2a9e0b06b9e91eb9742..f53adc156a7c454c492abaeac29d90be436785fc 100644
--- a/src/unix/core.c
+++ b/src/unix/core.c
@@ -544,6 +544,7 @@ int uv__accept(int sockfd) {
@@ -575,6 +575,7 @@ int uv__accept(int sockfd) {
return peerfd;
}
@@ -36,39 +35,11 @@ index 223c55131b1ca01696792d9305ab33f0d21af73c..4c23f608c842bdcb09d621374a0ccb0b
#if defined(__APPLE__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
diff --git a/src/unix/thread.c b/src/unix/thread.c
index 64726bd618b930e1aa7e1de3cbceb8aa712ff617..392a0715a85074576ba89d2a415ca55037edf347 100644
--- a/src/unix/thread.c
+++ b/src/unix/thread.c
@@ -85,7 +85,6 @@ error2:
return rc;
}
-
int uv_barrier_wait(uv_barrier_t* barrier) {
struct _uv_barrier* b;
int last;
@@ -94,6 +93,7 @@ int uv_barrier_wait(uv_barrier_t* barrier) {
return UV_EINVAL;
b = barrier->b;
+ /* Lock the mutex*/
uv_mutex_lock(&b->mutex);
if (++b->in == b->threshold) {
@@ -113,7 +113,6 @@ int uv_barrier_wait(uv_barrier_t* barrier) {
return last;
}
-
void uv_barrier_destroy(uv_barrier_t* barrier) {
struct _uv_barrier* b;
diff --git a/src/uv-common.c b/src/uv-common.c
index 49026c03c53a0779a051b8f6bd5809961f5c54e2..c9a32c0336777aa3a41cac7cb7a4c23ad3f677da 100644
index cd10b36b4a393e325ea03b93eb9897193ca9800b..bfcc3ef10f4fd7763221638947da6e02e7a17c33 100644
--- a/src/uv-common.c
+++ b/src/uv-common.c
@@ -758,6 +758,7 @@ void uv__fs_readdir_cleanup(uv_fs_t* req) {
@@ -799,6 +799,7 @@ void uv__fs_readdir_cleanup(uv_fs_t* req) {
}
}
@@ -77,7 +48,7 @@ index 49026c03c53a0779a051b8f6bd5809961f5c54e2..c9a32c0336777aa3a41cac7cb7a4c23a
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wvarargs"
diff --git a/src/win/process.c b/src/win/process.c
index a49016f65601c0127b4c0ba5b538e2556314eb46..8e7835a5e90f9fae89fc9a9be2f6945e2814dfa7 100644
index 2b1b46259959867482079962d0ea44246a42e7cb..18816d3b1e8c863f8ca74fe0104de1aecd0ae3fa 100644
--- a/src/win/process.c
+++ b/src/win/process.c
@@ -35,7 +35,6 @@

View File

@@ -1,17 +1,17 @@
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 08/10] Fix Win32 warning suppression pragma
Subject: [PATCH 07/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 7a5dd2ef99ba335a146635b61f8d3eba7ff5ef75..d9888aec7959de4ec49377a71b0dc931e89e5f4e 100644
index af18cfa6c106c5de0996e4fff9b4127aaa3b576b..9324992ec521cc3496e3e9304e600963a3f20897 100644
--- a/src/win/util.c
+++ b/src/win/util.c
@@ -1750,7 +1750,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
@@ -1692,7 +1692,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
} else {
/* Silence GetVersionEx() deprecation warning. */
#ifdef _MSC_VER

View File

@@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tyler Veness <calcmogul@gmail.com>
Date: Tue, 17 May 2022 21:36:57 -0700
Subject: [PATCH 07/10] Squelch GCC warnings we don't know how to fix
---
src/queue.h | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/src/queue.h b/src/queue.h
index ff3540a0a51c840d7ff5e6a3cea95f24c27b0812..c0d5efc187c78f7d60776447be492a9310c3b36c 100644
--- a/src/queue.h
+++ b/src/queue.h
@@ -58,6 +58,7 @@ typedef void *QUEUE[2];
} \
while (0)
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12
#define QUEUE_SPLIT(h, q, n) \
do { \
QUEUE_PREV(n) = QUEUE_PREV(h); \
@@ -65,9 +66,24 @@ typedef void *QUEUE[2];
QUEUE_NEXT(n) = (q); \
QUEUE_PREV(h) = QUEUE_PREV(q); \
QUEUE_PREV_NEXT(h) = (h); \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wdangling-pointer=\"") \
QUEUE_PREV(q) = (n); \
+ _Pragma("GCC diagnostic pop") \
} \
while (0)
+#else
+#define QUEUE_SPLIT(h, q, n) \
+ do { \
+ QUEUE_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(n) = (n); \
+ QUEUE_NEXT(n) = (q); \
+ QUEUE_PREV(h) = QUEUE_PREV(q); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ QUEUE_PREV(q) = (n); \
+ } \
+ while (0)
+#endif // defined(__GNUC__) && !defined(__clang__)
#define QUEUE_MOVE(h, n) \
do { \

View File

@@ -0,0 +1,531 @@
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 08/10] Use C++ atomics
---
src/unix/async.c | 25 +++++++++++++------------
src/unix/core.c | 3 ++-
src/unix/fs.c | 32 +++++++++++++++++---------------
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, 68 insertions(+), 62 deletions(-)
diff --git a/src/unix/async.c b/src/unix/async.c
index 0ff2669e30a628dbb2df9e28ba14b38cf14114e5..fef4ae93343edc0341179a1c4739dcd831ef6e26 100644
--- a/src/unix/async.c
+++ b/src/unix/async.c
@@ -26,7 +26,6 @@
#include "internal.h"
#include <errno.h>
-#include <stdatomic.h>
#include <stdio.h> /* snprintf() */
#include <assert.h>
#include <stdlib.h>
@@ -38,6 +37,8 @@
#include <sys/eventfd.h>
#endif
+#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) {
int uv_async_send(uv_async_t* handle) {
- _Atomic int* pending;
- _Atomic int* busy;
+ std::atomic<int>* pending;
+ std::atomic<int>* busy;
- pending = (_Atomic int*) &handle->pending;
- busy = (_Atomic int*) &handle->u.fd;
+ pending = (std::atomic<int>*) &handle->pending;
+ busy = (std::atomic<int>*) &handle->u.fd;
/* Do a cheap read first. */
- if (atomic_load_explicit(pending, memory_order_relaxed) != 0)
+ if (atomic_load_explicit(pending, std::memory_order_relaxed) != 0)
return 0;
/* Set the loop to busy. */
@@ -90,12 +91,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) {
- _Atomic int* pending;
- _Atomic int* busy;
+ std::atomic<int>* pending;
+ std::atomic<int>* busy;
int i;
- pending = (_Atomic int*) &handle->pending;
- busy = (_Atomic int*) &handle->u.fd;
+ pending = (std::atomic<int>*) &handle->pending;
+ busy = (std::atomic<int>*) &handle->u.fd;
/* 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) {
struct uv__queue queue;
struct uv__queue* q;
uv_async_t* h;
- _Atomic int *pending;
+ std::atomic<int> *pending;
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) {
uv__queue_insert_tail(&loop->async_handles, q);
/* Atomically fetch and clear pending flag */
- pending = (_Atomic int*) &h->pending;
+ pending = (std::atomic<int>*) &h->pending;
if (atomic_exchange(pending, 0) == 0)
continue;
diff --git a/src/unix/core.c b/src/unix/core.c
index f53adc156a7c454c492abaeac29d90be436785fc..ce7fd2cdfdd53410dc694450bd56dffc26ff4792 100644
--- a/src/unix/core.c
+++ b/src/unix/core.c
@@ -45,6 +45,7 @@
#include <sys/utsname.h>
#include <sys/time.h>
#include <time.h> /* clock_gettime */
+#include <atomic>
#ifdef __sun
# include <sys/filio.h>
@@ -263,7 +264,7 @@ int uv__getiovmax(void) {
#if defined(IOV_MAX)
return IOV_MAX;
#elif defined(_SC_IOV_MAX)
- static _Atomic int iovmax_cached = -1;
+ static std::atomic<int> iovmax_cached = -1;
int iovmax;
iovmax = atomic_load_explicit(&iovmax_cached, memory_order_relaxed);
diff --git a/src/unix/fs.c b/src/unix/fs.c
index e25d02e54dbe93e4b9c22b0140108c99ae2cb4f7..aba190a9c0240fba0128fb7fbc5d92d7fa86214b 100644
--- a/src/unix/fs.c
+++ b/src/unix/fs.c
@@ -46,6 +46,8 @@
#include <fcntl.h>
#include <poll.h>
+#include <atomic>
+
#if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
@@ -313,7 +315,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
static uv_once_t once = UV_ONCE_INIT;
int r;
#ifdef O_CLOEXEC
- static _Atomic int no_cloexec_support;
+ static std::atomic<int> no_cloexec_support;
#endif
static const char pattern[] = "XXXXXX";
static const size_t pattern_size = sizeof(pattern) - 1;
@@ -338,7 +340,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
uv_once(&once, uv__mkostemp_initonce);
#ifdef O_CLOEXEC
- if (atomic_load_explicit(&no_cloexec_support, memory_order_relaxed) == 0 &&
+ if (atomic_load_explicit(&no_cloexec_support, std::memory_order_relaxed) == 0 &&
uv__mkostemp != NULL) {
r = uv__mkostemp(path, O_CLOEXEC);
@@ -352,7 +354,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. */
- atomic_store_explicit(&no_cloexec_support, 1, memory_order_relaxed);
+ atomic_store_explicit(&no_cloexec_support, 1, std::memory_order_relaxed);
}
#endif /* O_CLOEXEC */
@@ -462,7 +464,7 @@ static ssize_t uv__fs_preadv(uv_file fd,
static ssize_t uv__fs_read(uv_fs_t* req) {
#if TRY_PREADV
- static _Atomic int no_preadv;
+ static std::atomic<int> no_preadv;
#endif
unsigned int iovmax;
ssize_t result;
@@ -486,7 +488,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if TRY_PREADV
- if (atomic_load_explicit(&no_preadv, memory_order_relaxed)) retry:
+ if (atomic_load_explicit(&no_preadv, std::memory_order_relaxed)) retry:
# endif
{
result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
@@ -498,7 +500,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
req->nbufs,
req->off);
if (result == -1 && errno == ENOSYS) {
- atomic_store_explicit(&no_preadv, 1, memory_order_relaxed);
+ atomic_store_explicit(&no_preadv, 1, std::memory_order_relaxed);
goto retry;
}
}
@@ -939,10 +941,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) {
- static _Atomic int no_copy_file_range_support;
+ static std::atomic<int> no_copy_file_range_support;
ssize_t r;
- if (atomic_load_explicit(&no_copy_file_range_support, memory_order_relaxed)) {
+ if (atomic_load_explicit(&no_copy_file_range_support, std::memory_order_relaxed)) {
errno = ENOSYS;
return -1;
}
@@ -961,7 +963,7 @@ static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
errno = ENOSYS; /* Use fallback. */
break;
case ENOSYS:
- atomic_store_explicit(&no_copy_file_range_support, 1, memory_order_relaxed);
+ atomic_store_explicit(&no_copy_file_range_support, 1, std::memory_order_relaxed);
break;
case EPERM:
/* It's been reported that CIFS spuriously fails.
@@ -1162,7 +1164,7 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
static ssize_t uv__fs_write(uv_fs_t* req) {
#if TRY_PREADV
- static _Atomic int no_pwritev;
+ static std::atomic<int> no_pwritev;
#endif
ssize_t r;
@@ -1191,7 +1193,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if TRY_PREADV
- if (atomic_load_explicit(&no_pwritev, memory_order_relaxed)) retry:
+ if (atomic_load_explicit(&no_pwritev, std::memory_order_relaxed)) retry:
# endif
{
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
@@ -1203,7 +1205,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
req->nbufs,
req->off);
if (r == -1 && errno == ENOSYS) {
- atomic_store_explicit(&no_pwritev, 1, memory_order_relaxed);
+ atomic_store_explicit(&no_pwritev, 1, std::memory_order_relaxed);
goto retry;
}
}
@@ -1483,14 +1485,14 @@ static int uv__fs_statx(int fd,
uv_stat_t* buf) {
STATIC_ASSERT(UV_ENOSYS != -1);
#ifdef __linux__
- static _Atomic int no_statx;
+ static std::atomic<int> no_statx;
struct uv__statx statxbuf;
int dirfd;
int flags;
int mode;
int rc;
- if (atomic_load_explicit(&no_statx, memory_order_relaxed))
+ if (atomic_load_explicit(&no_statx, std::memory_order_relaxed))
return UV_ENOSYS;
dirfd = AT_FDCWD;
@@ -1524,7 +1526,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.
*/
- atomic_store_explicit(&no_statx, 1, memory_order_relaxed);
+ atomic_store_explicit(&no_statx, 1, std::memory_order_relaxed);
return UV_ENOSYS;
}
diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c
index 28e55aae6c613576ede7024a5c73d746e134d865..ffe0f9191cc7b0c233447db358077d8814e0217e 100644
--- a/src/unix/kqueue.c
+++ b/src/unix/kqueue.c
@@ -34,6 +34,8 @@
#include <fcntl.h>
#include <time.h>
+#include <atomic>
+
/*
* Required on
* - Until at least FreeBSD 11.0
@@ -60,7 +62,7 @@ int uv__kqueue_init(uv_loop_t* loop) {
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-static _Atomic int uv__has_forked_with_cfrunloop;
+static std::atomic<int> uv__has_forked_with_cfrunloop;
#endif
int uv__io_fork(uv_loop_t* loop) {
@@ -84,7 +86,7 @@ int uv__io_fork(uv_loop_t* loop) {
*/
atomic_store_explicit(&uv__has_forked_with_cfrunloop,
1,
- memory_order_relaxed);
+ std::memory_order_relaxed);
uv__free(loop->cf_state);
loop->cf_state = NULL;
}
@@ -541,7 +543,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
goto fallback;
if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
- memory_order_relaxed)) {
+ std::memory_order_relaxed)) {
int r;
/* The fallback fd is no longer needed */
uv__close_nocheckstdio(fd);
@@ -577,7 +579,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,
- memory_order_relaxed))
+ std::memory_order_relaxed))
if (handle->cf_cb != NULL)
r = uv__fsevents_close(handle);
#endif
diff --git a/src/unix/linux.c b/src/unix/linux.c
index 157443792f1216c83b4221c3810d17c81c5913c4..e3dfb186dc531e5c8197a81681c00d693e0913c6 100644
--- a/src/unix/linux.c
+++ b/src/unix/linux.c
@@ -27,7 +27,6 @@
#include "internal.h"
#include <inttypes.h>
-#include <stdatomic.h>
#include <stddef.h> /* offsetof */
#include <stdint.h>
#include <stdio.h>
@@ -133,6 +132,8 @@
# include <netpacket/packet.h>
#endif /* HAVE_IFADDRS_H */
+#include <atomic>
+
enum {
UV__IORING_SETUP_SQPOLL = 2u,
};
@@ -311,14 +312,14 @@ static struct watcher_root* uv__inotify_watchers(uv_loop_t* loop) {
unsigned uv__kernel_version(void) {
- static _Atomic unsigned cached_version;
+ static std::atomic<unsigned int> cached_version;
struct utsname u;
unsigned version;
unsigned major;
unsigned minor;
unsigned patch;
- version = atomic_load_explicit(&cached_version, memory_order_relaxed);
+ version = std::atomic_load_explicit(&cached_version, std::memory_order_relaxed);
if (version != 0)
return version;
@@ -329,7 +330,7 @@ unsigned uv__kernel_version(void) {
return 0;
version = major * 65536 + minor * 256 + patch;
- atomic_store_explicit(&cached_version, version, memory_order_relaxed);
+ std::atomic_store_explicit(&cached_version, version, std::memory_order_relaxed);
return version;
}
@@ -424,16 +425,16 @@ static int uv__use_io_uring(void) {
return 0; /* Possibly available but blocked by seccomp. */
#else
/* Ternary: unknown=0, yes=1, no=-1 */
- static _Atomic int use_io_uring;
+ static std::atomic<int> use_io_uring;
char* val;
int use;
- use = atomic_load_explicit(&use_io_uring, memory_order_relaxed);
+ use = std::atomic_load_explicit(&use_io_uring, std::memory_order_relaxed);
if (use == 0) {
val = getenv("UV_USE_IO_URING");
use = val == NULL || atoi(val) ? 1 : -1;
- atomic_store_explicit(&use_io_uring, use, memory_order_relaxed);
+ std::atomic_store_explicit(&use_io_uring, use, std::memory_order_relaxed);
}
return use > 0;
@@ -709,8 +710,8 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou,
if (iou->ringfd == -1)
return NULL;
- head = atomic_load_explicit((_Atomic uint32_t*) iou->sqhead,
- memory_order_acquire);
+ head = std::atomic_load_explicit((std::atomic<uint32_t>*) iou->sqhead,
+ std::memory_order_acquire);
tail = *iou->sqtail;
mask = iou->sqmask;
@@ -739,12 +740,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;
- atomic_store_explicit((_Atomic uint32_t*) iou->sqtail,
+ std::atomic_store_explicit((std::atomic<uint32_t>*) iou->sqtail,
*iou->sqtail + 1,
- memory_order_release);
+ std::memory_order_release);
- flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags,
- memory_order_acquire);
+ flags = std::atomic_load_explicit((std::atomic<uint32_t>*) iou->sqflags,
+ std::memory_order_acquire);
if (flags & UV__IORING_SQ_NEED_WAKEUP)
if (uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_SQ_WAKEUP))
@@ -1076,8 +1077,8 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
int rc;
head = *iou->cqhead;
- tail = atomic_load_explicit((_Atomic uint32_t*) iou->cqtail,
- memory_order_acquire);
+ tail = std::atomic_load_explicit((std::atomic<uint32_t>*) iou->cqtail,
+ std::memory_order_acquire);
mask = iou->cqmask;
cqe = (uv__io_uring_cqe*)iou->cqe;
nevents = 0;
@@ -1109,15 +1110,15 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
nevents++;
}
- atomic_store_explicit((_Atomic uint32_t*) iou->cqhead,
+ std::atomic_store_explicit((std::atomic<uint32_t>*) iou->cqhead,
tail,
- memory_order_release);
+ std::memory_order_release);
/* Check whether CQE's overflowed, if so enter the kernel to make them
* available. Don't grab them immediately but in the next loop iteration to
* avoid loop starvation. */
- flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags,
- memory_order_acquire);
+ flags = std::atomic_load_explicit((std::atomic<uint32_t>*) iou->sqflags,
+ std::memory_order_acquire);
if (flags & UV__IORING_SQ_CQ_OVERFLOW) {
do
@@ -1531,7 +1532,7 @@ update_timeout:
}
uint64_t uv__hrtime(uv_clocktype_t type) {
- static _Atomic clock_t fast_clock_id = -1;
+ static std::atomic<clock_t> fast_clock_id = -1;
struct timespec t;
clock_t clock_id;
@@ -1547,7 +1548,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
if (type != UV_CLOCK_FAST)
goto done;
- clock_id = atomic_load_explicit(&fast_clock_id, memory_order_relaxed);
+ clock_id = std::atomic_load_explicit(&fast_clock_id, std::memory_order_relaxed);
if (clock_id != -1)
goto done;
@@ -1556,7 +1557,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
if (t.tv_nsec <= 1 * 1000 * 1000)
clock_id = CLOCK_MONOTONIC_COARSE;
- atomic_store_explicit(&fast_clock_id, clock_id, memory_order_relaxed);
+ std::atomic_store_explicit(&fast_clock_id, clock_id, std::memory_order_relaxed);
done:
diff --git a/src/unix/tty.c b/src/unix/tty.c
index 1bd217b5a15eed13a8349c479b53471dd36ca216..1304c6d8685cfd122cffea066dc668d1dfc9ae02 100644
--- a/src/unix/tty.c
+++ b/src/unix/tty.c
@@ -22,7 +22,6 @@
#include "uv.h"
#include "internal.h"
-#include <stdatomic.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
@@ -30,6 +29,8 @@
#include <errno.h>
#include <sys/ioctl.h>
+#include <atomic>
+
#if defined(__MVS__) && !defined(IMAXBEL)
#define IMAXBEL 0
#endif
@@ -64,7 +65,7 @@ static int isreallyatty(int file) {
static int orig_termios_fd = -1;
static struct termios orig_termios;
-static _Atomic int termios_spinlock;
+static std::atomic<int> termios_spinlock;
int uv__tcsetattr(int fd, int how, const struct termios *term) {
int rc;
diff --git a/src/uv-common.c b/src/uv-common.c
index bfcc3ef10f4fd7763221638947da6e02e7a17c33..5c6d84155408ae4f7c3c6ff9b48bd09ccd16a92e 100644
--- a/src/uv-common.c
+++ b/src/uv-common.c
@@ -951,7 +951,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
__attribute__((destructor))
#endif
void uv_library_shutdown(void) {
- static int was_shutdown;
+ static std::atomic<int> was_shutdown;
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
--- a/src/uv-common.h
+++ b/src/uv-common.h
@@ -32,15 +32,13 @@
#include <stddef.h>
#include <stdint.h>
+#include <atomic>
+
#include "uv.h"
#include "uv/tree.h"
#include "queue.h"
#include "strscpy.h"
-#ifndef _MSC_VER
-# include <stdatomic.h>
-#endif
-
#if EDOM > 0
# define UV__ERR(x) (-(x))
#else
@@ -70,7 +68,7 @@ extern int snprintf(char*, size_t, const char*, ...);
InterlockedExchangeNoFence((LONG volatile*)(p), v)
#else
#define uv__exchange_int_relaxed(p, v) \
- atomic_exchange_explicit((_Atomic int*)(p), v, memory_order_relaxed)
+ std::atomic_exchange_explicit((std::atomic<int>*)(p), v, std::memory_order_relaxed)
#endif
#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)

View File

@@ -1,21 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Johnson <johnson.peter@gmail.com>
Date: Sun, 5 Jun 2022 15:40:35 -0700
Subject: [PATCH 09/10] Avoid unused variable warning on Mac
---
src/unix/darwin.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/unix/darwin.c b/src/unix/darwin.c
index eeb35720f55bf26363a064443bd02fb9aae682a4..ed51a6ad61ca70b06c5e3c5b3a12f1109ac47083 100644
--- a/src/unix/darwin.c
+++ b/src/unix/darwin.c
@@ -257,6 +257,7 @@ static int uv__get_cpu_speed(uint64_t* speed) {
// clock_frequency_str's lifetimes after their initialization
{
kr = pIOMasterPort(MACH_PORT_NULL, &mach_port);
+ (void) kr;
assert(kr == KERN_SUCCESS);
CFMutableDictionaryRef classes_to_match
= pIOServiceMatching("IOPlatformDevice");

View File

@@ -0,0 +1,67 @@
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 09/10] 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 e3dfb186dc531e5c8197a81681c00d693e0913c6..d365b623a0a25228f0c6acf1fa14a5c7a9f1efbf 100644
--- a/src/unix/linux.c
+++ b/src/unix/linux.c
@@ -2060,7 +2060,7 @@ static uint64_t uv__read_uint64(const char* filename) {
* finds the location and length of the memory controller mount path.
* This disregards the leading / for easy concatenation of paths.
* Returns NULL if the memory controller wasn't found. */
-static char* uv__cgroup1_find_memory_controller(char buf[static 1024],
+static char* uv__cgroup1_find_memory_controller(char buf[1024],
int* n) {
char* p;
@@ -2081,7 +2081,7 @@ static char* uv__cgroup1_find_memory_controller(char buf[static 1024],
return p;
}
-static void uv__get_cgroup1_memory_limits(char buf[static 1024], uint64_t* high,
+static void uv__get_cgroup1_memory_limits(char buf[1024], uint64_t* high,
uint64_t* max) {
char filename[4097];
char* p;
@@ -2121,7 +2121,7 @@ update_limits:
*max = UINT64_MAX;
}
-static void uv__get_cgroup2_memory_limits(char buf[static 1024], uint64_t* high,
+static void uv__get_cgroup2_memory_limits(char buf[1024], uint64_t* high,
uint64_t* max) {
char filename[4097];
char* p;
@@ -2138,7 +2138,7 @@ static void uv__get_cgroup2_memory_limits(char buf[static 1024], uint64_t* high,
*high = uv__read_uint64(filename);
}
-static uint64_t uv__get_cgroup_constrained_memory(char buf[static 1024]) {
+static uint64_t uv__get_cgroup_constrained_memory(char buf[1024]) {
uint64_t high;
uint64_t max;
@@ -2164,7 +2164,7 @@ uint64_t uv_get_constrained_memory(void) {
}
-static uint64_t uv__get_cgroup1_current_memory(char buf[static 1024]) {
+static uint64_t uv__get_cgroup1_current_memory(char buf[1024]) {
char filename[4097];
uint64_t current;
char* p;
@@ -2188,7 +2188,7 @@ static uint64_t uv__get_cgroup1_current_memory(char buf[static 1024]) {
return uv__read_uint64("/sys/fs/cgroup/memory/memory.usage_in_bytes");
}
-static uint64_t uv__get_cgroup2_current_memory(char buf[static 1024]) {
+static uint64_t uv__get_cgroup2_current_memory(char buf[1024]) {
char filename[4097];
char* p;
int n;

View File

@@ -0,0 +1,79 @@
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 10/10] Remove uv_clock_gettime() and add pragmas for missing
libraries
The Win32 function GetSystemTimePreciseAsFileTime() is missing, which
causes compilation errors in uv_clock_gettime(). However, neither WPILib
nor libuv use uv_clock_gettime(), so removing it works around the
problem.
---
include/uv.h | 1 -
src/win/util.c | 33 ++-------------------------------
2 files changed, 2 insertions(+), 32 deletions(-)
diff --git a/include/uv.h b/include/uv.h
index d5342b0d52232bbf83825948cc6bc09e5d74a4c7..9adcf955e143bb323363c9d96da51ccdb618261a 100644
--- a/include/uv.h
+++ b/include/uv.h
@@ -1755,7 +1755,6 @@ UV_EXTERN uint64_t uv_get_total_memory(void);
UV_EXTERN uint64_t uv_get_constrained_memory(void);
UV_EXTERN uint64_t uv_get_available_memory(void);
-UV_EXTERN int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts);
UV_EXTERN uint64_t uv_hrtime(void);
UV_EXTERN void uv_sleep(unsigned int msec);
diff --git a/src/win/util.c b/src/win/util.c
index 9324992ec521cc3496e3e9304e600963a3f20897..4ea2eada07f8d7e664bee22e74b20c705a0eb9a3 100644
--- a/src/win/util.c
+++ b/src/win/util.c
@@ -73,7 +73,9 @@ static char *process_title;
static CRITICAL_SECTION process_title_lock;
#pragma comment(lib, "Advapi32.lib")
+#pragma comment(lib, "Dbghelp.lib")
#pragma comment(lib, "IPHLPAPI.lib")
+#pragma comment(lib, "Ole32.lib")
#pragma comment(lib, "Psapi.lib")
#pragma comment(lib, "Userenv.lib")
#pragma comment(lib, "kernel32.lib")
@@ -513,37 +515,6 @@ int uv_get_process_title(char* buffer, size_t size) {
}
-/* https://github.com/libuv/libuv/issues/1674 */
-int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts) {
- FILETIME ft;
- int64_t t;
-
- if (ts == NULL)
- return UV_EFAULT;
-
- switch (clock_id) {
- case UV_CLOCK_MONOTONIC:
- uv__once_init();
- t = uv__hrtime(UV__NANOSEC);
- ts->tv_sec = t / 1000000000;
- ts->tv_nsec = t % 1000000000;
- return 0;
- case UV_CLOCK_REALTIME:
- GetSystemTimePreciseAsFileTime(&ft);
- /* In 100-nanosecond increments from 1601-01-01 UTC because why not? */
- t = (int64_t) ft.dwHighDateTime << 32 | ft.dwLowDateTime;
- /* Convert to UNIX epoch, 1970-01-01. Still in 100 ns increments. */
- t -= 116444736000000000ll;
- /* Now convert to seconds and nanoseconds. */
- ts->tv_sec = t / 10000000;
- ts->tv_nsec = t % 10000000 * 100;
- return 0;
- }
-
- return UV_EINVAL;
-}
-
-
uint64_t uv_hrtime(void) {
uv__once_init();
return uv__hrtime(UV__NANOSEC);

View File

@@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tyler Veness <calcmogul@gmail.com>
Date: Wed, 7 Jun 2023 21:04:19 -0700
Subject: [PATCH 10/10] Squelch Apple Clang sprintf deprecation warning
---
src/inet.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/inet.c b/src/inet.c
index 1b190255ed5f4813428dbb3ba81a50cfd26c5bf1..57e5c042ef8adb880279f94bcccc70f78df338fc 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -139,7 +139,14 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
tp += strlen(tp);
break;
}
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif // defined(__APPLE__) && defined(__clang__)
tp += sprintf(tp, "%x", words[i]);
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic pop
+#endif // defined(__APPLE__) && defined(__clang__)
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))

View File

@@ -13,23 +13,23 @@ from upstream_utils import (
def main():
upstream_root = clone_repo("https://github.com/libuv/libuv", "v1.44.2")
upstream_root = clone_repo("https://github.com/libuv/libuv", "v1.46.0")
wpilib_root = get_repo_root()
wpinet = os.path.join(wpilib_root, "wpinet")
# Apply patches to upstream Git repo
os.chdir(upstream_root)
for f in [
"0001-Fix-missing-casts.patch",
"0002-Fix-warnings.patch",
"0003-Preprocessor-cleanup.patch",
"0004-Cleanup-problematic-language.patch",
"0005-Use-roborio-time.patch",
"0001-Revert-win-process-write-minidumps-when-sending-SIGQ.patch",
"0002-Fix-missing-casts.patch",
"0003-Fix-warnings.patch",
"0004-Preprocessor-cleanup.patch",
"0005-Cleanup-problematic-language.patch",
"0006-Style-comments-cleanup.patch",
"0007-Squelch-GCC-warnings-we-don-t-know-how-to-fix.patch",
"0008-Fix-Win32-warning-suppression-pragma.patch",
"0009-Avoid-unused-variable-warning-on-Mac.patch",
"0010-Squelch-Apple-Clang-sprintf-deprecation-warning.patch",
"0007-Fix-Win32-warning-suppression-pragma.patch",
"0008-Use-C-atomics.patch",
"0009-Remove-static-from-array-indices.patch",
"0010-Remove-uv_clock_gettime-and-add-pragmas-for-missing-.patch",
]:
git_am(os.path.join(wpilib_root, "upstream_utils/libuv_patches", f))

View File

@@ -108,10 +108,7 @@ set(uv_darwin_src
)
set(uv_linux_src
src/main/native/thirdparty/libuv/src/unix/epoll.cpp
src/main/native/thirdparty/libuv/src/unix/linux-core.cpp
src/main/native/thirdparty/libuv/src/unix/linux-inotify.cpp
src/main/native/thirdparty/libuv/src/unix/linux-syscalls.cpp
src/main/native/thirdparty/libuv/src/unix/linux.cpp
src/main/native/thirdparty/libuv/src/unix/procfs-exepath.cpp
src/main/native/thirdparty/libuv/src/unix/proctitle.cpp
src/main/native/thirdparty/libuv/src/unix/random-sysctl-linux.cpp

View File

@@ -147,10 +147,7 @@ ext {
source {
srcDirs 'src/main/native/thirdparty/libuv/src/unix'
includes = [
'epoll.cpp',
'linux-core.cpp',
'linux-inotify.cpp',
'linux-syscalls.cpp',
'linux.cpp',
'procfs-exepath.cpp',
'proctitle.cpp',
'random-sysctl-linux.cpp',

View File

@@ -28,6 +28,7 @@
#error "Define either BUILDING_UV_SHARED or USING_UV_SHARED, not both."
#endif
#ifndef UV_EXTERN
#ifdef _WIN32
/* Windows - set up dll import/export decorators. */
# if defined(BUILDING_UV_SHARED)
@@ -47,14 +48,20 @@
#else
# define UV_EXTERN /* nothing */
#endif
#endif /* UV_EXTERN */
#include "uv/errno.h"
#include "uv/version.h"
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
/* Internal type, do not use. */
struct uv__queue {
struct uv__queue* next;
struct uv__queue* prev;
};
#if defined(_WIN32)
# include "uv/win.h"
#else
@@ -145,6 +152,8 @@
XX(EFTYPE, "inappropriate file type or format") \
XX(EILSEQ, "illegal byte sequence") \
XX(ESOCKTNOSUPPORT, "socket type not supported") \
XX(ENODATA, "no data available") \
XX(EUNATCH, "protocol driver not attached") \
#define UV_HANDLE_TYPE_MAP(XX) \
XX(ASYNC, async) \
@@ -240,9 +249,12 @@ typedef struct uv_cpu_info_s uv_cpu_info_t;
typedef struct uv_interface_address_s uv_interface_address_t;
typedef struct uv_dirent_s uv_dirent_t;
typedef struct uv_passwd_s uv_passwd_t;
typedef struct uv_group_s uv_group_t;
typedef struct uv_utsname_s uv_utsname_t;
typedef struct uv_statfs_s uv_statfs_t;
typedef struct uv_metrics_s uv_metrics_t;
typedef enum {
UV_LOOP_BLOCK_SIGNAL = 0,
UV_METRICS_IDLE_TIME
@@ -275,13 +287,13 @@ UV_EXTERN int uv_loop_init(uv_loop_t* loop);
UV_EXTERN int uv_loop_close(uv_loop_t* loop);
/*
* NOTE:
* This function is DEPRECATED (to be removed after 0.12), users should
* This function is DEPRECATED, users should
* allocate the loop manually and use uv_loop_init instead.
*/
UV_EXTERN uv_loop_t* uv_loop_new(void);
/*
* NOTE:
* This function is DEPRECATED (to be removed after 0.12). Users should use
* This function is DEPRECATED. Users should use
* uv_loop_close and free the memory manually instead.
*/
UV_EXTERN void uv_loop_delete(uv_loop_t*);
@@ -337,11 +349,32 @@ typedef void (*uv_random_cb)(uv_random_t* req,
void* buf,
size_t buflen);
typedef enum {
UV_CLOCK_MONOTONIC,
UV_CLOCK_REALTIME
} uv_clock_id;
/* XXX(bnoordhuis) not 2038-proof, https://github.com/libuv/libuv/issues/3864 */
typedef struct {
long tv_sec;
long tv_nsec;
} uv_timespec_t;
typedef struct {
int64_t tv_sec;
int32_t tv_nsec;
} uv_timespec64_t;
/* XXX(bnoordhuis) not 2038-proof, https://github.com/libuv/libuv/issues/3864 */
typedef struct {
long tv_sec;
long tv_usec;
} uv_timeval_t;
typedef struct {
int64_t tv_sec;
int32_t tv_usec;
} uv_timeval64_t;
typedef struct {
uint64_t st_dev;
@@ -430,7 +463,7 @@ struct uv_shutdown_s {
uv_handle_type type; \
/* private */ \
uv_close_cb close_cb; \
void* handle_queue[2]; \
struct uv__queue handle_queue; \
union { \
int fd; \
void* reserved[4]; \
@@ -766,6 +799,10 @@ inline int uv_tty_set_mode(uv_tty_t* handle, int mode) {
UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
enum {
UV_PIPE_NO_TRUNCATE = 1u << 0
};
/*
* uv_pipe_t is a subclass of uv_stream_t.
*
@@ -782,10 +819,20 @@ struct uv_pipe_s {
UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file);
UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
UV_EXTERN int uv_pipe_bind2(uv_pipe_t* handle,
const char* name,
size_t namelen,
unsigned int flags);
UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
uv_pipe_t* handle,
const char* name,
uv_connect_cb cb);
UV_EXTERN int uv_pipe_connect2(uv_connect_t* req,
uv_pipe_t* handle,
const char* name,
size_t namelen,
unsigned int flags,
uv_connect_cb cb);
UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
char* buffer,
size_t* size);
@@ -1126,6 +1173,12 @@ struct uv_passwd_s {
char* homedir;
};
struct uv_group_s {
char* groupname;
unsigned long gid;
char** members;
};
struct uv_utsname_s {
char sysname[256];
char release[256];
@@ -1171,16 +1224,6 @@ UV_EXTERN int uv_uptime(double* uptime);
UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd);
UV_EXTERN int uv_open_osfhandle(uv_os_fd_t os_fd);
typedef struct {
long tv_sec;
long tv_usec;
} uv_timeval_t;
typedef struct {
int64_t tv_sec;
int32_t tv_usec;
} uv_timeval64_t;
typedef struct {
uv_timeval_t ru_utime; /* user CPU time used */
uv_timeval_t ru_stime; /* system CPU time used */
@@ -1206,6 +1249,9 @@ UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd);
UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
UV_EXTERN int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid);
UV_EXTERN int uv_os_get_group(uv_group_t* grp, uv_uid_t gid);
UV_EXTERN void uv_os_free_group(uv_group_t* grp);
UV_EXTERN uv_pid_t uv_os_getpid(void);
UV_EXTERN uv_pid_t uv_os_getppid(void);
@@ -1232,6 +1278,7 @@ UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
UV_EXTERN unsigned int uv_available_parallelism(void);
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
UV_EXTERN int uv_cpumask_size(void);
UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
int* count);
@@ -1264,6 +1311,15 @@ UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size);
UV_EXTERN int uv_os_uname(uv_utsname_t* buffer);
struct uv_metrics_s {
uint64_t loop_count;
uint64_t events;
uint64_t events_waiting;
/* private */
uint64_t* reserved[13];
};
UV_EXTERN int uv_metrics_info(uv_loop_t* loop, uv_metrics_t* metrics);
UV_EXTERN uint64_t uv_metrics_idle_time(uv_loop_t* loop);
typedef enum {
@@ -1697,6 +1753,7 @@ UV_EXTERN int uv_chdir(const char* dir);
UV_EXTERN uint64_t uv_get_free_memory(void);
UV_EXTERN uint64_t uv_get_total_memory(void);
UV_EXTERN uint64_t uv_get_constrained_memory(void);
UV_EXTERN uint64_t uv_get_available_memory(void);
UV_EXTERN uint64_t uv_hrtime(void);
UV_EXTERN void uv_sleep(unsigned int msec);
@@ -1774,6 +1831,14 @@ UV_EXTERN int uv_thread_create_ex(uv_thread_t* tid,
const uv_thread_options_t* params,
uv_thread_cb entry,
void* arg);
UV_EXTERN int uv_thread_setaffinity(uv_thread_t* tid,
char* cpumask,
char* oldmask,
size_t mask_size);
UV_EXTERN int uv_thread_getaffinity(uv_thread_t* tid,
char* cpumask,
size_t mask_size);
UV_EXTERN int uv_thread_getcpu(void);
UV_EXTERN uv_thread_t uv_thread_self(void);
UV_EXTERN int uv_thread_join(uv_thread_t *tid);
UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2);
@@ -1795,7 +1860,7 @@ struct uv_loop_s {
void* data;
/* Loop reference counting. */
unsigned int active_handles;
void* handle_queue[2];
struct uv__queue handle_queue;
union {
void* unused;
unsigned int count;

View File

@@ -40,7 +40,7 @@
void* cf_state; \
uv_mutex_t cf_mutex; \
uv_sem_t cf_sem; \
void* cf_signals[2]; \
struct uv__queue cf_signals; \
#define UV_PLATFORM_FS_EVENT_FIELDS \
uv__io_t event_watcher; \
@@ -48,8 +48,8 @@
int realpath_len; \
int cf_flags; \
uv_async_t* cf_cb; \
void* cf_events[2]; \
void* cf_member[2]; \
struct uv__queue cf_events; \
struct uv__queue cf_member; \
int cf_error; \
uv_mutex_t cf_mutex; \

View File

@@ -413,7 +413,6 @@
#elif defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__)
# define UV__EHOSTDOWN (-64)
@@ -457,4 +456,22 @@
# define UV__ESOCKTNOSUPPORT (-4025)
#endif
/* FreeBSD defines ENODATA in /usr/include/c++/v1/errno.h which is only visible
* if C++ is being used. Define it directly to avoid problems when integrating
* libuv in a C++ project.
*/
#if defined(ENODATA) && !defined(_WIN32)
# define UV__ENODATA UV__ERR(ENODATA)
#elif defined(__FreeBSD__)
# define UV__ENODATA (-9919)
#else
# define UV__ENODATA (-4024)
#endif
#if defined(EUNATCH) && !defined(_WIN32)
# define UV__EUNATCH UV__ERR(EUNATCH)
#else
# define UV__EUNATCH (-4023)
#endif
#endif /* UV_ERRNO_H_ */

View File

@@ -28,7 +28,7 @@
int inotify_fd; \
#define UV_PLATFORM_FS_EVENT_FIELDS \
void* watchers[2]; \
struct uv__queue watchers; \
int wd; \
#endif /* UV_LINUX_H */

View File

@@ -31,7 +31,7 @@ struct uv__work {
void (*work)(struct uv__work *w);
void (*done)(struct uv__work *w, int status);
struct uv_loop_s* loop;
void* wq[2];
struct uv__queue wq;
};
#endif /* UV_THREADPOOL_H_ */

View File

@@ -51,7 +51,6 @@
# include "uv/darwin.h"
#elif defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
# include "uv/bsd.h"
@@ -85,8 +84,8 @@ typedef struct uv__io_s uv__io_t;
struct uv__io_s {
uv__io_cb cb;
void* pending_queue[2];
void* watcher_queue[2];
struct uv__queue pending_queue;
struct uv__queue watcher_queue;
unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
unsigned int events; /* Current event mask. */
int fd;
@@ -213,21 +212,21 @@ typedef struct {
#define UV_LOOP_PRIVATE_FIELDS \
unsigned long flags; \
int backend_fd; \
void* pending_queue[2]; \
void* watcher_queue[2]; \
void** watchers; \
struct uv__queue pending_queue; \
struct uv__queue watcher_queue; \
uv__io_t** watchers; \
unsigned int nwatchers; \
unsigned int nfds; \
void* wq[2]; \
struct uv__queue wq; \
uv_mutex_t wq_mutex; \
uv_async_t wq_async; \
uv_rwlock_t cloexec_lock; \
uv_handle_t* closing_handles; \
void* process_handles[2]; \
void* prepare_handles[2]; \
void* check_handles[2]; \
void* idle_handles[2]; \
void* async_handles[2]; \
struct uv__queue process_handles; \
struct uv__queue prepare_handles; \
struct uv__queue check_handles; \
struct uv__queue idle_handles; \
struct uv__queue async_handles; \
void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \
uv__io_t async_io_watcher; \
int async_wfd; \
@@ -250,7 +249,7 @@ typedef struct {
#define UV_PRIVATE_REQ_TYPES /* empty */
#define UV_WRITE_PRIVATE_FIELDS \
void* queue[2]; \
struct uv__queue queue; \
unsigned int write_index; \
uv_buf_t* bufs; \
unsigned int nbufs; \
@@ -258,12 +257,12 @@ typedef struct {
uv_buf_t bufsml[4]; \
#define UV_CONNECT_PRIVATE_FIELDS \
void* queue[2]; \
struct uv__queue queue; \
#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
#define UV_UDP_SEND_PRIVATE_FIELDS \
void* queue[2]; \
struct uv__queue queue; \
struct sockaddr_storage addr; \
unsigned int nbufs; \
uv_buf_t* bufs; \
@@ -279,8 +278,8 @@ typedef struct {
uv_connect_t *connect_req; \
uv_shutdown_t *shutdown_req; \
uv__io_t io_watcher; \
void* write_queue[2]; \
void* write_completed_queue[2]; \
struct uv__queue write_queue; \
struct uv__queue write_completed_queue; \
uv_connection_cb connection_cb; \
int delayed_error; \
int accepted_fd; \
@@ -293,30 +292,30 @@ typedef struct {
uv_alloc_cb alloc_cb; \
uv_udp_recv_cb recv_cb; \
uv__io_t io_watcher; \
void* write_queue[2]; \
void* write_completed_queue[2]; \
struct uv__queue write_queue; \
struct uv__queue write_completed_queue; \
#define UV_PIPE_PRIVATE_FIELDS \
const char* pipe_fname; /* strdup'ed */
const char* pipe_fname; /* NULL or strdup'ed */
#define UV_POLL_PRIVATE_FIELDS \
uv__io_t io_watcher;
#define UV_PREPARE_PRIVATE_FIELDS \
uv_prepare_cb prepare_cb; \
void* queue[2]; \
struct uv__queue queue; \
#define UV_CHECK_PRIVATE_FIELDS \
uv_check_cb check_cb; \
void* queue[2]; \
struct uv__queue queue; \
#define UV_IDLE_PRIVATE_FIELDS \
uv_idle_cb idle_cb; \
void* queue[2]; \
struct uv__queue queue; \
#define UV_ASYNC_PRIVATE_FIELDS \
uv_async_cb async_cb; \
void* queue[2]; \
struct uv__queue queue; \
int pending; \
#define UV_TIMER_PRIVATE_FIELDS \
@@ -345,7 +344,7 @@ typedef struct {
int retcode;
#define UV_PROCESS_PRIVATE_FIELDS \
void* queue[2]; \
struct uv__queue queue; \
int status; \
#define UV_FS_PRIVATE_FIELDS \
@@ -410,6 +409,8 @@ typedef struct {
# define UV_FS_O_DIRECT 0x04000
#elif defined(__linux__) && defined(__x86_64__)
# define UV_FS_O_DIRECT 0x04000
#elif defined(__linux__) && defined(__loongarch__)
# define UV_FS_O_DIRECT 0x04000
#elif defined(O_DIRECT)
# define UV_FS_O_DIRECT O_DIRECT
#else

View File

@@ -31,8 +31,8 @@
*/
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 44
#define UV_VERSION_PATCH 2
#define UV_VERSION_MINOR 46
#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""

View File

@@ -59,7 +59,6 @@ typedef struct pollfd {
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdint.h>
#include "uv/tree.h"
@@ -71,6 +70,11 @@ typedef struct pollfd {
# define S_IFLNK 0xA000
#endif
// Define missing in Windows Kit Include\{VERSION}\ucrt\sys\stat.h
#if defined(_CRT_INTERNAL_NONSTDC_NAMES) && _CRT_INTERNAL_NONSTDC_NAMES && !defined(S_IFIFO)
# define S_IFIFO _S_IFIFO
#endif
/* Additional signals supported by uv_signal and or uv_kill. The CRT defines
* the following signals already:
*
@@ -275,11 +279,12 @@ typedef struct {
} uv_rwlock_t;
typedef struct {
unsigned int n;
unsigned int count;
unsigned threshold;
unsigned in;
uv_mutex_t mutex;
uv_sem_t turnstile1;
uv_sem_t turnstile2;
/* TODO: in v2 make this a uv_cond_t, without unused_ */
CONDITION_VARIABLE cond;
unsigned out;
} uv_barrier_t;
typedef struct {
@@ -349,14 +354,14 @@ typedef struct {
uv_idle_t* next_idle_handle; \
/* This handle holds the peer sockets for the fast variant of uv_poll_t */ \
SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \
/* Counter to keep track of active tcp streams */ \
/* No longer used. */ \
unsigned int active_tcp_streams; \
/* Counter to keep track of active udp streams */ \
/* No longer used. */ \
unsigned int active_udp_streams; \
/* Counter to started timer */ \
uint64_t timer_counter; \
/* Threadpool */ \
void* wq[2]; \
struct uv__queue wq; \
uv_mutex_t wq_mutex; \
uv_async_t wq_async;
@@ -383,6 +388,7 @@ typedef struct {
ULONG_PTR result; /* overlapped.Internal is reused to hold the result */\
HANDLE pipeHandle; \
DWORD duplex_flags; \
WCHAR* name; \
} connect; \
} u; \
struct uv_req_s* next_req;
@@ -484,7 +490,7 @@ typedef struct {
uint32_t payload_remaining; \
uint64_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
} ipc_data_frame; \
void* ipc_xfer_queue[2]; \
struct uv__queue ipc_xfer_queue; \
int ipc_xfer_queue_length; \
uv_write_t* non_overlapped_writes_tail; \
CRITICAL_SECTION readfile_thread_lock; \
@@ -498,7 +504,7 @@ typedef struct {
struct { uv_pipe_connection_fields } conn; \
} pipe;
/* TODO: put the parser states in an union - TTY handles are always half-duplex
/* TODO: put the parser states in a union - TTY handles are always half-duplex
* so read-state can safely overlap write-state. */
#define UV_TTY_PRIVATE_FIELDS \
HANDLE handle; \
@@ -606,7 +612,7 @@ typedef struct {
struct uv_process_exit_s { \
UV_REQ_FIELDS \
} exit_req; \
BYTE* child_stdio_buffer; \
void* unused; /* TODO: retained for ABI compat; remove this in v2.x. */ \
int exit_signal; \
HANDLE wait_handle; \
HANDLE process_handle; \

View File

@@ -17,12 +17,7 @@
#include <stdio.h>
#include <string.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
# include "uv/stdint-msvc2008.h"
#else
# include <stdint.h>
#endif
#include <stdint.h>
#include "uv.h"
#include "uv-common.h"
@@ -139,14 +134,7 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
tp += strlen(tp);
break;
}
#if defined(__APPLE__) && defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif // defined(__APPLE__) && defined(__clang__)
tp += sprintf(tp, "%x", words[i]);
#if defined(__APPLE__) && defined(__clang__)
#pragma clang diagnostic pop
#endif // defined(__APPLE__) && defined(__clang__)
tp += snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))

View File

@@ -18,107 +18,73 @@
#include <stddef.h>
typedef void *QUEUE[2];
#define uv__queue_data(pointer, type, field) \
((type*) ((char*) (pointer) - offsetof(type, field)))
/* Private macros. */
#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
#define uv__queue_foreach(q, h) \
for ((q) = (h)->next; (q) != (h); (q) = (q)->next)
/* Public macros. */
#define QUEUE_DATA(ptr, type, field) \
((type *) ((char *) (ptr) - offsetof(type, field)))
static inline void uv__queue_init(struct uv__queue* q) {
q->next = q;
q->prev = q;
}
/* Important note: mutating the list while QUEUE_FOREACH is
* iterating over its elements results in undefined behavior.
*/
#define QUEUE_FOREACH(q, h) \
for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
static inline int uv__queue_empty(const struct uv__queue* q) {
return q == q->next;
}
#define QUEUE_EMPTY(q) \
((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
static inline struct uv__queue* uv__queue_head(const struct uv__queue* q) {
return q->next;
}
#define QUEUE_HEAD(q) \
(QUEUE_NEXT(q))
static inline struct uv__queue* uv__queue_next(const struct uv__queue* q) {
return q->next;
}
#define QUEUE_INIT(q) \
do { \
QUEUE_NEXT(q) = (q); \
QUEUE_PREV(q) = (q); \
} \
while (0)
static inline void uv__queue_add(struct uv__queue* h, struct uv__queue* n) {
h->prev->next = n->next;
n->next->prev = h->prev;
h->prev = n->prev;
h->prev->next = h;
}
#define QUEUE_ADD(h, n) \
do { \
QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
QUEUE_PREV(h) = QUEUE_PREV(n); \
QUEUE_PREV_NEXT(h) = (h); \
} \
while (0)
static inline void uv__queue_split(struct uv__queue* h,
struct uv__queue* q,
struct uv__queue* n) {
n->prev = h->prev;
n->prev->next = n;
n->next = q;
h->prev = q->prev;
h->prev->next = h;
q->prev = n;
}
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12
#define QUEUE_SPLIT(h, q, n) \
do { \
QUEUE_PREV(n) = QUEUE_PREV(h); \
QUEUE_PREV_NEXT(n) = (n); \
QUEUE_NEXT(n) = (q); \
QUEUE_PREV(h) = QUEUE_PREV(q); \
QUEUE_PREV_NEXT(h) = (h); \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdangling-pointer=\"") \
QUEUE_PREV(q) = (n); \
_Pragma("GCC diagnostic pop") \
} \
while (0)
#else
#define QUEUE_SPLIT(h, q, n) \
do { \
QUEUE_PREV(n) = QUEUE_PREV(h); \
QUEUE_PREV_NEXT(n) = (n); \
QUEUE_NEXT(n) = (q); \
QUEUE_PREV(h) = QUEUE_PREV(q); \
QUEUE_PREV_NEXT(h) = (h); \
QUEUE_PREV(q) = (n); \
} \
while (0)
#endif // defined(__GNUC__) && !defined(__clang__)
static inline void uv__queue_move(struct uv__queue* h, struct uv__queue* n) {
if (uv__queue_empty(h))
uv__queue_init(n);
else
uv__queue_split(h, h->next, n);
}
#define QUEUE_MOVE(h, n) \
do { \
if (QUEUE_EMPTY(h)) \
QUEUE_INIT(n); \
else { \
QUEUE* q = QUEUE_HEAD(h); \
QUEUE_SPLIT(h, q, n); \
} \
} \
while (0)
static inline void uv__queue_insert_head(struct uv__queue* h,
struct uv__queue* q) {
q->next = h->next;
q->prev = h;
q->next->prev = q;
h->next = q;
}
#define QUEUE_INSERT_HEAD(h, q) \
do { \
QUEUE_NEXT(q) = QUEUE_NEXT(h); \
QUEUE_PREV(q) = (h); \
QUEUE_NEXT_PREV(q) = (q); \
QUEUE_NEXT(h) = (q); \
} \
while (0)
static inline void uv__queue_insert_tail(struct uv__queue* h,
struct uv__queue* q) {
q->next = h;
q->prev = h->prev;
q->prev->next = q;
h->prev = q;
}
#define QUEUE_INSERT_TAIL(h, q) \
do { \
QUEUE_NEXT(q) = (h); \
QUEUE_PREV(q) = QUEUE_PREV(h); \
QUEUE_PREV_NEXT(q) = (q); \
QUEUE_PREV(h) = (q); \
} \
while (0)
#define QUEUE_REMOVE(q) \
do { \
QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
} \
while (0)
static inline void uv__queue_remove(struct uv__queue* q) {
q->prev->next = q->next;
q->next->prev = q->prev;
}
#endif /* QUEUE_H_ */

View File

@@ -0,0 +1,175 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "uv-common.h"
#include <stdlib.h>
#ifndef _WIN32
#include <pthread.h>
#endif
#if defined(PTHREAD_BARRIER_SERIAL_THREAD)
STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
#endif
/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */
#if defined(_AIX) || \
defined(__OpenBSD__) || \
!defined(PTHREAD_BARRIER_SERIAL_THREAD)
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
int rc;
#ifdef _WIN32
uv_barrier_t* b;
b = barrier;
if (barrier == NULL || count == 0)
return UV_EINVAL;
#else
struct _uv_barrier* b;
if (barrier == NULL || count == 0)
return UV_EINVAL;
b = (struct _uv_barrier *)uv__malloc(sizeof(*b));
if (b == NULL)
return UV_ENOMEM;
#endif
b->in = 0;
b->out = 0;
b->threshold = count;
rc = uv_mutex_init(&b->mutex);
if (rc != 0)
goto error2;
/* TODO(vjnash): remove these uv_cond_t casts in v2. */
rc = uv_cond_init((uv_cond_t*) &b->cond);
if (rc != 0)
goto error;
#ifndef _WIN32
barrier->b = b;
#endif
return 0;
error:
uv_mutex_destroy(&b->mutex);
error2:
#ifndef _WIN32
uv__free(b);
#endif
return rc;
}
int uv_barrier_wait(uv_barrier_t* barrier) {
int last;
#ifdef _WIN32
uv_barrier_t* b;
b = barrier;
#else
struct _uv_barrier* b;
if (barrier == NULL || barrier->b == NULL)
return UV_EINVAL;
b = barrier->b;
#endif
uv_mutex_lock(&b->mutex);
while (b->out != 0)
uv_cond_wait((uv_cond_t*) &b->cond, &b->mutex);
if (++b->in == b->threshold) {
b->in = 0;
b->out = b->threshold;
uv_cond_broadcast((uv_cond_t*) &b->cond);
} else {
do
uv_cond_wait((uv_cond_t*) &b->cond, &b->mutex);
while (b->in != 0);
}
last = (--b->out == 0);
if (last)
uv_cond_broadcast((uv_cond_t*) &b->cond);
uv_mutex_unlock(&b->mutex);
return last;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
#ifdef _WIN32
uv_barrier_t* b;
b = barrier;
#else
struct _uv_barrier* b;
b = barrier->b;
#endif
uv_mutex_lock(&b->mutex);
assert(b->in == 0);
while (b->out != 0)
uv_cond_wait((uv_cond_t*) &b->cond, &b->mutex);
if (b->in != 0)
abort();
uv_mutex_unlock(&b->mutex);
uv_mutex_destroy(&b->mutex);
uv_cond_destroy((uv_cond_t*) &b->cond);
#ifndef _WIN32
uv__free(barrier->b);
barrier->b = NULL;
#endif
}
#else
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
}
int uv_barrier_wait(uv_barrier_t* barrier) {
int rc;
rc = pthread_barrier_wait(barrier);
if (rc != 0)
if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
abort();
return rc == PTHREAD_BARRIER_SERIAL_THREAD;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
if (pthread_barrier_destroy(barrier))
abort();
}
#endif

View File

@@ -41,10 +41,10 @@ static unsigned int slow_io_work_running;
static unsigned int nthreads;
static uv_thread_t* threads;
static uv_thread_t default_threads[4];
static QUEUE exit_message;
static QUEUE wq;
static QUEUE run_slow_work_message;
static QUEUE slow_io_pending_wq;
static struct uv__queue exit_message;
static struct uv__queue wq;
static struct uv__queue run_slow_work_message;
static struct uv__queue slow_io_pending_wq;
static unsigned int slow_work_thread_threshold(void) {
return (nthreads + 1) / 2;
@@ -60,7 +60,7 @@ static void uv__cancelled(struct uv__work* w) {
*/
static void worker(void* arg) {
struct uv__work* w;
QUEUE* q;
struct uv__queue* q;
int is_slow_work;
uv_sem_post((uv_sem_t*) arg);
@@ -72,49 +72,49 @@ static void worker(void* arg) {
/* Keep waiting while either no work is present or only slow I/O
and we're at the threshold for that. */
while (QUEUE_EMPTY(&wq) ||
(QUEUE_HEAD(&wq) == &run_slow_work_message &&
QUEUE_NEXT(&run_slow_work_message) == &wq &&
while (uv__queue_empty(&wq) ||
(uv__queue_head(&wq) == &run_slow_work_message &&
uv__queue_next(&run_slow_work_message) == &wq &&
slow_io_work_running >= slow_work_thread_threshold())) {
idle_threads += 1;
uv_cond_wait(&cond, &mutex);
idle_threads -= 1;
}
q = QUEUE_HEAD(&wq);
q = uv__queue_head(&wq);
if (q == &exit_message) {
uv_cond_signal(&cond);
uv_mutex_unlock(&mutex);
break;
}
QUEUE_REMOVE(q);
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */
uv__queue_remove(q);
uv__queue_init(q); /* Signal uv_cancel() that the work req is executing. */
is_slow_work = 0;
if (q == &run_slow_work_message) {
/* If we're at the slow I/O threshold, re-schedule until after all
other work in the queue is done. */
if (slow_io_work_running >= slow_work_thread_threshold()) {
QUEUE_INSERT_TAIL(&wq, q);
uv__queue_insert_tail(&wq, q);
continue;
}
/* If we encountered a request to run slow I/O work but there is none
to run, that means it's cancelled => Start over. */
if (QUEUE_EMPTY(&slow_io_pending_wq))
if (uv__queue_empty(&slow_io_pending_wq))
continue;
is_slow_work = 1;
slow_io_work_running++;
q = QUEUE_HEAD(&slow_io_pending_wq);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
q = uv__queue_head(&slow_io_pending_wq);
uv__queue_remove(q);
uv__queue_init(q);
/* If there is more slow I/O work, schedule it to be run as well. */
if (!QUEUE_EMPTY(&slow_io_pending_wq)) {
QUEUE_INSERT_TAIL(&wq, &run_slow_work_message);
if (!uv__queue_empty(&slow_io_pending_wq)) {
uv__queue_insert_tail(&wq, &run_slow_work_message);
if (idle_threads > 0)
uv_cond_signal(&cond);
}
@@ -122,13 +122,13 @@ static void worker(void* arg) {
uv_mutex_unlock(&mutex);
w = QUEUE_DATA(q, struct uv__work, wq);
w = uv__queue_data(q, struct uv__work, wq);
w->work(w);
uv_mutex_lock(&w->loop->wq_mutex);
w->work = NULL; /* Signal uv_cancel() that the work req is done
executing. */
QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
uv__queue_insert_tail(&w->loop->wq, &w->wq);
uv_async_send(&w->loop->wq_async);
uv_mutex_unlock(&w->loop->wq_mutex);
@@ -143,12 +143,12 @@ static void worker(void* arg) {
}
static void post(QUEUE* q, enum uv__work_kind kind) {
static void post(struct uv__queue* q, enum uv__work_kind kind) {
uv_mutex_lock(&mutex);
if (kind == UV__WORK_SLOW_IO) {
/* Insert into a separate queue. */
QUEUE_INSERT_TAIL(&slow_io_pending_wq, q);
if (!QUEUE_EMPTY(&run_slow_work_message)) {
uv__queue_insert_tail(&slow_io_pending_wq, q);
if (!uv__queue_empty(&run_slow_work_message)) {
/* Running slow I/O tasks is already scheduled => Nothing to do here.
The worker that runs said other task will schedule this one as well. */
uv_mutex_unlock(&mutex);
@@ -157,7 +157,7 @@ static void post(QUEUE* q, enum uv__work_kind kind) {
q = &run_slow_work_message;
}
QUEUE_INSERT_TAIL(&wq, q);
uv__queue_insert_tail(&wq, q);
if (idle_threads > 0)
uv_cond_signal(&cond);
uv_mutex_unlock(&mutex);
@@ -195,6 +195,7 @@ void uv__threadpool_cleanup(void) {
static void init_threads(void) {
uv_thread_options_t config;
unsigned int i;
const char* val;
uv_sem_t sem;
@@ -223,15 +224,18 @@ static void init_threads(void) {
if (uv_mutex_init(&mutex))
abort();
QUEUE_INIT(&wq);
QUEUE_INIT(&slow_io_pending_wq);
QUEUE_INIT(&run_slow_work_message);
uv__queue_init(&wq);
uv__queue_init(&slow_io_pending_wq);
uv__queue_init(&run_slow_work_message);
if (uv_sem_init(&sem, 0))
abort();
config.flags = UV_THREAD_HAS_STACK_SIZE;
config.stack_size = 8u << 20; /* 8 MB */
for (i = 0; i < nthreads; i++)
if (uv_thread_create(threads + i, worker, &sem))
if (uv_thread_create_ex(threads + i, &config, worker, &sem))
abort();
for (i = 0; i < nthreads; i++)
@@ -275,15 +279,19 @@ void uv__work_submit(uv_loop_t* loop,
}
/* TODO(bnoordhuis) teach libuv how to cancel file operations
* that go through io_uring instead of the thread pool.
*/
static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
int cancelled;
uv_once(&once, init_once); /* Ensure |mutex| is initialized. */
uv_mutex_lock(&mutex);
uv_mutex_lock(&w->loop->wq_mutex);
cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
cancelled = !uv__queue_empty(&w->wq) && w->work != NULL;
if (cancelled)
QUEUE_REMOVE(&w->wq);
uv__queue_remove(&w->wq);
uv_mutex_unlock(&w->loop->wq_mutex);
uv_mutex_unlock(&mutex);
@@ -293,7 +301,7 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
w->work = uv__cancelled;
uv_mutex_lock(&loop->wq_mutex);
QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
uv__queue_insert_tail(&loop->wq, &w->wq);
uv_async_send(&loop->wq_async);
uv_mutex_unlock(&loop->wq_mutex);
@@ -304,22 +312,39 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
void uv__work_done(uv_async_t* handle) {
struct uv__work* w;
uv_loop_t* loop;
QUEUE* q;
QUEUE wq;
struct uv__queue* q;
struct uv__queue wq;
int err;
int nevents;
loop = container_of(handle, uv_loop_t, wq_async);
uv_mutex_lock(&loop->wq_mutex);
QUEUE_MOVE(&loop->wq, &wq);
uv__queue_move(&loop->wq, &wq);
uv_mutex_unlock(&loop->wq_mutex);
while (!QUEUE_EMPTY(&wq)) {
q = QUEUE_HEAD(&wq);
QUEUE_REMOVE(q);
nevents = 0;
while (!uv__queue_empty(&wq)) {
q = uv__queue_head(&wq);
uv__queue_remove(q);
w = container_of(q, struct uv__work, wq);
err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
w->done(w, err);
nevents++;
}
/* This check accomplishes 2 things:
* 1. Even if the queue was empty, the call to uv__work_done() should count
* as an event. Which will have been added by the event loop when
* calling this callback.
* 2. Prevents accidental wrap around in case nevents == 0 events == 0.
*/
if (nevents > 1) {
/* Subtract 1 to counter the call to uv__work_done(). */
uv__metrics_inc_events(loop, nevents - 1);
if (uv__get_internal_fields(loop)->current_timeout == 0)
uv__metrics_inc_events_waiting(loop, nevents - 1);
}
}

View File

@@ -24,7 +24,6 @@
#include "uv.h"
#include "internal.h"
#include "atomic-ops.h"
#include <errno.h>
#include <stdio.h> /* snprintf() */
@@ -38,8 +37,11 @@
#include <sys/eventfd.h>
#endif
#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);
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
@@ -52,8 +54,9 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
handle->async_cb = async_cb;
handle->pending = 0;
handle->u.fd = 0; /* This will be used as a busy flag. */
QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
uv__queue_insert_tail(&loop->async_handles, &handle->queue);
uv__handle_start(handle);
return 0;
@@ -61,46 +64,54 @@ 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) {
std::atomic<int>* pending;
std::atomic<int>* busy;
pending = (std::atomic<int>*) &handle->pending;
busy = (std::atomic<int>*) &handle->u.fd;
/* Do a cheap read first. */
if (ACCESS_ONCE(int, handle->pending) != 0)
if (atomic_load_explicit(pending, std::memory_order_relaxed) != 0)
return 0;
/* Tell the other thread we're busy with the handle. */
if (cmpxchgi(&handle->pending, 0, 1) != 0)
return 0;
/* Set the loop to busy. */
atomic_fetch_add(busy, 1);
/* Wake up the other thread's event loop. */
uv__async_send(handle->loop);
if (atomic_exchange(pending, 1) == 0)
uv__async_send(handle->loop);
/* Tell the other thread we're done. */
if (cmpxchgi(&handle->pending, 1, 2) != 1)
abort();
/* Set the loop to not-busy. */
atomic_fetch_add(busy, -1);
return 0;
}
/* Only call this from the event loop thread. */
static int uv__async_spin(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) {
std::atomic<int>* pending;
std::atomic<int>* busy;
int i;
int rc;
pending = (std::atomic<int>*) &handle->pending;
busy = (std::atomic<int>*) &handle->u.fd;
/* Set the pending flag first, so no new events will be added by other
* threads after this function returns. */
atomic_store(pending, 1);
for (;;) {
/* 997 is not completely chosen at random. It's a prime number, acyclical
* by nature, and should therefore hopefully dampen sympathetic resonance.
/* 997 is not completely chosen at random. It's a prime number, acyclic by
* nature, and should therefore hopefully dampen sympathetic resonance.
*/
for (i = 0; i < 997; i++) {
/* rc=0 -- handle is not pending.
* rc=1 -- handle is pending, other thread is still working with it.
* rc=2 -- handle is pending, other thread is done.
*/
rc = cmpxchgi(&handle->pending, 2, 0);
if (rc != 1)
return rc;
if (atomic_load(busy) == 0)
return;
/* Other thread is busy with this handle, spin until it's done. */
cpu_relax();
uv__cpu_relax();
}
/* Yield the CPU. We may have preempted the other thread while it's
@@ -114,7 +125,7 @@ static int uv__async_spin(uv_async_t* handle) {
void uv__async_close(uv_async_t* handle) {
uv__async_spin(handle);
QUEUE_REMOVE(&handle->queue);
uv__queue_remove(&handle->queue);
uv__handle_stop(handle);
}
@@ -122,9 +133,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) {
char buf[1024];
ssize_t r;
QUEUE queue;
QUEUE* q;
struct uv__queue queue;
struct uv__queue* q;
uv_async_t* h;
std::atomic<int> *pending;
assert(w == &loop->async_io_watcher);
@@ -146,16 +158,18 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
abort();
}
QUEUE_MOVE(&loop->async_handles, &queue);
while (!QUEUE_EMPTY(&queue)) {
q = QUEUE_HEAD(&queue);
h = QUEUE_DATA(q, uv_async_t, queue);
uv__queue_move(&loop->async_handles, &queue);
while (!uv__queue_empty(&queue)) {
q = uv__queue_head(&queue);
h = uv__queue_data(q, uv_async_t, queue);
QUEUE_REMOVE(q);
QUEUE_INSERT_TAIL(&loop->async_handles, q);
uv__queue_remove(q);
uv__queue_insert_tail(&loop->async_handles, q);
if (0 == uv__async_spin(h))
continue; /* Not pending. */
/* Atomically fetch and clear pending flag */
pending = (std::atomic<int>*) &h->pending;
if (atomic_exchange(pending, 0) == 0)
continue;
if (h->async_cb == NULL)
continue;
@@ -227,20 +241,28 @@ static int uv__async_start(uv_loop_t* loop) {
}
int uv__async_fork(uv_loop_t* loop) {
if (loop->async_io_watcher.fd == -1) /* never started */
return 0;
uv__async_stop(loop);
return uv__async_start(loop);
}
void uv__async_stop(uv_loop_t* loop) {
struct uv__queue queue;
struct uv__queue* q;
uv_async_t* h;
if (loop->async_io_watcher.fd == -1)
return;
/* Make sure no other thread is accessing the async handle fd after the loop
* cleanup.
*/
uv__queue_move(&loop->async_handles, &queue);
while (!uv__queue_empty(&queue)) {
q = uv__queue_head(&queue);
h = uv__queue_data(q, uv_async_t, queue);
uv__queue_remove(q);
uv__queue_insert_tail(&loop->async_handles, q);
uv__async_spin(h);
}
if (loop->async_wfd != -1) {
if (loop->async_wfd != loop->async_io_watcher.fd)
uv__close(loop->async_wfd);
@@ -251,3 +273,58 @@ void uv__async_stop(uv_loop_t* loop) {
uv__close(loop->async_io_watcher.fd);
loop->async_io_watcher.fd = -1;
}
int uv__async_fork(uv_loop_t* loop) {
struct uv__queue queue;
struct uv__queue* q;
uv_async_t* h;
if (loop->async_io_watcher.fd == -1) /* never started */
return 0;
uv__queue_move(&loop->async_handles, &queue);
while (!uv__queue_empty(&queue)) {
q = uv__queue_head(&queue);
h = uv__queue_data(q, uv_async_t, queue);
uv__queue_remove(q);
uv__queue_insert_tail(&loop->async_handles, q);
/* The state of any thread that set pending is now likely corrupt in this
* child because the user called fork, so just clear these flags and move
* on. Calling most libc functions after `fork` is declared to be undefined
* behavior anyways, unless async-signal-safe, for multithreaded programs
* like libuv, and nothing interesting in pthreads is async-signal-safe.
*/
h->pending = 0;
/* This is the busy flag, and we just abruptly lost all other threads. */
h->u.fd = 0;
}
/* Recreate these, since they still exist, but belong to the wrong pid now. */
if (loop->async_wfd != -1) {
if (loop->async_wfd != loop->async_io_watcher.fd)
uv__close(loop->async_wfd);
loop->async_wfd = -1;
}
uv__io_stop(loop, &loop->async_io_watcher, POLLIN);
uv__close(loop->async_io_watcher.fd);
loop->async_io_watcher.fd = -1;
return uv__async_start(loop);
}
static void uv__cpu_relax(void) {
#if defined(__i386__) || defined(__x86_64__)
__asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
__asm__ __volatile__ ("yield" ::: "memory");
#elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__)
__asm volatile ("" : : : "memory");
#elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__))
__asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
#endif
}

View File

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

View File

@@ -41,12 +41,14 @@
#include <sys/uio.h> /* writev */
#include <sys/resource.h> /* getrusage */
#include <pwd.h>
#include <grp.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <time.h> /* clock_gettime */
#include <atomic>
#ifdef __sun
# include <sys/filio.h>
# include <sys/types.h>
# include <sys/wait.h>
#endif
@@ -66,13 +68,14 @@ extern char** environ;
#if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__)
# include <sys/sysctl.h>
# include <sys/filio.h>
# include <sys/wait.h>
# include <sys/param.h>
# if defined(__FreeBSD__)
# include <sys/cpuset.h>
# define uv__accept4 accept4
# endif
# if defined(__NetBSD__)
@@ -107,6 +110,35 @@ STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base));
STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
/* https://github.com/libuv/libuv/issues/1674 */
int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts) {
struct timespec t;
int r;
if (ts == NULL)
return UV_EFAULT;
switch (clock_id) {
default:
return UV_EINVAL;
case UV_CLOCK_MONOTONIC:
r = clock_gettime(CLOCK_MONOTONIC, &t);
break;
case UV_CLOCK_REALTIME:
r = clock_gettime(CLOCK_REALTIME, &t);
break;
}
if (r)
return UV__ERR(errno);
ts->tv_sec = t.tv_sec;
ts->tv_nsec = t.tv_nsec;
return 0;
}
uint64_t uv_hrtime(void) {
return uv__hrtime(UV_CLOCK_PRECISE);
}
@@ -232,10 +264,10 @@ int uv__getiovmax(void) {
#if defined(IOV_MAX)
return IOV_MAX;
#elif defined(_SC_IOV_MAX)
static int iovmax_cached = -1;
static std::atomic<int> iovmax_cached = -1;
int iovmax;
iovmax = uv__load_relaxed(&iovmax_cached);
iovmax = atomic_load_explicit(&iovmax_cached, memory_order_relaxed);
if (iovmax != -1)
return iovmax;
@@ -247,7 +279,7 @@ int uv__getiovmax(void) {
if (iovmax == -1)
iovmax = 1;
uv__store_relaxed(&iovmax_cached, iovmax);
atomic_store_explicit(&iovmax_cached, iovmax, memory_order_relaxed);
return iovmax;
#else
@@ -313,7 +345,7 @@ static void uv__finish_close(uv_handle_t* handle) {
}
uv__handle_unref(handle);
QUEUE_REMOVE(&handle->handle_queue);
uv__queue_remove(&handle->handle_queue);
if (handle->close_cb) {
handle->close_cb(handle);
@@ -349,7 +381,7 @@ int uv_backend_fd(const uv_loop_t* loop) {
static int uv__loop_alive(const uv_loop_t* loop) {
return uv__has_active_handles(loop) ||
uv__has_active_reqs(loop) ||
!QUEUE_EMPTY(&loop->pending_queue) ||
!uv__queue_empty(&loop->pending_queue) ||
loop->closing_handles != NULL;
}
@@ -358,8 +390,9 @@ static int uv__backend_timeout(const uv_loop_t* loop) {
if (loop->stop_flag == 0 &&
/* uv__loop_alive(loop) && */
(uv__has_active_handles(loop) || uv__has_active_reqs(loop)) &&
QUEUE_EMPTY(&loop->pending_queue) &&
QUEUE_EMPTY(&loop->idle_handles) &&
uv__queue_empty(&loop->pending_queue) &&
uv__queue_empty(&loop->idle_handles) &&
(loop->flags & UV_LOOP_REAP_CHILDREN) == 0 &&
loop->closing_handles == NULL)
return uv__next_timeout(loop);
return 0;
@@ -367,7 +400,7 @@ static int uv__backend_timeout(const uv_loop_t* loop) {
int uv_backend_timeout(const uv_loop_t* loop) {
if (QUEUE_EMPTY(&loop->watcher_queue))
if (uv__queue_empty(&loop->watcher_queue))
return uv__backend_timeout(loop);
/* Need to call uv_run to update the backend fd state. */
return 0;
@@ -388,12 +421,19 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
if (!r)
uv__update_time(loop);
while (r != 0 && loop->stop_flag == 0) {
/* Maintain backwards compatibility by processing timers before entering the
* while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed
* once, which should be done after polling in order to maintain proper
* execution order of the conceptual event loop. */
if (mode == UV_RUN_DEFAULT && r != 0 && loop->stop_flag == 0) {
uv__update_time(loop);
uv__run_timers(loop);
}
while (r != 0 && loop->stop_flag == 0) {
can_sleep =
QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles);
uv__queue_empty(&loop->pending_queue) &&
uv__queue_empty(&loop->idle_handles);
uv__run_pending(loop);
uv__run_idle(loop);
@@ -403,11 +443,13 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
timeout = uv__backend_timeout(loop);
uv__metrics_inc_loop_count(loop);
uv__io_poll(loop, timeout);
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
* times to avoid loop starvation.*/
for (r = 0; r < 8 && !QUEUE_EMPTY(&loop->pending_queue); r++)
for (r = 0; r < 8 && !uv__queue_empty(&loop->pending_queue); r++)
uv__run_pending(loop);
/* Run one final update on the provider_idle_time in case uv__io_poll
@@ -420,18 +462,8 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
uv__run_check(loop);
uv__run_closing_handles(loop);
if (mode == UV_RUN_ONCE) {
/* UV_RUN_ONCE implies forward progress: at least one callback must have
* been invoked when it returns. uv__io_poll() can return without doing
* I/O (meaning: no callbacks) when its timeout expires - which means we
* have pending timers that satisfy the forward progress constraint.
*
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
* the check.
*/
uv__update_time(loop);
uv__run_timers(loop);
}
uv__update_time(loop);
uv__run_timers(loop);
r = uv__loop_alive(loop);
if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
@@ -805,17 +837,17 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
static void uv__run_pending(uv_loop_t* loop) {
QUEUE* q;
QUEUE pq;
struct uv__queue* q;
struct uv__queue pq;
uv__io_t* w;
QUEUE_MOVE(&loop->pending_queue, &pq);
uv__queue_move(&loop->pending_queue, &pq);
while (!QUEUE_EMPTY(&pq)) {
q = QUEUE_HEAD(&pq);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, pending_queue);
while (!uv__queue_empty(&pq)) {
q = uv__queue_head(&pq);
uv__queue_remove(q);
uv__queue_init(q);
w = uv__queue_data(q, uv__io_t, pending_queue);
w->cb(loop, w, POLLOUT);
}
}
@@ -862,7 +894,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) {
watchers[nwatchers] = fake_watcher_list;
watchers[nwatchers + 1] = fake_watcher_count;
loop->watchers = watchers;
loop->watchers = (uv__io_t**)watchers;
loop->nwatchers = nwatchers;
}
@@ -870,17 +902,12 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) {
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
assert(cb != NULL);
assert(fd >= -1);
QUEUE_INIT(&w->pending_queue);
QUEUE_INIT(&w->watcher_queue);
uv__queue_init(&w->pending_queue);
uv__queue_init(&w->watcher_queue);
w->cb = cb;
w->fd = fd;
w->events = 0;
w->pevents = 0;
#if defined(UV_HAVE_KQUEUE)
w->rcount = 0;
w->wcount = 0;
#endif /* defined(UV_HAVE_KQUEUE) */
}
@@ -902,8 +929,8 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
return;
#endif
if (QUEUE_EMPTY(&w->watcher_queue))
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
if (uv__queue_empty(&w->watcher_queue))
uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
if (loop->watchers[w->fd] == NULL) {
loop->watchers[w->fd] = w;
@@ -928,8 +955,8 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
w->pevents &= ~events;
if (w->pevents == 0) {
QUEUE_REMOVE(&w->watcher_queue);
QUEUE_INIT(&w->watcher_queue);
uv__queue_remove(&w->watcher_queue);
uv__queue_init(&w->watcher_queue);
w->events = 0;
if (w == loop->watchers[w->fd]) {
@@ -938,14 +965,14 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
loop->nfds--;
}
}
else if (QUEUE_EMPTY(&w->watcher_queue))
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
else if (uv__queue_empty(&w->watcher_queue))
uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
}
void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
QUEUE_REMOVE(&w->pending_queue);
uv__queue_remove(&w->pending_queue);
/* Remove stale events for this file descriptor */
if (w->fd != -1)
@@ -954,8 +981,8 @@ void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
if (QUEUE_EMPTY(&w->pending_queue))
QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
if (uv__queue_empty(&w->pending_queue))
uv__queue_insert_tail(&loop->pending_queue, &w->pending_queue);
}
@@ -1000,6 +1027,15 @@ int uv_getrusage(uv_rusage_t* rusage) {
rusage->ru_nivcsw = usage.ru_nivcsw;
#endif
/* Most platforms report ru_maxrss in kilobytes; macOS and Solaris are
* the outliers because of course they are.
*/
#if defined(__APPLE__)
rusage->ru_maxrss /= 1024; /* macOS and iOS report bytes. */
#elif defined(__sun)
rusage->ru_maxrss /= getpagesize() / 1024; /* Solaris reports pages. */
#endif
return 0;
}
@@ -1099,8 +1135,8 @@ int uv_os_homedir(char* buffer, size_t* size) {
if (r != UV_ENOENT)
return r;
/* HOME is not set, so call uv__getpwuid_r() */
r = uv__getpwuid_r(&pwd);
/* HOME is not set, so call uv_os_get_passwd() */
r = uv_os_get_passwd(&pwd);
if (r != 0) {
return r;
@@ -1173,11 +1209,10 @@ return_buffer:
}
int uv__getpwuid_r(uv_passwd_t* pwd) {
static int uv__getpwuid_r(uv_passwd_t *pwd, uid_t uid) {
struct passwd pw;
struct passwd* result;
char* buf;
uid_t uid;
size_t bufsize;
size_t name_size;
size_t homedir_size;
@@ -1187,8 +1222,6 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
if (pwd == NULL)
return UV_EINVAL;
uid = geteuid();
/* Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it
* is frequently 1024 or 4096, so we can just use that directly. The pwent
* will not usually be large. */
@@ -1247,24 +1280,98 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
}
void uv_os_free_passwd(uv_passwd_t* pwd) {
if (pwd == NULL)
return;
int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
#if defined(__ANDROID__) && __ANDROID_API__ < 24
/* This function getgrgid_r() was added in Android N (level 24) */
return UV_ENOSYS;
#else
struct group gp;
struct group* result;
char* buf;
char* gr_mem;
size_t bufsize;
size_t name_size;
long members;
size_t mem_size;
int r;
/*
The memory for name, shell, and homedir are allocated in a single
uv__malloc() call. The base of the pointer is stored in pwd->username, so
that is the field that needs to be freed.
*/
uv__free(pwd->username);
pwd->username = NULL;
pwd->shell = NULL;
pwd->homedir = NULL;
if (grp == NULL)
return UV_EINVAL;
/* Calling sysconf(_SC_GETGR_R_SIZE_MAX) would get the suggested size, but it
* is frequently 1024 or 4096, so we can just use that directly. The pwent
* will not usually be large. */
for (bufsize = 2000;; bufsize *= 2) {
buf = (char*)uv__malloc(bufsize);
if (buf == NULL)
return UV_ENOMEM;
do
r = getgrgid_r(gid, &gp, buf, bufsize, &result);
while (r == EINTR);
if (r != 0 || result == NULL)
uv__free(buf);
if (r != ERANGE)
break;
}
if (r != 0)
return UV__ERR(r);
if (result == NULL)
return UV_ENOENT;
/* Allocate memory for the groupname and members. */
name_size = strlen(gp.gr_name) + 1;
members = 0;
mem_size = sizeof(char*);
for (r = 0; gp.gr_mem[r] != NULL; r++) {
mem_size += strlen(gp.gr_mem[r]) + 1 + sizeof(char*);
members++;
}
gr_mem = (char*)uv__malloc(name_size + mem_size);
if (gr_mem == NULL) {
uv__free(buf);
return UV_ENOMEM;
}
/* Copy the members */
grp->members = (char**) gr_mem;
grp->members[members] = NULL;
gr_mem = (char*) &grp->members[members + 1];
for (r = 0; r < members; r++) {
grp->members[r] = gr_mem;
strcpy(gr_mem, gp.gr_mem[r]);
gr_mem += strlen(gr_mem) + 1;
}
assert(gr_mem == (char*)grp->members + mem_size);
/* Copy the groupname */
grp->groupname = gr_mem;
memcpy(grp->groupname, gp.gr_name, name_size);
gr_mem += name_size;
/* Copy the gid */
grp->gid = gp.gr_gid;
uv__free(buf);
return 0;
#endif
}
int uv_os_get_passwd(uv_passwd_t* pwd) {
return uv__getpwuid_r(pwd);
return uv__getpwuid_r(pwd, geteuid());
}
int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) {
return uv__getpwuid_r(pwd, uid);
}
@@ -1425,6 +1532,13 @@ uv_pid_t uv_os_getppid(void) {
return getppid();
}
int uv_cpumask_size(void) {
#if UV__CPU_AFFINITY_SUPPORTED
return CPU_SETSIZE;
#else
return UV_ENOTSUP;
#endif
}
int uv_os_getpriority(uv_pid_t pid, int* priority) {
int r;

View File

@@ -51,3 +51,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}
uint64_t uv_get_available_memory(void) {
return uv_get_free_memory();
}

View File

@@ -27,7 +27,6 @@
struct CFArrayCallBacks;
struct CFRunLoopSourceContext;
struct FSEventStreamContext;
struct CFRange;
typedef double CFAbsoluteTime;
typedef double CFTimeInterval;
@@ -43,23 +42,13 @@ typedef unsigned CFStringEncoding;
typedef void* CFAllocatorRef;
typedef void* CFArrayRef;
typedef void* CFBundleRef;
typedef void* CFDataRef;
typedef void* CFDictionaryRef;
typedef void* CFMutableDictionaryRef;
typedef struct CFRange CFRange;
typedef void* CFRunLoopRef;
typedef void* CFRunLoopSourceRef;
typedef void* CFStringRef;
typedef void* CFTypeRef;
typedef void* FSEventStreamRef;
typedef uint32_t IOOptionBits;
typedef unsigned int io_iterator_t;
typedef unsigned int io_object_t;
typedef unsigned int io_service_t;
typedef unsigned int io_registry_entry_t;
typedef void (*FSEventStreamCallback)(const FSEventStreamRef,
void*,
size_t,
@@ -80,11 +69,6 @@ struct FSEventStreamContext {
void* pad[3];
};
struct CFRange {
CFIndex location;
CFIndex length;
};
static const CFStringEncoding kCFStringEncodingUTF8 = 0x8000100;
static const OSStatus noErr = 0;

View File

@@ -33,13 +33,10 @@
#include <sys/sysctl.h>
#include <unistd.h> /* sysconf */
#include "darwin-stub.h"
static uv_once_t once = UV_ONCE_INIT;
static uint64_t (*time_func)(void);
static mach_timebase_info_data_t timebase;
typedef unsigned char UInt8;
int uv__platform_loop_init(uv_loop_t* loop) {
loop->cf_state = NULL;
@@ -110,7 +107,7 @@ uint64_t uv_get_free_memory(void) {
if (host_statistics(mach_host_self(), HOST_VM_INFO,
(host_info_t)&info, &count) != KERN_SUCCESS) {
return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
return 0;
}
return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
@@ -123,7 +120,7 @@ uint64_t uv_get_total_memory(void) {
size_t size = sizeof(info);
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return 0;
return (uint64_t) info;
}
@@ -134,6 +131,11 @@ uint64_t uv_get_constrained_memory(void) {
}
uint64_t uv_get_available_memory(void) {
return uv_get_free_memory();
}
void uv_loadavg(double avg[3]) {
struct loadavg info;
size_t size = sizeof(info);
@@ -183,164 +185,17 @@ int uv_uptime(double* uptime) {
return 0;
}
static int uv__get_cpu_speed(uint64_t* speed) {
/* IOKit */
void (*pIOObjectRelease)(io_object_t);
kern_return_t (*pIOMasterPort)(mach_port_t, mach_port_t*);
CFMutableDictionaryRef (*pIOServiceMatching)(const char*);
kern_return_t (*pIOServiceGetMatchingServices)(mach_port_t,
CFMutableDictionaryRef,
io_iterator_t*);
io_service_t (*pIOIteratorNext)(io_iterator_t);
CFTypeRef (*pIORegistryEntryCreateCFProperty)(io_registry_entry_t,
CFStringRef,
CFAllocatorRef,
IOOptionBits);
/* CoreFoundation */
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
const char*,
CFStringEncoding);
CFStringEncoding (*pCFStringGetSystemEncoding)(void);
UInt8 *(*pCFDataGetBytePtr)(CFDataRef);
CFIndex (*pCFDataGetLength)(CFDataRef);
void (*pCFDataGetBytes)(CFDataRef, CFRange, UInt8*);
void (*pCFRelease)(CFTypeRef);
void* core_foundation_handle;
void* iokit_handle;
int err;
kern_return_t kr;
mach_port_t mach_port;
io_iterator_t it;
io_object_t service;
mach_port = 0;
err = UV_ENOENT;
core_foundation_handle = dlopen("/System/Library/Frameworks/"
"CoreFoundation.framework/"
"CoreFoundation",
RTLD_LAZY | RTLD_LOCAL);
iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/"
"IOKit",
RTLD_LAZY | RTLD_LOCAL);
if (core_foundation_handle == NULL || iokit_handle == NULL)
goto out;
#define V(handle, symbol) \
do { \
*(void **)(&p ## symbol) = dlsym((handle), #symbol); \
if (p ## symbol == NULL) \
goto out; \
} \
while (0)
V(iokit_handle, IOMasterPort);
V(iokit_handle, IOServiceMatching);
V(iokit_handle, IOServiceGetMatchingServices);
V(iokit_handle, IOIteratorNext);
V(iokit_handle, IOObjectRelease);
V(iokit_handle, IORegistryEntryCreateCFProperty);
V(core_foundation_handle, CFStringCreateWithCString);
V(core_foundation_handle, CFStringGetSystemEncoding);
V(core_foundation_handle, CFDataGetBytePtr);
V(core_foundation_handle, CFDataGetLength);
V(core_foundation_handle, CFDataGetBytes);
V(core_foundation_handle, CFRelease);
#undef V
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
// Braces ensure goto doesn't jump into device_type_str's and
// clock_frequency_str's lifetimes after their initialization
{
kr = pIOMasterPort(MACH_PORT_NULL, &mach_port);
(void) kr;
assert(kr == KERN_SUCCESS);
CFMutableDictionaryRef classes_to_match
= pIOServiceMatching("IOPlatformDevice");
kr = pIOServiceGetMatchingServices(mach_port, classes_to_match, &it);
assert(kr == KERN_SUCCESS);
service = pIOIteratorNext(it);
CFStringRef device_type_str = S("device_type");
CFStringRef clock_frequency_str = S("clock-frequency");
while (service != 0) {
CFDataRef data;
data = pIORegistryEntryCreateCFProperty(service,
device_type_str,
NULL,
0);
if (data) {
const UInt8* raw = pCFDataGetBytePtr(data);
if (strncmp((char*)raw, "cpu", 3) == 0 ||
strncmp((char*)raw, "processor", 9) == 0) {
CFDataRef freq_ref;
freq_ref = pIORegistryEntryCreateCFProperty(service,
clock_frequency_str,
NULL,
0);
if (freq_ref) {
const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref);
CFIndex len = pCFDataGetLength(freq_ref);
if (len == 8)
memcpy(speed, freq_ref_ptr, 8);
else if (len == 4) {
uint32_t v;
memcpy(&v, freq_ref_ptr, 4);
*speed = v;
} else {
*speed = 0;
}
pCFRelease(freq_ref);
pCFRelease(data);
break;
}
}
pCFRelease(data);
}
service = pIOIteratorNext(it);
}
pIOObjectRelease(it);
err = 0;
if (device_type_str != NULL)
pCFRelease(device_type_str);
if (clock_frequency_str != NULL)
pCFRelease(clock_frequency_str);
}
out:
if (core_foundation_handle != NULL)
dlclose(core_foundation_handle);
if (iokit_handle != NULL)
dlclose(iokit_handle);
mach_port_deallocate(mach_task_self(), mach_port);
return err;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks);
char model[512];
uint64_t cpuspeed;
size_t size;
unsigned int i;
natural_t numcpus;
mach_msg_type_number_t msg_type;
processor_cpu_load_info_data_t *info;
uv_cpu_info_t* cpu_info;
uint64_t cpuspeed;
int err;
size = sizeof(model);
if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
@@ -348,9 +203,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
return UV__ERR(errno);
}
err = uv__get_cpu_speed(&cpuspeed);
if (err < 0)
return err;
cpuspeed = 0;
size = sizeof(cpuspeed);
sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0);
if (cpuspeed == 0)
/* If sysctl hw.cputype == CPU_TYPE_ARM64, the correct value is unavailable
* from Apple, but we can hard-code it here to a plausible value. */
cpuspeed = 2400000000;
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
(processor_info_array_t*)&info,

View File

@@ -1,422 +0,0 @@
/* Copyright libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <errno.h>
#include <sys/epoll.h>
int uv__epoll_init(uv_loop_t* loop) {
int fd;
fd = epoll_create1(O_CLOEXEC);
/* epoll_create1() can fail either because it's not implemented (old kernel)
* or because it doesn't understand the O_CLOEXEC flag.
*/
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
fd = epoll_create(256);
if (fd != -1)
uv__cloexec(fd, 1);
}
loop->backend_fd = fd;
if (fd == -1)
return UV__ERR(errno);
return 0;
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct epoll_event* events;
struct epoll_event dummy;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
assert(fd >= 0);
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events != NULL)
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if (events[i].data.fd == fd)
events[i].data.fd = -1;
/* Remove the file descriptor from the epoll.
* This avoids a problem where the same file description remains open
* in another process, causing repeated junk epoll events.
*
* We pass in a dummy epoll_event, to work around a bug in old kernels.
*/
if (loop->backend_fd >= 0) {
/* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
* has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
*/
memset(&dummy, 0, sizeof(dummy));
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
}
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct epoll_event e;
int rc;
memset(&e, 0, sizeof(e));
e.events = POLLIN;
e.data.fd = -1;
rc = 0;
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
if (errno != EEXIST)
rc = UV__ERR(errno);
if (rc == 0)
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
abort();
return rc;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
/* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
* effectively infinite on 32 bits architectures. To avoid blocking
* indefinitely, we cap the timeout and poll again if necessary.
*
* Note that "30 minutes" is a simplification because it depends on
* the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
* that being the largest value I have seen in the wild (and only once.)
*/
static const int max_safe_timeout = 1789569;
static int no_epoll_pwait_cached;
static int no_epoll_wait_cached;
int no_epoll_pwait;
int no_epoll_wait;
struct epoll_event events[1024];
struct epoll_event* pe;
struct epoll_event e;
int real_timeout;
QUEUE* q;
uv__io_t* w;
sigset_t sigset;
uint64_t sigmask;
uint64_t base;
int have_signals;
int nevents;
int count;
int nfds;
int fd;
int op;
int i;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
memset(&e, 0, sizeof(e));
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
e.events = w->pevents;
e.data.fd = w->fd;
if (w->events == 0)
op = EPOLL_CTL_ADD;
else
op = EPOLL_CTL_MOD;
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
* events, skip the syscall and squelch the events after epoll_wait().
*/
if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
if (errno != EEXIST)
abort();
assert(op == EPOLL_CTL_ADD);
/* We've reactivated a file descriptor that's been watched before. */
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
abort();
}
w->events = w->pevents;
}
sigmask = 0;
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
sigemptyset(&sigset);
sigaddset(&sigset, SIGPROF);
sigmask |= 1 << (SIGPROF - 1);
}
assert(timeout >= -1);
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
real_timeout = timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
user_timeout = 0;
}
/* You could argue there is a dependency between these two but
* ultimately we don't care about their ordering with respect
* to one another. Worst case, we make a few system calls that
* could have been avoided because another thread already knows
* they fail with ENOSYS. Hardly the end of the world.
*/
no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached);
no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached);
for (;;) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
/* See the comment for max_safe_timeout for an explanation of why
* this is necessary. Executive summary: kernel bug workaround.
*/
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
timeout = max_safe_timeout;
if (sigmask != 0 && no_epoll_pwait != 0)
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
abort();
if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
nfds = epoll_pwait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout,
&sigset);
if (nfds == -1 && errno == ENOSYS) {
uv__store_relaxed(&no_epoll_pwait_cached, 1);
no_epoll_pwait = 1;
}
} else {
nfds = epoll_wait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout);
if (nfds == -1 && errno == ENOSYS) {
uv__store_relaxed(&no_epoll_wait_cached, 1);
no_epoll_wait = 1;
}
}
if (sigmask != 0 && no_epoll_pwait != 0)
if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
abort();
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
assert(timeout != -1);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* We may have been inside the system call for longer than |timeout|
* milliseconds so we need to update the timestamp to avoid drift.
*/
goto update_timeout;
}
if (nfds == -1) {
if (errno == ENOSYS) {
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
continue;
}
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
}
have_signals = 0;
nevents = 0;
{
/* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */
union {
struct epoll_event* events;
uv__io_t* watchers;
} x;
x.events = events;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = x.watchers;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
}
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->data.fd;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
w = (uv__io_t*)loop->watchers[fd];
if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it.
*
* Ignore all errors because we may be racing with another thread
* when the file descriptor is closed.
*/
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
continue;
}
/* Give users only events they're interested in. Prevents spurious
* callbacks when previous callback invocation in this loop has stopped
* the current watcher. Also, filters out events that users has not
* requested us to watch.
*/
pe->events &= w->pevents | POLLERR | POLLHUP;
/* Work around an epoll quirk where it sometimes reports just the
* EPOLLERR or EPOLLHUP event. In order to force the event loop to
* move forward, we merge in the read/write events that the watcher
* is interested in; uv__read() and uv__write() will then deal with
* the error or hangup in the usual fashion.
*
* Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
* reads the available data, calls uv_read_stop(), then sometime later
* calls uv_read_start() again. By then, libuv has forgotten about the
* hangup and the kernel won't report EPOLLIN again because there's
* nothing left to read. If anything, libuv is to blame here. The
* current hack is just a quick bandaid; to properly fix it, libuv
* needs to remember the error/hangup event. We should get that for
* free when we switch over to edge-triggered I/O.
*/
if (pe->events == POLLERR || pe->events == POLLHUP)
pe->events |=
w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
if (pe->events != 0) {
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher) {
have_signals = 1;
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->events);
}
nevents++;
}
}
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
timeout = 0;
continue;
}
return;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
real_timeout -= (loop->time - base);
if (real_timeout <= 0)
return;
timeout = real_timeout;
}
}

View File

@@ -91,7 +91,7 @@ uint64_t uv_get_free_memory(void) {
size_t size = sizeof(freecount);
if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
return UV__ERR(errno);
return 0;
return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
@@ -105,7 +105,7 @@ uint64_t uv_get_total_memory(void) {
size_t size = sizeof(info);
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return 0;
return (uint64_t) info;
}
@@ -116,6 +116,11 @@ uint64_t uv_get_constrained_memory(void) {
}
uint64_t uv_get_available_memory(void) {
return uv_get_free_memory();
}
void uv_loadavg(double avg[3]) {
struct loadavg info;
size_t size = sizeof(info);
@@ -264,30 +269,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
}
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if __FreeBSD__ >= 11 && !defined(__DragonFly__)
return sendmmsg(fd,
(struct mmsghdr*) mmsg,
vlen,
0 /* flags */);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if __FreeBSD__ >= 11 && !defined(__DragonFly__)
return recvmmsg(fd,
(struct mmsghdr*) mmsg,
vlen,
0 /* flags */,
NULL /* timeout */);
#else
return errno = ENOSYS, -1;
#endif
}
ssize_t
uv__fs_copy_file_range(int fd_in,
off_t* off_in,

View File

@@ -46,9 +46,10 @@
#include <fcntl.h>
#include <poll.h>
#include <atomic>
#if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
# define HAVE_PREADV 1
@@ -56,11 +57,16 @@
# define HAVE_PREADV 0
#endif
#if defined(__linux__)
# include "sys/utsname.h"
/* preadv() and pwritev() were added in Android N (level 24) */
#if defined(__linux__) && !(defined(__ANDROID__) && __ANDROID_API__ < 24)
# define TRY_PREADV 1
#endif
#if defined(__linux__) || defined(__sun)
#if defined(__linux__)
# include <sys/sendfile.h>
#endif
#if defined(__sun)
# include <sys/sendfile.h>
# include <sys/sysmacros.h>
#endif
@@ -79,7 +85,6 @@
#if defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
# include <sys/param.h>
@@ -256,7 +261,6 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
#elif defined(__APPLE__) \
|| defined(__DragonFly__) \
|| defined(__FreeBSD__) \
|| defined(__FreeBSD_kernel__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__) \
|| defined(__sun)
@@ -311,7 +315,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
static uv_once_t once = UV_ONCE_INIT;
int r;
#ifdef O_CLOEXEC
static int no_cloexec_support;
static std::atomic<int> no_cloexec_support;
#endif
static const char pattern[] = "XXXXXX";
static const size_t pattern_size = sizeof(pattern) - 1;
@@ -336,7 +340,8 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
uv_once(&once, uv__mkostemp_initonce);
#ifdef O_CLOEXEC
if (uv__load_relaxed(&no_cloexec_support) == 0 && uv__mkostemp != NULL) {
if (atomic_load_explicit(&no_cloexec_support, std::memory_order_relaxed) == 0 &&
uv__mkostemp != NULL) {
r = uv__mkostemp(path, O_CLOEXEC);
if (r >= 0)
@@ -349,7 +354,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. */
uv__store_relaxed(&no_cloexec_support, 1);
atomic_store_explicit(&no_cloexec_support, 1, std::memory_order_relaxed);
}
#endif /* O_CLOEXEC */
@@ -458,8 +463,8 @@ static ssize_t uv__fs_preadv(uv_file fd,
static ssize_t uv__fs_read(uv_fs_t* req) {
#if defined(__linux__)
static int no_preadv;
#if TRY_PREADV
static std::atomic<int> no_preadv;
#endif
unsigned int iovmax;
ssize_t result;
@@ -482,20 +487,20 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
#if HAVE_PREADV
result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if defined(__linux__)
if (uv__load_relaxed(&no_preadv)) retry:
# if TRY_PREADV
if (atomic_load_explicit(&no_preadv, std::memory_order_relaxed)) retry:
# endif
{
result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
}
# if defined(__linux__)
# if TRY_PREADV
else {
result = uv__preadv(req->file,
(struct iovec*)req->bufs,
req->nbufs,
req->off);
result = preadv(req->file,
(struct iovec*) req->bufs,
req->nbufs,
req->off);
if (result == -1 && errno == ENOSYS) {
uv__store_relaxed(&no_preadv, 1);
atomic_store_explicit(&no_preadv, 1, std::memory_order_relaxed);
goto retry;
}
}
@@ -516,7 +521,7 @@ done:
if (result == -1 && errno == EOPNOTSUPP) {
struct stat buf;
ssize_t rc;
rc = fstat(req->file, &buf);
rc = uv__fstat(req->file, &buf);
if (rc == 0 && S_ISDIR(buf.st_mode)) {
errno = EISDIR;
}
@@ -527,19 +532,12 @@ done:
}
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)
#define UV_CONST_DIRENT uv__dirent_t
#else
#define UV_CONST_DIRENT const uv__dirent_t
#endif
static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) {
static int uv__fs_scandir_filter(const uv__dirent_t* dent) {
return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
}
static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) {
static int uv__fs_scandir_sort(const uv__dirent_t** a, const uv__dirent_t** b) {
return strcmp((*a)->d_name, (*b)->d_name);
}
@@ -715,7 +713,7 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
/* We may not have a real PATH_MAX. Read size of link. */
struct stat st;
int ret;
ret = lstat(req->path, &st);
ret = uv__lstat(req->path, &st);
if (ret != 0)
return -1;
if (!S_ISLNK(st.st_mode)) {
@@ -907,31 +905,6 @@ out:
#ifdef __linux__
static unsigned uv__kernel_version(void) {
static unsigned cached_version;
struct utsname u;
unsigned version;
unsigned major;
unsigned minor;
unsigned patch;
version = uv__load_relaxed(&cached_version);
if (version != 0)
return version;
if (-1 == uname(&u))
return 0;
if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch))
return 0;
version = major * 65536 + minor * 256 + patch;
uv__store_relaxed(&cached_version, version);
return version;
}
/* Pre-4.20 kernels have a bug where CephFS uses the RADOS copy-from command
* in copy_file_range() when it shouldn't. There is no workaround except to
* fall back to a regular copy.
@@ -968,10 +941,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) {
static int no_copy_file_range_support;
static std::atomic<int> no_copy_file_range_support;
ssize_t r;
if (uv__load_relaxed(&no_copy_file_range_support)) {
if (atomic_load_explicit(&no_copy_file_range_support, std::memory_order_relaxed)) {
errno = ENOSYS;
return -1;
}
@@ -990,7 +963,7 @@ static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
errno = ENOSYS; /* Use fallback. */
break;
case ENOSYS:
uv__store_relaxed(&no_copy_file_range_support, 1);
atomic_store_explicit(&no_copy_file_range_support, 1, std::memory_order_relaxed);
break;
case EPERM:
/* It's been reported that CIFS spuriously fails.
@@ -1061,10 +1034,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
return -1;
}
#elif defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__)
#elif defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
{
off_t len;
ssize_t r;
@@ -1088,15 +1058,6 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
#endif
len = 0;
r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
#elif defined(__FreeBSD_kernel__)
len = 0;
r = bsd_sendfile(in_fd,
out_fd,
req->off,
req->bufsml[0].len,
NULL,
&len,
0);
#else
/* The darwin sendfile takes len as an input for the length to send,
* so make sure to initialize it with the caller's value. */
@@ -1148,7 +1109,6 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
#elif defined(__APPLE__) \
|| defined(__DragonFly__) \
|| defined(__FreeBSD__) \
|| defined(__FreeBSD_kernel__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__)
struct timeval tv[2];
@@ -1190,7 +1150,6 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
#elif defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__NetBSD__)
struct timeval tv[2];
tv[0] = uv__fs_to_timeval(req->atime);
@@ -1204,8 +1163,8 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
static ssize_t uv__fs_write(uv_fs_t* req) {
#if defined(__linux__)
static int no_pwritev;
#if TRY_PREADV
static std::atomic<int> no_pwritev;
#endif
ssize_t r;
@@ -1233,20 +1192,20 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
#if HAVE_PREADV
r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if defined(__linux__)
if (no_pwritev) retry:
# if TRY_PREADV
if (atomic_load_explicit(&no_pwritev, std::memory_order_relaxed)) retry:
# endif
{
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
}
# if defined(__linux__)
# if TRY_PREADV
else {
r = uv__pwritev(req->file,
(struct iovec*) req->bufs,
req->nbufs,
req->off);
r = pwritev(req->file,
(struct iovec*) req->bufs,
req->nbufs,
req->off);
if (r == -1 && errno == ENOSYS) {
no_pwritev = 1;
atomic_store_explicit(&no_pwritev, 1, std::memory_order_relaxed);
goto retry;
}
}
@@ -1288,7 +1247,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
return srcfd;
/* Get the source file's mode. */
if (fstat(srcfd, &src_statsbuf)) {
if (uv__fstat(srcfd, &src_statsbuf)) {
err = UV__ERR(errno);
goto out;
}
@@ -1316,7 +1275,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
destination are not the same file. If they are the same, bail out early. */
if ((req->flags & UV_FS_COPYFILE_EXCL) == 0) {
/* Get the destination file's mode. */
if (fstat(dstfd, &dst_statsbuf)) {
if (uv__fstat(dstfd, &dst_statsbuf)) {
err = UV__ERR(errno);
goto out;
}
@@ -1330,7 +1289,19 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
/* Truncate the file in case the destination already existed. */
if (ftruncate(dstfd, 0) != 0) {
err = UV__ERR(errno);
goto out;
/* ftruncate() on ceph-fuse fails with EACCES when the file is created
* with read only permissions. Since ftruncate() on a newly created
* file is a meaningless operation anyway, detect that condition
* and squelch the error.
*/
if (err != UV_EACCES)
goto out;
if (dst_statsbuf.st_size > 0)
goto out;
err = 0;
}
}
@@ -1514,14 +1485,14 @@ static int uv__fs_statx(int fd,
uv_stat_t* buf) {
STATIC_ASSERT(UV_ENOSYS != -1);
#ifdef __linux__
static int no_statx;
static std::atomic<int> no_statx;
struct uv__statx statxbuf;
int dirfd;
int flags;
int mode;
int rc;
if (uv__load_relaxed(&no_statx))
if (atomic_load_explicit(&no_statx, std::memory_order_relaxed))
return UV_ENOSYS;
dirfd = AT_FDCWD;
@@ -1555,30 +1526,11 @@ 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.
*/
uv__store_relaxed(&no_statx, 1);
atomic_store_explicit(&no_statx, 1, std::memory_order_relaxed);
return UV_ENOSYS;
}
buf->st_dev = makedev(statxbuf.stx_dev_major, statxbuf.stx_dev_minor);
buf->st_mode = statxbuf.stx_mode;
buf->st_nlink = statxbuf.stx_nlink;
buf->st_uid = statxbuf.stx_uid;
buf->st_gid = statxbuf.stx_gid;
buf->st_rdev = makedev(statxbuf.stx_rdev_major, statxbuf.stx_rdev_minor);
buf->st_ino = statxbuf.stx_ino;
buf->st_size = statxbuf.stx_size;
buf->st_blksize = statxbuf.stx_blksize;
buf->st_blocks = statxbuf.stx_blocks;
buf->st_atim.tv_sec = statxbuf.stx_atime.tv_sec;
buf->st_atim.tv_nsec = statxbuf.stx_atime.tv_nsec;
buf->st_mtim.tv_sec = statxbuf.stx_mtime.tv_sec;
buf->st_mtim.tv_nsec = statxbuf.stx_mtime.tv_nsec;
buf->st_ctim.tv_sec = statxbuf.stx_ctime.tv_sec;
buf->st_ctim.tv_nsec = statxbuf.stx_ctime.tv_nsec;
buf->st_birthtim.tv_sec = statxbuf.stx_btime.tv_sec;
buf->st_birthtim.tv_nsec = statxbuf.stx_btime.tv_nsec;
buf->st_flags = 0;
buf->st_gen = 0;
uv__statx_to_stat(&statxbuf, buf);
return 0;
#else
@@ -1595,7 +1547,7 @@ static int uv__fs_stat(const char *path, uv_stat_t *buf) {
if (ret != UV_ENOSYS)
return ret;
ret = stat(path, &pbuf);
ret = uv__stat(path, &pbuf);
if (ret == 0)
uv__to_stat(&pbuf, buf);
@@ -1611,7 +1563,7 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
if (ret != UV_ENOSYS)
return ret;
ret = lstat(path, &pbuf);
ret = uv__lstat(path, &pbuf);
if (ret == 0)
uv__to_stat(&pbuf, buf);
@@ -1627,7 +1579,7 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
if (ret != UV_ENOSYS)
return ret;
ret = fstat(fd, &pbuf);
ret = uv__fstat(fd, &pbuf);
if (ret == 0)
uv__to_stat(&pbuf, buf);
@@ -1822,6 +1774,9 @@ int uv_fs_chown(uv_loop_t* loop,
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
INIT(CLOSE);
req->file = file;
if (cb != NULL)
if (uv__iou_fs_close(loop, req))
return 0;
POST;
}
@@ -1869,6 +1824,9 @@ int uv_fs_lchown(uv_loop_t* loop,
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
INIT(FDATASYNC);
req->file = file;
if (cb != NULL)
if (uv__iou_fs_fsync_or_fdatasync(loop, req, /* IORING_FSYNC_DATASYNC */ 1))
return 0;
POST;
}
@@ -1876,6 +1834,9 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
INIT(FSTAT);
req->file = file;
if (cb != NULL)
if (uv__iou_fs_statx(loop, req, /* is_fstat */ 1, /* is_lstat */ 0))
return 0;
POST;
}
@@ -1883,6 +1844,9 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
INIT(FSYNC);
req->file = file;
if (cb != NULL)
if (uv__iou_fs_fsync_or_fdatasync(loop, req, /* no flags */ 0))
return 0;
POST;
}
@@ -1929,6 +1893,9 @@ int uv_fs_lutime(uv_loop_t* loop,
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
INIT(LSTAT);
PATH;
if (cb != NULL)
if (uv__iou_fs_statx(loop, req, /* is_fstat */ 0, /* is_lstat */ 1))
return 0;
POST;
}
@@ -1940,6 +1907,9 @@ int uv_fs_link(uv_loop_t* loop,
uv_fs_cb cb) {
INIT(LINK);
PATH2;
if (cb != NULL)
if (uv__iou_fs_link(loop, req))
return 0;
POST;
}
@@ -1952,6 +1922,9 @@ int uv_fs_mkdir(uv_loop_t* loop,
INIT(MKDIR);
PATH;
req->mode = mode;
if (cb != NULL)
if (uv__iou_fs_mkdir(loop, req))
return 0;
POST;
}
@@ -1990,6 +1963,9 @@ int uv_fs_open(uv_loop_t* loop,
PATH;
req->flags = flags;
req->mode = mode;
if (cb != NULL)
if (uv__iou_fs_open(loop, req))
return 0;
POST;
}
@@ -2018,6 +1994,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
req->off = off;
if (cb != NULL)
if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 1))
return 0;
POST;
}
@@ -2095,6 +2076,9 @@ int uv_fs_rename(uv_loop_t* loop,
uv_fs_cb cb) {
INIT(RENAME);
PATH2;
if (cb != NULL)
if (uv__iou_fs_rename(loop, req))
return 0;
POST;
}
@@ -2125,6 +2109,9 @@ int uv_fs_sendfile(uv_loop_t* loop,
int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
INIT(STAT);
PATH;
if (cb != NULL)
if (uv__iou_fs_statx(loop, req, /* is_fstat */ 0, /* is_lstat */ 0))
return 0;
POST;
}
@@ -2138,6 +2125,9 @@ int uv_fs_symlink(uv_loop_t* loop,
INIT(SYMLINK);
PATH2;
req->flags = flags;
if (cb != NULL)
if (uv__iou_fs_symlink(loop, req))
return 0;
POST;
}
@@ -2145,6 +2135,9 @@ int uv_fs_symlink(uv_loop_t* loop,
int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
INIT(UNLINK);
PATH;
if (cb != NULL)
if (uv__iou_fs_unlink(loop, req))
return 0;
POST;
}
@@ -2188,6 +2181,11 @@ int uv_fs_write(uv_loop_t* loop,
memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
req->off = off;
if (cb != NULL)
if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 0))
return 0;
POST;
}
@@ -2196,7 +2194,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
if (req == NULL)
return;
/* Only necessary for asychronous requests, i.e., requests with a callback.
/* Only necessary for asynchronous requests, i.e., requests with a callback.
* Synchronous ones don't copy their arguments and have req->path and
* req->new_path pointing to user-owned memory. UV_FS_MKDTEMP and
* UV_FS_MKSTEMP are the exception to the rule, they always allocate memory.

View File

@@ -80,13 +80,13 @@ enum uv__cf_loop_signal_type_e {
typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
struct uv__cf_loop_signal_s {
QUEUE member;
struct uv__queue member;
uv_fs_event_t* handle;
uv__cf_loop_signal_type_t type;
};
struct uv__fsevents_event_s {
QUEUE member;
struct uv__queue member;
int events;
char path[1];
};
@@ -98,7 +98,7 @@ struct uv__cf_loop_state_s {
FSEventStreamRef fsevent_stream;
uv_sem_t fsevent_sem;
uv_mutex_t fsevent_mutex;
void* fsevent_handles[2];
struct uv__queue fsevent_handles;
unsigned int fsevent_handle_count;
};
@@ -132,7 +132,6 @@ static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
CFAllocatorRef,
const char*);
static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
static CFStringRef (*pkCFRunLoopDefaultMode);
static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
FSEventStreamCallback,
@@ -141,7 +140,6 @@ static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
FSEventStreamEventId,
CFTimeInterval,
FSEventStreamCreateFlags);
static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
static void (*pFSEventStreamRelease)(FSEventStreamRef);
static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
@@ -152,22 +150,22 @@ static void (*pFSEventStreamStop)(FSEventStreamRef);
#define UV__FSEVENTS_PROCESS(handle, block) \
do { \
QUEUE events; \
QUEUE* q; \
struct uv__queue events; \
struct uv__queue* q; \
uv__fsevents_event_t* event; \
int err; \
uv_mutex_lock(&(handle)->cf_mutex); \
/* Split-off all events and empty original queue */ \
QUEUE_MOVE(&(handle)->cf_events, &events); \
uv__queue_move(&(handle)->cf_events, &events); \
/* Get error (if any) and zero original one */ \
err = (handle)->cf_error; \
(handle)->cf_error = 0; \
uv_mutex_unlock(&(handle)->cf_mutex); \
/* Loop through events, deallocating each after processing */ \
while (!QUEUE_EMPTY(&events)) { \
q = QUEUE_HEAD(&events); \
event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
QUEUE_REMOVE(q); \
while (!uv__queue_empty(&events)) { \
q = uv__queue_head(&events); \
event = uv__queue_data(q, uv__fsevents_event_t, member); \
uv__queue_remove(q); \
/* NOTE: Checking uv__is_active() is required here, because handle \
* callback may close handle and invoking it after it will lead to \
* incorrect behaviour */ \
@@ -195,14 +193,14 @@ static void uv__fsevents_cb(uv_async_t* cb) {
/* Runs in CF thread, pushed event into handle's event list */
static void uv__fsevents_push_event(uv_fs_event_t* handle,
QUEUE* events,
struct uv__queue* events,
int err) {
assert(events != NULL || err != 0);
uv_mutex_lock(&handle->cf_mutex);
/* Concatenate two queues */
if (events != NULL)
QUEUE_ADD(&handle->cf_events, events);
uv__queue_add(&handle->cf_events, events);
/* Propagate error */
if (err != 0)
@@ -226,12 +224,12 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
char* path;
char* pos;
uv_fs_event_t* handle;
QUEUE* q;
struct uv__queue* q;
uv_loop_t* loop;
uv__cf_loop_state_t* state;
uv__fsevents_event_t* event;
FSEventStreamEventFlags flags;
QUEUE head;
struct uv__queue head;
loop = (uv_loop_t*)info;
state = (uv__cf_loop_state_t*)loop->cf_state;
@@ -240,9 +238,9 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
/* For each handle */
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_FOREACH(q, &state->fsevent_handles) {
handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
QUEUE_INIT(&head);
uv__queue_foreach(q, &state->fsevent_handles) {
handle = uv__queue_data(q, uv_fs_event_t, cf_member);
uv__queue_init(&head);
/* Process and filter out events */
for (i = 0; i < numEvents; i++) {
@@ -320,10 +318,10 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
event->events = UV_CHANGE;
}
QUEUE_INSERT_TAIL(&head, &event->member);
uv__queue_insert_tail(&head, &event->member);
}
if (!QUEUE_EMPTY(&head))
if (!uv__queue_empty(&head))
uv__fsevents_push_event(handle, &head, 0);
}
uv_mutex_unlock(&state->fsevent_mutex);
@@ -331,8 +329,9 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
/* Runs in CF thread */
static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
uv__cf_loop_state_t* state;
static int uv__fsevents_create_stream(uv__cf_loop_state_t* state,
uv_loop_t* loop,
CFArrayRef paths) {
FSEventStreamContext ctx;
FSEventStreamRef ref;
CFAbsoluteTime latency;
@@ -373,10 +372,7 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
flags);
assert(ref != NULL);
state = (uv__cf_loop_state_t*)loop->cf_state;
pFSEventStreamScheduleWithRunLoop(ref,
state->loop,
*pkCFRunLoopDefaultMode);
pFSEventStreamScheduleWithRunLoop(ref, state->loop, *pkCFRunLoopDefaultMode);
if (!pFSEventStreamStart(ref)) {
pFSEventStreamInvalidate(ref);
pFSEventStreamRelease(ref);
@@ -389,11 +385,7 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
/* Runs in CF thread */
static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
uv__cf_loop_state_t* state;
state = (uv__cf_loop_state_t*)loop->cf_state;
static void uv__fsevents_destroy_stream(uv__cf_loop_state_t* state) {
if (state->fsevent_stream == NULL)
return;
@@ -408,10 +400,10 @@ static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
/* Runs in CF thread, when there're new fsevent handles to add to stream */
static void uv__fsevents_reschedule(uv_fs_event_t* handle,
static void uv__fsevents_reschedule(uv__cf_loop_state_t* state,
uv_loop_t* loop,
uv__cf_loop_signal_type_t type) {
uv__cf_loop_state_t* state;
QUEUE* q;
struct uv__queue* q;
uv_fs_event_t* curr;
CFArrayRef cf_paths;
CFStringRef* paths;
@@ -419,7 +411,6 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle,
int err;
unsigned int path_count;
state = (uv__cf_loop_state_t*)handle->loop->cf_state;
paths = NULL;
cf_paths = NULL;
err = 0;
@@ -438,7 +429,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle,
uv_mutex_unlock(&state->fsevent_mutex);
/* Destroy previous FSEventStream */
uv__fsevents_destroy_stream(handle->loop);
uv__fsevents_destroy_stream(state);
/* Any failure below will be a memory failure */
err = UV_ENOMEM;
@@ -455,9 +446,9 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle,
q = &state->fsevent_handles;
for (; i < path_count; i++) {
q = QUEUE_NEXT(q);
q = uv__queue_next(q);
assert(q != &state->fsevent_handles);
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
curr = uv__queue_data(q, uv_fs_event_t, cf_member);
assert(curr->realpath != NULL);
paths[i] =
@@ -478,7 +469,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle,
err = UV_ENOMEM;
goto final;
}
err = uv__fsevents_create_stream(handle->loop, cf_paths);
err = uv__fsevents_create_stream(state, loop, cf_paths);
}
final:
@@ -495,8 +486,8 @@ final:
/* Broadcast error to all handles */
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_FOREACH(q, &state->fsevent_handles) {
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
uv__queue_foreach(q, &state->fsevent_handles) {
curr = uv__queue_data(q, uv_fs_event_t, cf_member);
uv__fsevents_push_event(curr, NULL, err);
}
uv_mutex_unlock(&state->fsevent_mutex);
@@ -563,10 +554,8 @@ static int uv__fsevents_global_init(void) {
V(core_foundation_handle, CFRunLoopStop);
V(core_foundation_handle, CFRunLoopWakeUp);
V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
V(core_foundation_handle, CFStringGetSystemEncoding);
V(core_foundation_handle, kCFRunLoopDefaultMode);
V(core_services_handle, FSEventStreamCreate);
V(core_services_handle, FSEventStreamFlushSync);
V(core_services_handle, FSEventStreamInvalidate);
V(core_services_handle, FSEventStreamRelease);
V(core_services_handle, FSEventStreamScheduleWithRunLoop);
@@ -617,7 +606,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) {
if (err)
goto fail_sem_init;
QUEUE_INIT(&loop->cf_signals);
uv__queue_init(&loop->cf_signals);
err = uv_sem_init(&state->fsevent_sem, 0);
if (err)
@@ -627,7 +616,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) {
if (err)
goto fail_fsevent_mutex_init;
QUEUE_INIT(&state->fsevent_handles);
uv__queue_init(&state->fsevent_handles);
state->fsevent_need_reschedule = 0;
state->fsevent_handle_count = 0;
@@ -686,7 +675,7 @@ fail_mutex_init:
void uv__fsevents_loop_delete(uv_loop_t* loop) {
uv__cf_loop_signal_t* s;
uv__cf_loop_state_t* state;
QUEUE* q;
struct uv__queue* q;
if (loop->cf_state == NULL)
return;
@@ -699,10 +688,10 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) {
uv_mutex_destroy(&loop->cf_mutex);
/* Free any remaining data */
while (!QUEUE_EMPTY(&loop->cf_signals)) {
q = QUEUE_HEAD(&loop->cf_signals);
s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
QUEUE_REMOVE(q);
while (!uv__queue_empty(&loop->cf_signals)) {
q = uv__queue_head(&loop->cf_signals);
s = uv__queue_data(q, uv__cf_loop_signal_t, member);
uv__queue_remove(q);
uv__free(s);
}
@@ -746,28 +735,28 @@ static void* uv__cf_loop_runner(void* arg) {
static void uv__cf_loop_cb(void* arg) {
uv_loop_t* loop;
uv__cf_loop_state_t* state;
QUEUE* item;
QUEUE split_head;
struct uv__queue* item;
struct uv__queue split_head;
uv__cf_loop_signal_t* s;
loop = (uv_loop_t*)arg;
state = (uv__cf_loop_state_t*)loop->cf_state;
uv_mutex_lock(&loop->cf_mutex);
QUEUE_MOVE(&loop->cf_signals, &split_head);
uv__queue_move(&loop->cf_signals, &split_head);
uv_mutex_unlock(&loop->cf_mutex);
while (!QUEUE_EMPTY(&split_head)) {
item = QUEUE_HEAD(&split_head);
QUEUE_REMOVE(item);
while (!uv__queue_empty(&split_head)) {
item = uv__queue_head(&split_head);
uv__queue_remove(item);
s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
s = uv__queue_data(item, uv__cf_loop_signal_t, member);
/* This was a termination signal */
if (s->handle == NULL)
pCFRunLoopStop(state->loop);
else
uv__fsevents_reschedule(s->handle, s->type);
uv__fsevents_reschedule(state, loop, s->type);
uv__free(s);
}
@@ -789,7 +778,7 @@ int uv__cf_loop_signal(uv_loop_t* loop,
item->type = type;
uv_mutex_lock(&loop->cf_mutex);
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
uv__queue_insert_tail(&loop->cf_signals, &item->member);
state = (uv__cf_loop_state_t*)loop->cf_state;
assert(state != NULL);
@@ -818,7 +807,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
handle->realpath_len = strlen(handle->realpath);
/* Initialize event queue */
QUEUE_INIT(&handle->cf_events);
uv__queue_init(&handle->cf_events);
handle->cf_error = 0;
/*
@@ -843,7 +832,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
/* Insert handle into the list */
state = (uv__cf_loop_state_t*)handle->loop->cf_state;
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
uv__queue_insert_tail(&state->fsevent_handles, &handle->cf_member);
state->fsevent_handle_count++;
state->fsevent_need_reschedule = 1;
uv_mutex_unlock(&state->fsevent_mutex);
@@ -883,7 +872,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) {
/* Remove handle from the list */
state = (uv__cf_loop_state_t*)handle->loop->cf_state;
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_REMOVE(&handle->cf_member);
uv__queue_remove(&handle->cf_member);
state->fsevent_handle_count--;
state->fsevent_need_reschedule = 1;
uv_mutex_unlock(&state->fsevent_mutex);

View File

@@ -249,6 +249,11 @@ uint64_t uv_get_constrained_memory(void) {
}
uint64_t uv_get_available_memory(void) {
return uv_get_free_memory();
}
void uv_loadavg(double avg[3]) {
SSTS0200 rcvr;

View File

@@ -26,21 +26,34 @@
#include <assert.h>
#include <limits.h> /* _POSIX_PATH_MAX, PATH_MAX */
#include <stdint.h>
#include <stdlib.h> /* abort */
#include <string.h> /* strrchr */
#include <fcntl.h> /* O_CLOEXEC and O_NONBLOCK, if supported. */
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#define uv__msan_unpoison(p, n) \
do { \
(void) (p); \
(void) (n); \
} while (0)
#if defined(__has_feature)
# if __has_feature(memory_sanitizer)
# include <sanitizer/msan_interface.h>
# undef uv__msan_unpoison
# define uv__msan_unpoison __msan_unpoison
# endif
#endif
#if defined(__STRICT_ANSI__)
# define inline __inline
#endif
#if defined(__linux__)
# include "linux-syscalls.h"
#endif /* __linux__ */
#if defined(__MVS__)
# include "os390-syscalls.h"
#endif /* __MVS__ */
@@ -79,13 +92,11 @@
# define UV__PATH_MAX 8192
#endif
#if defined(__ANDROID__)
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
# ifdef pthread_sigmask
# undef pthread_sigmask
# endif
# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
#endif
union uv__sockaddr {
struct sockaddr_in6 in6;
struct sockaddr_in in;
struct sockaddr addr;
};
#define ACCESS_ONCE(type, var) \
(*(volatile type*) &(var))
@@ -166,12 +177,42 @@ struct uv__stream_queued_fds_s {
int fds[1];
};
#ifdef __linux__
struct uv__statx_timestamp {
int64_t tv_sec;
uint32_t tv_nsec;
int32_t unused0;
};
struct uv__statx {
uint32_t stx_mask;
uint32_t stx_blksize;
uint64_t stx_attributes;
uint32_t stx_nlink;
uint32_t stx_uid;
uint32_t stx_gid;
uint16_t stx_mode;
uint16_t unused0;
uint64_t stx_ino;
uint64_t stx_size;
uint64_t stx_blocks;
uint64_t stx_attributes_mask;
struct uv__statx_timestamp stx_atime;
struct uv__statx_timestamp stx_btime;
struct uv__statx_timestamp stx_ctime;
struct uv__statx_timestamp stx_mtime;
uint32_t stx_rdev_major;
uint32_t stx_rdev_minor;
uint32_t stx_dev_major;
uint32_t stx_dev_minor;
uint64_t unused1[14];
};
#endif /* __linux__ */
#if defined(_AIX) || \
defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__linux__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
@@ -260,10 +301,10 @@ int uv__signal_loop_fork(uv_loop_t* loop);
/* platform specific */
uint64_t uv__hrtime(uv_clocktype_t type);
int uv__kqueue_init(uv_loop_t* loop);
int uv__epoll_init(uv_loop_t* loop);
int uv__platform_loop_init(uv_loop_t* loop);
void uv__platform_loop_delete(uv_loop_t* loop);
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
int uv__process_init(uv_loop_t* loop);
/* various */
void uv__async_close(uv_async_t* handle);
@@ -280,7 +321,6 @@ size_t uv__thread_stack_size(void);
void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle);
FILE* uv__open_file(const char* path);
int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__search_path(const char* prog, char* buf, size_t* buflen);
void uv__wait_children(uv_loop_t* loop);
@@ -291,6 +331,38 @@ int uv__random_getentropy(void* buf, size_t buflen);
int uv__random_readpath(const char* path, void* buf, size_t buflen);
int uv__random_sysctl(void* buf, size_t buflen);
/* io_uring */
#ifdef __linux__
int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req);
int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop,
uv_fs_t* req,
uint32_t fsync_flags);
int uv__iou_fs_link(uv_loop_t* loop, uv_fs_t* req);
int uv__iou_fs_mkdir(uv_loop_t* loop, uv_fs_t* req);
int uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req);
int uv__iou_fs_read_or_write(uv_loop_t* loop,
uv_fs_t* req,
int is_read);
int uv__iou_fs_rename(uv_loop_t* loop, uv_fs_t* req);
int uv__iou_fs_statx(uv_loop_t* loop,
uv_fs_t* req,
int is_fstat,
int is_lstat);
int uv__iou_fs_symlink(uv_loop_t* loop, uv_fs_t* req);
int uv__iou_fs_unlink(uv_loop_t* loop, uv_fs_t* req);
#else
#define uv__iou_fs_close(loop, req) 0
#define uv__iou_fs_fsync_or_fdatasync(loop, req, fsync_flags) 0
#define uv__iou_fs_link(loop, req) 0
#define uv__iou_fs_mkdir(loop, req) 0
#define uv__iou_fs_open(loop, req) 0
#define uv__iou_fs_read_or_write(loop, req, is_read) 0
#define uv__iou_fs_rename(loop, req) 0
#define uv__iou_fs_statx(loop, req, is_fstat, is_lstat) 0
#define uv__iou_fs_symlink(loop, req) 0
#define uv__iou_fs_unlink(loop, req) 0
#endif
#if defined(__APPLE__)
int uv___stream_fd(const uv_stream_t* handle);
#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle)))
@@ -324,8 +396,52 @@ UV_UNUSED(static const char* uv__basename_r(const char* path)) {
return s + 1;
}
UV_UNUSED(static int uv__fstat(int fd, struct stat* s)) {
int rc;
rc = fstat(fd, s);
if (rc >= 0)
uv__msan_unpoison(s, sizeof(*s));
return rc;
}
UV_UNUSED(static int uv__lstat(const char* path, struct stat* s)) {
int rc;
rc = lstat(path, s);
if (rc >= 0)
uv__msan_unpoison(s, sizeof(*s));
return rc;
}
UV_UNUSED(static int uv__stat(const char* path, struct stat* s)) {
int rc;
rc = stat(path, s);
if (rc >= 0)
uv__msan_unpoison(s, sizeof(*s));
return rc;
}
#if defined(__linux__)
int uv__inotify_fork(uv_loop_t* loop, void* old_watchers);
ssize_t
uv__fs_copy_file_range(int fd_in,
off_t* off_in,
int fd_out,
off_t* off_out,
size_t len,
unsigned int flags);
int uv__statx(int dirfd,
const char* path,
int flags,
unsigned int mask,
struct uv__statx* statxbuf);
void uv__statx_to_stat(const struct uv__statx* statxbuf, uv_stat_t* buf);
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags);
unsigned uv__kernel_version(void);
#endif
typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
@@ -335,22 +451,6 @@ int uv__getsockpeername(const uv_handle_t* handle,
struct sockaddr* name,
int* namelen);
#if defined(__linux__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__DragonFly__)
#define HAVE_MMSG 1
struct uv__mmsghdr {
struct msghdr msg_hdr;
unsigned int msg_len;
};
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen);
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen);
#else
#define HAVE_MMSG 0
#endif
#if defined(__sun)
#if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L
size_t strnlen(const char* s, size_t maxlen);
@@ -367,5 +467,10 @@ uv__fs_copy_file_range(int fd_in,
unsigned int flags);
#endif
#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1301000)
#define UV__CPU_AFFINITY_SUPPORTED 1
#else
#define UV__CPU_AFFINITY_SUPPORTED 0
#endif
#endif /* UV_UNIX_INTERNAL_H_ */

View File

@@ -34,6 +34,8 @@
#include <fcntl.h>
#include <time.h>
#include <atomic>
/*
* Required on
* - Until at least FreeBSD 11.0
@@ -60,7 +62,7 @@ int uv__kqueue_init(uv_loop_t* loop) {
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
static int uv__has_forked_with_cfrunloop;
static std::atomic<int> uv__has_forked_with_cfrunloop;
#endif
int uv__io_fork(uv_loop_t* loop) {
@@ -82,7 +84,9 @@ int uv__io_fork(uv_loop_t* loop) {
process. So we sidestep the issue by pretending like we never
started it in the first place.
*/
uv__store_relaxed(&uv__has_forked_with_cfrunloop, 1);
atomic_store_explicit(&uv__has_forked_with_cfrunloop,
1,
std::memory_order_relaxed);
uv__free(loop->cf_state);
loop->cf_state = NULL;
}
@@ -109,13 +113,29 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
}
static void uv__kqueue_delete(int kqfd, const struct kevent *ev) {
struct kevent change;
EV_SET(&change, ev->ident, ev->filter, EV_DELETE, 0, 0, 0);
if (0 == kevent(kqfd, &change, 1, NULL, 0, NULL))
return;
if (errno == EBADF || errno == ENOENT)
return;
abort();
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
uv__loop_internal_fields_t* lfields;
struct kevent events[1024];
struct kevent* ev;
struct timespec spec;
unsigned int nevents;
unsigned int revents;
QUEUE* q;
struct uv__queue* q;
uv__io_t* w;
uv_process_t* process;
sigset_t* pset;
@@ -134,18 +154,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
assert(uv__queue_empty(&loop->watcher_queue));
return;
}
lfields = uv__get_internal_fields(loop);
nevents = 0;
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
while (!uv__queue_empty(&loop->watcher_queue)) {
q = uv__queue_head(&loop->watcher_queue);
uv__queue_remove(q);
uv__queue_init(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
w = uv__queue_data(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
@@ -205,7 +226,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
if (lfields->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
@@ -228,6 +249,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (pset != NULL)
pthread_sigmask(SIG_BLOCK, pset, NULL);
/* Store the current timeout in a location that's globally accessible so
* other locations like uv__work_done() can determine whether the queue
* of events in the callback were waiting when poll was called.
*/
lfields->current_timeout = timeout;
nfds = kevent(loop->backend_fd,
events,
nevents,
@@ -235,6 +262,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
ARRAY_SIZE(events),
timeout == -1 ? NULL : &spec);
if (nfds == -1)
assert(errno == EINTR);
if (pset != NULL)
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
@@ -242,36 +272,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
SAVE_ERRNO(uv__update_time(loop));
uv__update_time(loop);
if (nfds == 0) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
if (timeout == -1)
continue;
if (timeout > 0)
goto update_timeout;
if (nfds == 0 || nfds == -1) {
/* If kqueue is empty or interrupted, we might still have children ready
* to reap immediately. */
if (loop->flags & UV_LOOP_REAP_CHILDREN) {
loop->flags &= ~UV_LOOP_REAP_CHILDREN;
uv__wait_children(loop);
assert((reset_timeout == 0 ? timeout : user_timeout) == 0);
return; /* Equivalent to fall-through behavior. */
}
assert(timeout != -1);
return;
}
if (nfds == -1) {
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == 0)
} else if (nfds == 0) {
/* Reached the user timeout value. */
assert(timeout != -1);
return;
if (timeout == -1)
continue;
}
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
@@ -289,8 +309,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
/* Handle kevent NOTE_EXIT results */
if (ev->filter == EVFILT_PROC) {
QUEUE_FOREACH(q, &loop->process_handles) {
process = QUEUE_DATA(q, uv_process_t, queue);
uv__queue_foreach(q, &loop->process_handles) {
process = uv__queue_data(q, uv_process_t, queue);
if (process->pid == fd) {
process->flags |= UV_HANDLE_REAP;
loop->flags |= UV_LOOP_REAP_CHILDREN;
@@ -307,15 +327,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
w = (uv__io_t*)loop->watchers[fd];
if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it.
* TODO: batch up. */
struct kevent events[1];
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
if (errno != EBADF && errno != ENOENT)
abort();
/* File descriptor that we've stopped watching, disarm it. */
uv__kqueue_delete(loop->backend_fd, ev);
continue;
}
@@ -331,47 +344,27 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
revents = 0;
if (ev->filter == EVFILT_READ) {
if (w->pevents & POLLIN) {
if (w->pevents & POLLIN)
revents |= POLLIN;
w->rcount = ev->data;
} else {
/* TODO batch up */
struct kevent events[1];
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
if (errno != ENOENT)
abort();
}
else
uv__kqueue_delete(loop->backend_fd, ev);
if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
revents |= UV__POLLRDHUP;
}
if (ev->filter == EV_OOBAND) {
if (w->pevents & UV__POLLPRI) {
if (w->pevents & UV__POLLPRI)
revents |= UV__POLLPRI;
w->rcount = ev->data;
} else {
/* TODO batch up */
struct kevent events[1];
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
if (errno != ENOENT)
abort();
}
else
uv__kqueue_delete(loop->backend_fd, ev);
}
if (ev->filter == EVFILT_WRITE) {
if (w->pevents & POLLOUT) {
if (w->pevents & POLLOUT)
revents |= POLLOUT;
w->wcount = ev->data;
} else {
/* TODO batch up */
struct kevent events[1];
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
if (errno != ENOENT)
abort();
}
else
uv__kqueue_delete(loop->backend_fd, ev);
}
if (ev->flags & EV_ERROR)
@@ -398,9 +391,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
uv__wait_children(loop);
}
uv__metrics_inc_events(loop, nevents);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
uv__metrics_inc_events_waiting(loop, nevents);
}
if (have_signals != 0) {
@@ -423,13 +418,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
return;
}
update_timeout:
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
diff = loop->time - base;
@@ -541,13 +536,14 @@ int uv_fs_event_start(uv_fs_event_t* handle,
handle->realpath_len = 0;
handle->cf_flags = flags;
if (fstat(fd, &statbuf))
if (uv__fstat(fd, &statbuf))
goto fallback;
/* FSEvents works only with directories */
if (!(statbuf.st_mode & S_IFDIR))
goto fallback;
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) {
if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
std::memory_order_relaxed)) {
int r;
/* The fallback fd is no longer needed */
uv__close_nocheckstdio(fd);
@@ -582,7 +578,8 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
uv__handle_stop(handle);
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop))
if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
std::memory_order_relaxed))
if (handle->cf_cb != NULL)
r = uv__fsevents_close(handle);
#endif

View File

@@ -1,841 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their
* EPOLL* counterparts. We use the POLL* variants in this file because that
* is what libuv uses elsewhere.
*/
#include "uv.h"
#include "internal.h"
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <net/if.h>
#include <sys/epoll.h>
#include <sys/param.h>
#include <sys/prctl.h>
#include <sys/sysinfo.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#define HAVE_IFADDRS_H 1
# if defined(__ANDROID_API__) && __ANDROID_API__ < 24
# undef HAVE_IFADDRS_H
#endif
#ifdef __UCLIBC__
# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
# undef HAVE_IFADDRS_H
# endif
#endif
#ifdef HAVE_IFADDRS_H
# include <ifaddrs.h>
# include <sys/socket.h>
# include <net/ethernet.h>
# include <netpacket/packet.h>
#endif /* HAVE_IFADDRS_H */
/* Available from 2.6.32 onwards. */
#ifndef CLOCK_MONOTONIC_COARSE
# define CLOCK_MONOTONIC_COARSE 6
#endif
#ifdef __FRC_ROBORIO__
#include "wpi/timestamp.h"
#endif
/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
* include that file because it conflicts with <time.h>. We'll just have to
* define it ourselves.
*/
#ifndef CLOCK_BOOTTIME
# define CLOCK_BOOTTIME 7
#endif
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci);
static int read_times(FILE* statfile_fp,
unsigned int numcpus,
uv_cpu_info_t* ci);
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
static uint64_t read_cpufreq(unsigned int cpunum);
int uv__platform_loop_init(uv_loop_t* loop) {
loop->inotify_fd = -1;
loop->inotify_watchers = NULL;
return uv__epoll_init(loop);
}
int uv__io_fork(uv_loop_t* loop) {
int err;
void* old_watchers;
old_watchers = loop->inotify_watchers;
uv__close(loop->backend_fd);
loop->backend_fd = -1;
uv__platform_loop_delete(loop);
err = uv__platform_loop_init(loop);
if (err)
return err;
return uv__inotify_fork(loop, old_watchers);
}
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->inotify_fd == -1) return;
uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN);
uv__close(loop->inotify_fd);
loop->inotify_fd = -1;
}
uint64_t uv__hrtime(uv_clocktype_t type) {
#ifdef __FRC_ROBORIO__
return wpi::Now() * 1000u;
#else
static clock_t fast_clock_id = -1;
struct timespec t;
clock_t clock_id;
/* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
* millisecond granularity or better. CLOCK_MONOTONIC_COARSE is
* serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
* decide to make a costly system call.
*/
/* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
* when it has microsecond granularity or better (unlikely).
*/
clock_id = CLOCK_MONOTONIC;
if (type != UV_CLOCK_FAST)
goto done;
clock_id = uv__load_relaxed(&fast_clock_id);
if (clock_id != -1)
goto done;
clock_id = CLOCK_MONOTONIC;
if (0 == clock_getres(CLOCK_MONOTONIC_COARSE, &t))
if (t.tv_nsec <= 1 * 1000 * 1000)
clock_id = CLOCK_MONOTONIC_COARSE;
uv__store_relaxed(&fast_clock_id, clock_id);
done:
if (clock_gettime(clock_id, &t))
return 0; /* Not really possible. */
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
#endif
}
int uv_resident_set_memory(size_t* rss) {
char buf[1024];
const char* s;
ssize_t n;
long val;
int fd;
int i;
do
fd = open("/proc/self/stat", O_RDONLY);
while (fd == -1 && errno == EINTR);
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, ')');
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 (errno != 0)
goto err;
if (val < 0)
goto err;
*rss = val * getpagesize();
return 0;
err:
return UV_EINVAL;
}
int uv_uptime(double* uptime) {
static volatile int no_clock_boottime;
char buf[128];
struct timespec now;
int r;
/* Try /proc/uptime first, then fallback to clock_gettime(). */
if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
if (1 == sscanf(buf, "%lf", uptime))
return 0;
/* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
* (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
* is suspended.
*/
if (no_clock_boottime) {
retry_clock_gettime: r = clock_gettime(CLOCK_MONOTONIC, &now);
}
else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
no_clock_boottime = 1;
goto retry_clock_gettime;
}
if (r)
return UV__ERR(errno);
*uptime = now.tv_sec;
return 0;
}
static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) {
unsigned int num;
char buf[1024];
if (!fgets(buf, sizeof(buf), statfile_fp))
return UV_EIO;
num = 0;
while (fgets(buf, sizeof(buf), statfile_fp)) {
if (strncmp(buf, "cpu", 3))
break;
num++;
}
if (num == 0)
return UV_EIO;
*numcpus = num;
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int numcpus;
uv_cpu_info_t* ci;
int err;
FILE* statfile_fp;
*cpu_infos = NULL;
*count = 0;
statfile_fp = uv__open_file("/proc/stat");
if (statfile_fp == NULL)
return UV__ERR(errno);
err = uv__cpu_num(statfile_fp, &numcpus);
if (err < 0)
goto out;
err = UV_ENOMEM;
ci = (uv_cpu_info_t*)uv__calloc(numcpus, sizeof(*ci));
if (ci == NULL)
goto out;
err = read_models(numcpus, ci);
if (err == 0)
err = read_times(statfile_fp, numcpus, ci);
if (err) {
uv_free_cpu_info(ci, numcpus);
goto out;
}
/* read_models() on x86 also reads the CPU speed from /proc/cpuinfo.
* We don't check for errors here. Worst case, the field is left zero.
*/
if (ci[0].speed == 0)
read_speeds(numcpus, ci);
*cpu_infos = ci;
*count = numcpus;
err = 0;
out:
if (fclose(statfile_fp))
if (errno != EINTR && errno != EINPROGRESS)
abort();
return err;
}
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
unsigned int num;
for (num = 0; num < numcpus; num++)
ci[num].speed = read_cpufreq(num) / 1000;
}
/* Also reads the CPU frequency on ppc and x86. The other architectures only
* have a BogoMIPS field, which may not be very accurate.
*
* Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
*/
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
#if defined(__PPC__)
static const char model_marker[] = "cpu\t\t: ";
static const char speed_marker[] = "clock\t\t: ";
#else
static const char model_marker[] = "model name\t: ";
static const char speed_marker[] = "cpu MHz\t\t: ";
#endif
const char* inferred_model;
unsigned int model_idx;
unsigned int speed_idx;
unsigned int part_idx;
char buf[1024];
char* model;
FILE* fp;
int model_id;
/* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
(void) &model_marker;
(void) &speed_marker;
(void) &speed_idx;
(void) &part_idx;
(void) &model;
(void) &buf;
(void) &fp;
(void) &model_id;
model_idx = 0;
speed_idx = 0;
part_idx = 0;
#if defined(__arm__) || \
defined(__i386__) || \
defined(__mips__) || \
defined(__aarch64__) || \
defined(__PPC__) || \
defined(__x86_64__)
fp = uv__open_file("/proc/cpuinfo");
if (fp == NULL)
return UV__ERR(errno);
while (fgets(buf, sizeof(buf), fp)) {
if (model_idx < numcpus) {
if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
model = buf + sizeof(model_marker) - 1;
model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
if (model == NULL) {
fclose(fp);
return UV_ENOMEM;
}
ci[model_idx++].model = model;
continue;
}
}
#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
if (model_idx < numcpus) {
#if defined(__arm__)
/* Fallback for pre-3.8 kernels. */
static const char model_marker[] = "Processor\t: ";
#elif defined(__aarch64__)
static const char part_marker[] = "CPU part\t: ";
/* Adapted from: https://github.com/karelzak/util-linux */
struct vendor_part {
const int id;
const char* name;
};
static const struct vendor_part arm_chips[] = {
{ 0x811, "ARM810" },
{ 0x920, "ARM920" },
{ 0x922, "ARM922" },
{ 0x926, "ARM926" },
{ 0x940, "ARM940" },
{ 0x946, "ARM946" },
{ 0x966, "ARM966" },
{ 0xa20, "ARM1020" },
{ 0xa22, "ARM1022" },
{ 0xa26, "ARM1026" },
{ 0xb02, "ARM11 MPCore" },
{ 0xb36, "ARM1136" },
{ 0xb56, "ARM1156" },
{ 0xb76, "ARM1176" },
{ 0xc05, "Cortex-A5" },
{ 0xc07, "Cortex-A7" },
{ 0xc08, "Cortex-A8" },
{ 0xc09, "Cortex-A9" },
{ 0xc0d, "Cortex-A17" }, /* Originally A12 */
{ 0xc0f, "Cortex-A15" },
{ 0xc0e, "Cortex-A17" },
{ 0xc14, "Cortex-R4" },
{ 0xc15, "Cortex-R5" },
{ 0xc17, "Cortex-R7" },
{ 0xc18, "Cortex-R8" },
{ 0xc20, "Cortex-M0" },
{ 0xc21, "Cortex-M1" },
{ 0xc23, "Cortex-M3" },
{ 0xc24, "Cortex-M4" },
{ 0xc27, "Cortex-M7" },
{ 0xc60, "Cortex-M0+" },
{ 0xd01, "Cortex-A32" },
{ 0xd03, "Cortex-A53" },
{ 0xd04, "Cortex-A35" },
{ 0xd05, "Cortex-A55" },
{ 0xd06, "Cortex-A65" },
{ 0xd07, "Cortex-A57" },
{ 0xd08, "Cortex-A72" },
{ 0xd09, "Cortex-A73" },
{ 0xd0a, "Cortex-A75" },
{ 0xd0b, "Cortex-A76" },
{ 0xd0c, "Neoverse-N1" },
{ 0xd0d, "Cortex-A77" },
{ 0xd0e, "Cortex-A76AE" },
{ 0xd13, "Cortex-R52" },
{ 0xd20, "Cortex-M23" },
{ 0xd21, "Cortex-M33" },
{ 0xd41, "Cortex-A78" },
{ 0xd42, "Cortex-A78AE" },
{ 0xd4a, "Neoverse-E1" },
{ 0xd4b, "Cortex-A78C" },
};
if (strncmp(buf, part_marker, sizeof(part_marker) - 1) == 0) {
model = buf + sizeof(part_marker) - 1;
errno = 0;
model_id = strtol(model, NULL, 16);
if ((errno != 0) || model_id < 0) {
fclose(fp);
return UV_EINVAL;
}
for (part_idx = 0; part_idx < ARRAY_SIZE(arm_chips); part_idx++) {
if (model_id == arm_chips[part_idx].id) {
model = uv__strdup(arm_chips[part_idx].name);
if (model == NULL) {
fclose(fp);
return UV_ENOMEM;
}
ci[model_idx++].model = model;
break;
}
}
}
#else /* defined(__mips__) */
static const char model_marker[] = "cpu model\t\t: ";
#endif
if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
model = buf + sizeof(model_marker) - 1;
model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
if (model == NULL) {
fclose(fp);
return UV_ENOMEM;
}
ci[model_idx++].model = model;
continue;
}
}
#else /* !__arm__ && !__mips__ && !__aarch64__ */
if (speed_idx < numcpus) {
if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
continue;
}
}
#endif /* __arm__ || __mips__ || __aarch64__ */
}
fclose(fp);
#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ || __aarch__ */
/* Now we want to make sure that all the models contain *something* because
* it's not safe to leave them as null. Copy the last entry unless there
* isn't one, in that case we simply put "unknown" into everything.
*/
inferred_model = "unknown";
if (model_idx > 0)
inferred_model = ci[model_idx - 1].model;
while (model_idx < numcpus) {
model = uv__strndup(inferred_model, strlen(inferred_model));
if (model == NULL)
return UV_ENOMEM;
ci[model_idx++].model = model;
}
return 0;
}
static int read_times(FILE* statfile_fp,
unsigned int numcpus,
uv_cpu_info_t* ci) {
struct uv_cpu_times_s ts;
unsigned int ticks;
unsigned int multiplier;
uint64_t user;
uint64_t nice;
uint64_t sys;
uint64_t idle;
uint64_t dummy;
uint64_t irq;
uint64_t num;
uint64_t len;
char buf[1024];
ticks = (unsigned int)sysconf(_SC_CLK_TCK);
assert(ticks != (unsigned int) -1);
assert(ticks != 0);
multiplier = ((uint64_t)1000L / ticks);
rewind(statfile_fp);
if (!fgets(buf, sizeof(buf), statfile_fp))
abort();
num = 0;
while (fgets(buf, sizeof(buf), statfile_fp)) {
if (num >= numcpus)
break;
if (strncmp(buf, "cpu", 3))
break;
/* skip "cpu<num> " marker */
{
unsigned int n;
int r = sscanf(buf, "cpu%u ", &n);
assert(r == 1);
(void) r; /* silence build warning */
for (len = sizeof("cpu0"); n /= 10; len++);
}
/* Line contains user, nice, system, idle, iowait, irq, softirq, steal,
* guest, guest_nice but we're only interested in the first four + irq.
*
* Don't use %*s to skip fields or %ll to read straight into the uint64_t
* fields, they're not allowed in C89 mode.
*/
if (6 != sscanf(buf + len,
"%" PRIu64 " %" PRIu64 " %" PRIu64
"%" PRIu64 " %" PRIu64 " %" PRIu64,
&user,
&nice,
&sys,
&idle,
&dummy,
&irq))
abort();
ts.user = user * multiplier;
ts.nice = nice * multiplier;
ts.sys = sys * multiplier;
ts.idle = idle * multiplier;
ts.irq = irq * multiplier;
ci[num++].cpu_times = ts;
}
assert(num == numcpus);
return 0;
}
static uint64_t read_cpufreq(unsigned int cpunum) {
uint64_t val;
char buf[1024];
FILE* fp;
snprintf(buf,
sizeof(buf),
"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
cpunum);
fp = uv__open_file(buf);
if (fp == NULL)
return 0;
if (fscanf(fp, "%" PRIu64, &val) != 1)
val = 0;
fclose(fp);
return val;
}
#ifdef HAVE_IFADDRS_H
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
return 1;
if (ent->ifa_addr == NULL)
return 1;
/*
* On Linux getifaddrs returns information related to the raw underlying
* devices. We're not interested in this information yet.
*/
if (ent->ifa_addr->sa_family == PF_PACKET)
return exclude_type;
return !exclude_type;
}
#endif
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
#ifndef HAVE_IFADDRS_H
*count = 0;
*addresses = NULL;
return UV_ENOSYS;
#else
struct ifaddrs *addrs, *ent;
uv_interface_address_t* address;
int i;
struct sockaddr_ll *sll;
*count = 0;
*addresses = NULL;
if (getifaddrs(&addrs))
return UV__ERR(errno);
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
(*count)++;
}
if (*count == 0) {
freeifaddrs(addrs);
return 0;
}
/* Make sure the memory is initiallized to zero using calloc() */
*addresses = (uv_interface_address_t*)uv__calloc(*count, sizeof(**addresses));
if (!(*addresses)) {
freeifaddrs(addrs);
return UV_ENOMEM;
}
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
address->name = uv__strdup(ent->ifa_name);
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
} else {
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
}
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
address++;
}
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
continue;
address = *addresses;
for (i = 0; i < (*count); i++) {
size_t namelen = strlen(ent->ifa_name);
/* Alias interface share the same physical address */
if (strncmp(address->name, ent->ifa_name, namelen) == 0 &&
(address->name[namelen] == 0 || address->name[namelen] == ':')) {
sll = (struct sockaddr_ll*)ent->ifa_addr;
memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
}
address++;
}
}
freeifaddrs(addrs);
return 0;
#endif
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; i++) {
uv__free(addresses[i].name);
}
uv__free(addresses);
}
void uv__set_process_title(const char* title) {
#if defined(PR_SET_NAME)
prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */
#endif
}
static uint64_t uv__read_proc_meminfo(const char* what) {
uint64_t rc;
char* p;
char buf[4096]; /* Large enough to hold all of /proc/meminfo. */
if (uv__slurp("/proc/meminfo", buf, sizeof(buf)))
return 0;
p = strstr(buf, what);
if (p == NULL)
return 0;
p += strlen(what);
rc = 0;
sscanf(p, "%" PRIu64 " kB", &rc);
return rc * 1024;
}
uint64_t uv_get_free_memory(void) {
struct sysinfo info;
uint64_t rc;
rc = uv__read_proc_meminfo("MemAvailable:");
if (rc != 0)
return rc;
if (0 == sysinfo(&info))
return (uint64_t) info.freeram * info.mem_unit;
return 0;
}
uint64_t uv_get_total_memory(void) {
struct sysinfo info;
uint64_t rc;
rc = uv__read_proc_meminfo("MemTotal:");
if (rc != 0)
return rc;
if (0 == sysinfo(&info))
return (uint64_t) info.totalram * info.mem_unit;
return 0;
}
static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) {
char filename[256];
char buf[32]; /* Large enough to hold an encoded uint64_t. */
uint64_t rc;
rc = 0;
snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/%s", cgroup, param);
if (0 == uv__slurp(filename, buf, sizeof(buf)))
sscanf(buf, "%" PRIu64, &rc);
return rc;
}
uint64_t uv_get_constrained_memory(void) {
/*
* This might return 0 if there was a problem getting the memory limit from
* cgroups. This is OK because a return value of 0 signifies that the memory
* limit is unknown.
*/
return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes");
}
void uv_loadavg(double avg[3]) {
struct sysinfo info;
char buf[128]; /* Large enough to hold all of /proc/loadavg. */
if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf)))
if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2]))
return;
if (sysinfo(&info) < 0)
return;
avg[0] = (double) info.loads[0] / 65536.0;
avg[1] = (double) info.loads[1] / 65536.0;
avg[2] = (double) info.loads[2] / 65536.0;
}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -32,7 +32,7 @@
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
if (uv__is_active(handle)) return 0; \
if (cb == NULL) return UV_EINVAL; \
QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
uv__queue_insert_head(&handle->loop->name##_handles, &handle->queue); \
handle->name##_cb = cb; \
uv__handle_start(handle); \
return 0; \
@@ -40,21 +40,21 @@
\
int uv_##name##_stop(uv_##name##_t* handle) { \
if (!uv__is_active(handle)) return 0; \
QUEUE_REMOVE(&handle->queue); \
uv__queue_remove(&handle->queue); \
uv__handle_stop(handle); \
return 0; \
} \
\
void uv__run_##name(uv_loop_t* loop) { \
uv_##name##_t* h; \
QUEUE queue; \
QUEUE* q; \
QUEUE_MOVE(&loop->name##_handles, &queue); \
while (!QUEUE_EMPTY(&queue)) { \
q = QUEUE_HEAD(&queue); \
h = QUEUE_DATA(q, uv_##name##_t, queue); \
QUEUE_REMOVE(q); \
QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
struct uv__queue queue; \
struct uv__queue* q; \
uv__queue_move(&loop->name##_handles, &queue); \
while (!uv__queue_empty(&queue)) { \
q = uv__queue_head(&queue); \
h = uv__queue_data(q, uv_##name##_t, queue); \
uv__queue_remove(q); \
uv__queue_insert_tail(&loop->name##_handles, q); \
h->name##_cb(h); \
} \
} \

View File

@@ -45,22 +45,25 @@ int uv_loop_init(uv_loop_t* loop) {
err = uv_mutex_init(&lfields->loop_metrics.lock);
if (err)
goto fail_metrics_mutex_init;
memset(&lfields->loop_metrics.metrics,
0,
sizeof(lfields->loop_metrics.metrics));
heap_init((struct heap*) &loop->timer_heap);
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->idle_handles);
QUEUE_INIT(&loop->async_handles);
QUEUE_INIT(&loop->check_handles);
QUEUE_INIT(&loop->prepare_handles);
QUEUE_INIT(&loop->handle_queue);
uv__queue_init(&loop->wq);
uv__queue_init(&loop->idle_handles);
uv__queue_init(&loop->async_handles);
uv__queue_init(&loop->check_handles);
uv__queue_init(&loop->prepare_handles);
uv__queue_init(&loop->handle_queue);
loop->active_handles = 0;
loop->active_reqs.count = 0;
loop->nfds = 0;
loop->watchers = NULL;
loop->nwatchers = 0;
QUEUE_INIT(&loop->pending_queue);
QUEUE_INIT(&loop->watcher_queue);
uv__queue_init(&loop->pending_queue);
uv__queue_init(&loop->watcher_queue);
loop->closing_handles = NULL;
uv__update_time(loop);
@@ -79,13 +82,10 @@ int uv_loop_init(uv_loop_t* loop) {
goto fail_platform_init;
uv__signal_global_once_init();
err = uv_signal_init(loop, &loop->child_watcher);
err = uv__process_init(loop);
if (err)
goto fail_signal_init;
uv__handle_unref(&loop->child_watcher);
loop->child_watcher.flags |= UV_HANDLE_INTERNAL;
QUEUE_INIT(&loop->process_handles);
uv__queue_init(&loop->process_handles);
err = uv_rwlock_init(&loop->cloexec_lock);
if (err)
@@ -152,9 +152,9 @@ int uv_loop_fork(uv_loop_t* loop) {
if (w == NULL)
continue;
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) {
if (w->pevents != 0 && uv__queue_empty(&w->watcher_queue)) {
w->events = 0; /* Force re-registration in uv__io_poll. */
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
}
}
@@ -180,7 +180,7 @@ void uv__loop_close(uv_loop_t* loop) {
}
uv_mutex_lock(&loop->wq_mutex);
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
assert(uv__queue_empty(&loop->wq) && "thread pool work queue not empty!");
assert(!uv__has_active_reqs(loop));
uv_mutex_unlock(&loop->wq_mutex);
uv_mutex_destroy(&loop->wq_mutex);
@@ -192,8 +192,8 @@ void uv__loop_close(uv_loop_t* loop) {
uv_rwlock_destroy(&loop->cloexec_lock);
#if 0
assert(QUEUE_EMPTY(&loop->pending_queue));
assert(QUEUE_EMPTY(&loop->watcher_queue));
assert(uv__queue_empty(&loop->pending_queue));
assert(uv__queue_empty(&loop->watcher_queue));
assert(loop->nfds == 0);
#endif

View File

@@ -103,7 +103,7 @@ uint64_t uv_get_free_memory(void) {
int which[] = {CTL_VM, VM_UVMEXP};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return 0;
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
}
@@ -120,7 +120,7 @@ uint64_t uv_get_total_memory(void) {
size_t size = sizeof(info);
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return 0;
return (uint64_t) info;
}
@@ -131,6 +131,11 @@ uint64_t uv_get_constrained_memory(void) {
}
uint64_t uv_get_available_memory(void) {
return uv_get_free_memory();
}
int uv_resident_set_memory(size_t* rss) {
kvm_t *kd = NULL;
struct kinfo_proc2 *kinfo = NULL;

View File

@@ -116,7 +116,7 @@ uint64_t uv_get_free_memory(void) {
int which[] = {CTL_VM, VM_UVMEXP};
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return 0;
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
}
@@ -128,7 +128,7 @@ uint64_t uv_get_total_memory(void) {
size_t size = sizeof(info);
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
return UV__ERR(errno);
return 0;
return (uint64_t) info;
}
@@ -139,6 +139,11 @@ uint64_t uv_get_constrained_memory(void) {
}
uint64_t uv_get_available_memory(void) {
return uv_get_free_memory();
}
int uv_resident_set_memory(size_t* rss) {
struct kinfo_proc kinfo;
size_t page_size = getpagesize();

View File

@@ -41,26 +41,60 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
return uv_pipe_bind2(handle, name, strlen(name), 0);
}
int uv_pipe_bind2(uv_pipe_t* handle,
const char* name,
size_t namelen,
unsigned int flags) {
struct sockaddr_un saddr;
const char* pipe_fname;
char* pipe_fname;
int sockfd;
int err;
pipe_fname = NULL;
if (flags & ~UV_PIPE_NO_TRUNCATE)
return UV_EINVAL;
if (name == NULL)
return UV_EINVAL;
if (namelen == 0)
return UV_EINVAL;
#ifndef __linux__
/* Abstract socket namespace only works on Linux. */
if (*name == '\0')
return UV_EINVAL;
#endif
if (flags & UV_PIPE_NO_TRUNCATE)
if (namelen > sizeof(saddr.sun_path))
return UV_EINVAL;
/* Truncate long paths. Documented behavior. */
if (namelen > sizeof(saddr.sun_path))
namelen = sizeof(saddr.sun_path);
/* Already bound? */
if (uv__stream_fd(handle) >= 0)
return UV_EINVAL;
if (uv__is_closing(handle)) {
return UV_EINVAL;
}
/* Make a copy of the file name, it outlives this function's scope. */
pipe_fname = uv__strdup(name);
if (pipe_fname == NULL)
return UV_ENOMEM;
/* We've got a copy, don't touch the original any more. */
name = NULL;
if (uv__is_closing(handle))
return UV_EINVAL;
/* Make a copy of the file path unless it is an abstract socket.
* We unlink the file later but abstract sockets disappear
* automatically since they're not real file system entities.
*/
if (*name != '\0') {
pipe_fname = uv__strdup(name);
if (pipe_fname == NULL)
return UV_ENOMEM;
}
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
if (err < 0)
@@ -68,7 +102,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
sockfd = err;
memset(&saddr, 0, sizeof saddr);
uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
memcpy(&saddr.sun_path, name, namelen);
saddr.sun_family = AF_UNIX;
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
@@ -83,12 +117,12 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
/* Success. */
handle->flags |= UV_HANDLE_BOUND;
handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
handle->pipe_fname = pipe_fname; /* NULL or a strdup'ed copy. */
handle->io_watcher.fd = sockfd;
return 0;
err_socket:
uv__free((void*)pipe_fname);
uv__free(pipe_fname);
return err;
}
@@ -176,11 +210,44 @@ void uv_pipe_connect(uv_connect_t* req,
uv_pipe_t* handle,
const char* name,
uv_connect_cb cb) {
uv_pipe_connect2(req, handle, name, strlen(name), 0, cb);
}
int uv_pipe_connect2(uv_connect_t* req,
uv_pipe_t* handle,
const char* name,
size_t namelen,
unsigned int flags,
uv_connect_cb cb) {
struct sockaddr_un saddr;
int new_sock;
int err;
int r;
if (flags & ~UV_PIPE_NO_TRUNCATE)
return UV_EINVAL;
if (name == NULL)
return UV_EINVAL;
if (namelen == 0)
return UV_EINVAL;
#ifndef __linux__
/* Abstract socket namespace only works on Linux. */
if (*name == '\0')
return UV_EINVAL;
#endif
if (flags & UV_PIPE_NO_TRUNCATE)
if (namelen > sizeof(saddr.sun_path))
return UV_EINVAL;
/* Truncate long paths. Documented behavior. */
if (namelen > sizeof(saddr.sun_path))
namelen = sizeof(saddr.sun_path);
new_sock = (uv__stream_fd(handle) == -1);
if (new_sock) {
@@ -191,7 +258,7 @@ void uv_pipe_connect(uv_connect_t* req,
}
memset(&saddr, 0, sizeof saddr);
uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path));
memcpy(&saddr.sun_path, name, namelen);
saddr.sun_family = AF_UNIX;
do {
@@ -230,12 +297,13 @@ out:
uv__req_init(handle->loop, req, UV_CONNECT);
req->handle = (uv_stream_t*)handle;
req->cb = cb;
QUEUE_INIT(&req->queue);
uv__queue_init(&req->queue);
/* Force callback to run on next tick in case of error. */
if (err)
uv__io_feed(handle->loop, &handle->io_watcher);
return 0;
}
@@ -357,7 +425,7 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
}
/* stat must be used as fstat has a bug on Darwin */
if (stat(name_buffer, &pipe_stat) == -1) {
if (uv__stat(name_buffer, &pipe_stat) == -1) {
uv__free(name_buffer);
return -errno;
}

View File

@@ -125,7 +125,7 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
UV_PRIORITIZED)) == 0);
assert(!uv__is_closing(handle));
watchers = handle->loop->watchers;
watchers = (void**)handle->loop->watchers;
w = &handle->io_watcher;
if (uv__fd_exists(handle->loop, w->fd))

View File

@@ -23,13 +23,14 @@
#include "internal.h"
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
uint64_t uv__hrtime(uv_clocktype_t type) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
struct timespec t;
if (clock_gettime(CLOCK_MONOTONIC, &t))
abort();
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
}

View File

@@ -132,11 +132,12 @@ static void uv__pollfds_del(uv_loop_t* loop, int fd) {
void uv__io_poll(uv_loop_t* loop, int timeout) {
uv__loop_internal_fields_t* lfields;
sigset_t* pset;
sigset_t set;
uint64_t time_base;
uint64_t time_diff;
QUEUE* q;
struct uv__queue* q;
uv__io_t* w;
size_t i;
unsigned int nevents;
@@ -148,17 +149,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
assert(uv__queue_empty(&loop->watcher_queue));
return;
}
/* Take queued watchers and add their fds to our poll fds array. */
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
lfields = uv__get_internal_fields(loop);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
/* Take queued watchers and add their fds to our poll fds array. */
while (!uv__queue_empty(&loop->watcher_queue)) {
q = uv__queue_head(&loop->watcher_queue);
uv__queue_remove(q);
uv__queue_init(q);
w = uv__queue_data(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
assert(w->fd < (int) loop->nwatchers);
@@ -179,7 +182,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
assert(timeout >= -1);
time_base = loop->time;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
if (lfields->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
@@ -198,6 +201,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
/* Store the current timeout in a location that's globally accessible so
* other locations like uv__work_done() can determine whether the queue
* of events in the callback were waiting when poll was called.
*/
lfields->current_timeout = timeout;
if (pset != NULL)
if (pthread_sigmask(SIG_BLOCK, pset, NULL))
abort();
@@ -292,9 +301,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
}
}
uv__metrics_inc_events(loop, nevents);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
uv__metrics_inc_events_waiting(loop, nevents);
}
if (have_signals != 0) {

View File

@@ -55,7 +55,7 @@
extern char **environ;
#endif
#if defined(__linux__) || defined(__GLIBC__)
#if defined(__linux__)
# include <grp.h>
#endif
@@ -79,8 +79,28 @@ static void uv__chld(uv_signal_t* handle, int signum) {
assert(signum == SIGCHLD);
uv__wait_children(handle->loop);
}
int uv__process_init(uv_loop_t* loop) {
int err;
err = uv_signal_init(loop, &loop->child_watcher);
if (err)
return err;
uv__handle_unref(&loop->child_watcher);
loop->child_watcher.flags |= UV_HANDLE_INTERNAL;
return 0;
}
#else
int uv__process_init(uv_loop_t* loop) {
memset(&loop->child_watcher, 0, sizeof(loop->child_watcher));
return 0;
}
#endif
void uv__wait_children(uv_loop_t* loop) {
uv_process_t* process;
int exit_status;
@@ -88,23 +108,24 @@ void uv__wait_children(uv_loop_t* loop) {
int status;
int options;
pid_t pid;
QUEUE pending;
QUEUE* q;
QUEUE* h;
struct uv__queue pending;
struct uv__queue* q;
struct uv__queue* h;
QUEUE_INIT(&pending);
uv__queue_init(&pending);
h = &loop->process_handles;
q = QUEUE_HEAD(h);
q = uv__queue_head(h);
while (q != h) {
process = QUEUE_DATA(q, uv_process_t, queue);
q = QUEUE_NEXT(q);
process = uv__queue_data(q, uv_process_t, queue);
q = uv__queue_next(q);
#ifndef UV_USE_SIGCHLD
if ((process->flags & UV_HANDLE_REAP) == 0)
continue;
options = 0;
process->flags &= ~UV_HANDLE_REAP;
loop->nfds--;
#else
options = WNOHANG;
#endif
@@ -128,18 +149,18 @@ void uv__wait_children(uv_loop_t* loop) {
assert(pid == process->pid);
process->status = status;
QUEUE_REMOVE(&process->queue);
QUEUE_INSERT_TAIL(&pending, &process->queue);
uv__queue_remove(&process->queue);
uv__queue_insert_tail(&pending, &process->queue);
}
h = &pending;
q = QUEUE_HEAD(h);
q = uv__queue_head(h);
while (q != h) {
process = QUEUE_DATA(q, uv_process_t, queue);
q = QUEUE_NEXT(q);
process = uv__queue_data(q, uv_process_t, queue);
q = uv__queue_next(q);
QUEUE_REMOVE(&process->queue);
QUEUE_INIT(&process->queue);
uv__queue_remove(&process->queue);
uv__queue_init(&process->queue);
uv__handle_stop(process);
if (process->exit_cb == NULL)
@@ -155,13 +176,18 @@ void uv__wait_children(uv_loop_t* loop) {
process->exit_cb(process, exit_status, term_signal);
}
assert(QUEUE_EMPTY(&pending));
assert(uv__queue_empty(&pending));
}
/*
* Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success. See also the cleanup section in uv_spawn().
*/
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
* avoided. Since this isn't called on those targets, the function
* doesn't even need to be defined for them.
*/
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
int mask;
int fd;
@@ -248,11 +274,6 @@ static void uv__write_errno(int error_fd) {
}
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
* avoided. Since this isn't called on those targets, the function
* doesn't even need to be defined for them.
*/
static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
@@ -384,7 +405,6 @@ static void uv__process_child_init(const uv_process_options_t* options,
uv__write_errno(error_fd);
}
#endif
#if defined(__APPLE__)
@@ -665,7 +685,7 @@ static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options,
if (options->file == NULL)
return ENOENT;
/* The environment for the child process is that of the parent unless overriden
/* The environment for the child process is that of the parent unless overridden
* by options->env */
char** env = environ;
if (options->env != NULL)
@@ -931,6 +951,7 @@ static int uv__spawn_and_init_child(
return err;
}
#endif /* ISN'T TARGET_OS_TV || TARGET_OS_WATCH */
int uv_spawn(uv_loop_t* loop,
uv_process_t* process,
@@ -957,7 +978,7 @@ int uv_spawn(uv_loop_t* loop,
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
QUEUE_INIT(&process->queue);
uv__queue_init(&process->queue);
process->status = 0;
stdio_count = options->stdio_count;
@@ -1012,11 +1033,15 @@ int uv_spawn(uv_loop_t* loop,
process->flags |= UV_HANDLE_REAP;
loop->flags |= UV_LOOP_REAP_CHILDREN;
}
/* This prevents uv__io_poll() from bailing out prematurely, being unaware
* that we added an event here for it to react to. We will decrement this
* again after the waitpid call succeeds. */
loop->nfds++;
#endif
process->pid = pid;
process->exit_cb = options->exit_cb;
QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
uv__queue_insert_tail(&loop->process_handles, &process->queue);
uv__handle_start(process);
}
@@ -1078,8 +1103,10 @@ int uv_kill(int pid, int signum) {
void uv__process_close(uv_process_t* handle) {
QUEUE_REMOVE(&handle->queue);
uv__queue_remove(&handle->queue);
uv__handle_stop(handle);
if (QUEUE_EMPTY(&handle->loop->process_handles))
#ifdef UV_USE_SIGCHLD
if (uv__queue_empty(&handle->loop->process_handles))
uv_signal_stop(&handle->loop->child_watcher);
#endif
}

View File

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

View File

@@ -40,7 +40,7 @@ int uv__random_readpath(const char* path, void* buf, size_t buflen) {
if (fd < 0)
return fd;
if (fstat(fd, &s)) {
if (uv__fstat(fd, &s)) {
uv__close(fd);
return UV__ERR(errno);
}

View File

@@ -24,8 +24,6 @@
#ifdef __linux__
#include "linux-syscalls.h"
#define uv__random_getrandom_init() 0
#else /* !__linux__ */

View File

@@ -279,6 +279,8 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
int uv__signal_loop_fork(uv_loop_t* loop) {
if (loop->signal_pipefd[0] == -1)
return 0;
uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
uv__close(loop->signal_pipefd[0]);
uv__close(loop->signal_pipefd[1]);
@@ -289,16 +291,16 @@ int uv__signal_loop_fork(uv_loop_t* loop) {
void uv__signal_loop_cleanup(uv_loop_t* loop) {
QUEUE* q;
struct uv__queue* q;
/* Stop all the signal watchers that are still attached to this loop. This
* ensures that the (shared) signal tree doesn't contain any invalid entries
* entries, and that signal handlers are removed when appropriate.
* It's safe to use QUEUE_FOREACH here because the handles and the handle
* It's safe to use uv__queue_foreach here because the handles and the handle
* queue are not modified by uv__signal_stop().
*/
QUEUE_FOREACH(q, &loop->handle_queue) {
uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
uv__queue_foreach(q, &loop->handle_queue) {
uv_handle_t* handle = uv__queue_data(q, uv_handle_t, handle_queue);
if (handle->type == UV_SIGNAL)
uv__signal_stop((uv_signal_t*) handle);

View File

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

View File

@@ -60,6 +60,16 @@ struct uv__stream_select_s {
};
#endif /* defined(__APPLE__) */
union uv__cmsg {
struct cmsghdr hdr;
/* This cannot be larger because of the IBMi PASE limitation that
* the total size of control messages cannot exceed 256 bytes.
*/
char pad[256];
};
STATIC_ASSERT(256 == sizeof(union uv__cmsg));
static void uv__stream_connect(uv_stream_t*);
static void uv__write(uv_stream_t* stream);
static void uv__read(uv_stream_t* stream);
@@ -84,8 +94,8 @@ void uv__stream_init(uv_loop_t* loop,
stream->accepted_fd = -1;
stream->queued_fds = NULL;
stream->delayed_error = 0;
QUEUE_INIT(&stream->write_queue);
QUEUE_INIT(&stream->write_completed_queue);
uv__queue_init(&stream->write_queue);
uv__queue_init(&stream->write_completed_queue);
stream->write_queue_size = 0;
if (loop->emfile_fd == -1) {
@@ -429,15 +439,15 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
uv_write_t* req;
QUEUE* q;
while (!QUEUE_EMPTY(&stream->write_queue)) {
q = QUEUE_HEAD(&stream->write_queue);
QUEUE_REMOVE(q);
struct uv__queue* q;
while (!uv__queue_empty(&stream->write_queue)) {
q = uv__queue_head(&stream->write_queue);
uv__queue_remove(q);
req = QUEUE_DATA(q, uv_write_t, queue);
req = uv__queue_data(q, uv_write_t, queue);
req->error = error;
QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
uv__queue_insert_tail(&stream->write_completed_queue, &req->queue);
}
}
@@ -495,76 +505,34 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
}
#if defined(UV_HAVE_KQUEUE)
# define UV_DEC_BACKLOG(w) w->rcount--;
#else
# define UV_DEC_BACKLOG(w) /* no-op */
#endif /* defined(UV_HAVE_KQUEUE) */
void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
uv_stream_t* stream;
int err;
int fd;
stream = container_of(w, uv_stream_t, io_watcher);
assert(events & POLLIN);
assert(stream->accepted_fd == -1);
assert(!(stream->flags & UV_HANDLE_CLOSING));
uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
fd = uv__stream_fd(stream);
err = uv__accept(fd);
/* connection_cb can close the server socket while we're
* in the loop so check it on each iteration.
*/
while (uv__stream_fd(stream) != -1) {
assert(stream->accepted_fd == -1);
if (err == UV_EMFILE || err == UV_ENFILE)
err = uv__emfile_trick(loop, fd); /* Shed load. */
#if defined(UV_HAVE_KQUEUE)
if (w->rcount <= 0)
return;
#endif /* defined(UV_HAVE_KQUEUE) */
if (err < 0)
return;
err = uv__accept(uv__stream_fd(stream));
if (err < 0) {
if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK))
return; /* Not an error. */
stream->accepted_fd = err;
stream->connection_cb(stream, 0);
if (err == UV_ECONNABORTED)
continue; /* Ignore. Nothing we can do about that. */
if (err == UV_EMFILE || err == UV_ENFILE) {
err = uv__emfile_trick(loop, uv__stream_fd(stream));
if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK))
break;
}
stream->connection_cb(stream, err);
continue;
}
UV_DEC_BACKLOG(w)
stream->accepted_fd = err;
stream->connection_cb(stream, 0);
if (stream->accepted_fd != -1) {
/* The user hasn't yet accepted called uv_accept() */
uv__io_stop(loop, &stream->io_watcher, POLLIN);
return;
}
if (stream->type == UV_TCP &&
(stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
/* Give other processes a chance to accept connections. */
struct timespec timeout = { 0, 1 };
nanosleep(&timeout, NULL);
}
}
if (stream->accepted_fd != -1)
/* The user hasn't yet accepted called uv_accept() */
uv__io_stop(loop, &stream->io_watcher, POLLIN);
}
#undef UV_DEC_BACKLOG
int uv_accept(uv_stream_t* server, uv_stream_t* client) {
int err;
@@ -659,13 +627,13 @@ static void uv__drain(uv_stream_t* stream) {
uv_shutdown_t* req;
int err;
assert(QUEUE_EMPTY(&stream->write_queue));
assert(uv__queue_empty(&stream->write_queue));
if (!(stream->flags & UV_HANDLE_CLOSING)) {
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream);
}
if (!(stream->flags & UV_HANDLE_SHUTTING))
if (!uv__is_stream_shutting(stream))
return;
req = stream->shutdown_req;
@@ -674,7 +642,6 @@ static void uv__drain(uv_stream_t* stream) {
if ((stream->flags & UV_HANDLE_CLOSING) ||
!(stream->flags & UV_HANDLE_SHUT)) {
stream->shutdown_req = NULL;
stream->flags &= ~UV_HANDLE_SHUTTING;
uv__req_unregister(stream->loop, req);
err = 0;
@@ -747,7 +714,7 @@ static void uv__write_req_finish(uv_write_t* req) {
uv_stream_t* stream = req->handle;
/* Pop the req off tcp->write_queue. */
QUEUE_REMOVE(&req->queue);
uv__queue_remove(&req->queue);
/* Only free when there was no error. On error, we touch up write_queue_size
* right before making the callback. The reason we don't do that right away
@@ -764,7 +731,7 @@ static void uv__write_req_finish(uv_write_t* req) {
/* Add it to the write_completed_queue where it will have its
* callback called in the near future.
*/
QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
uv__queue_insert_tail(&stream->write_completed_queue, &req->queue);
uv__io_feed(stream->loop, &stream->io_watcher);
}
@@ -812,18 +779,14 @@ static int uv__try_write(uv_stream_t* stream,
if (send_handle != NULL) {
int fd_to_send;
struct msghdr msg;
struct cmsghdr *cmsg;
union {
char data[64];
struct cmsghdr alias;
} scratch;
union uv__cmsg cmsg;
if (uv__is_closing(send_handle))
return UV_EBADF;
fd_to_send = uv__handle_fd((uv_handle_t*) send_handle);
memset(&scratch, 0, sizeof(scratch));
memset(&cmsg, 0, sizeof(cmsg));
assert(fd_to_send >= 0);
@@ -833,20 +796,13 @@ static int uv__try_write(uv_stream_t* stream,
msg.msg_iovlen = iovcnt;
msg.msg_flags = 0;
msg.msg_control = &scratch.alias;
msg.msg_control = &cmsg.hdr;
msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send));
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
/* silence aliasing warning */
{
void* pv = CMSG_DATA(cmsg);
int* pi = (int*)pv;
*pi = fd_to_send;
}
cmsg.hdr.cmsg_level = SOL_SOCKET;
cmsg.hdr.cmsg_type = SCM_RIGHTS;
cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(fd_to_send));
memcpy(CMSG_DATA(&cmsg.hdr), &fd_to_send, sizeof(fd_to_send));
do
n = sendmsg(uv__stream_fd(stream), &msg, 0);
@@ -881,18 +837,25 @@ static int uv__try_write(uv_stream_t* stream,
}
static void uv__write(uv_stream_t* stream) {
QUEUE* q;
struct uv__queue* q;
uv_write_t* req;
ssize_t n;
int count;
assert(uv__stream_fd(stream) >= 0);
/* Prevent loop starvation when the consumer of this stream read as fast as
* (or faster than) we can write it. This `count` mechanism does not need to
* change even if we switch to edge-triggered I/O.
*/
count = 32;
for (;;) {
if (QUEUE_EMPTY(&stream->write_queue))
if (uv__queue_empty(&stream->write_queue))
return;
q = QUEUE_HEAD(&stream->write_queue);
req = QUEUE_DATA(q, uv_write_t, queue);
q = uv__queue_head(&stream->write_queue);
req = uv__queue_data(q, uv_write_t, queue);
assert(req->handle == stream);
n = uv__try_write(stream,
@@ -905,10 +868,13 @@ static void uv__write(uv_stream_t* stream) {
req->send_handle = NULL;
if (uv__write_req_update(stream, req, n)) {
uv__write_req_finish(req);
return; /* TODO(bnoordhuis) Start trying to write the next request. */
if (count-- > 0)
continue; /* Start trying to write the next request. */
return;
}
} else if (n != UV_EAGAIN)
break;
goto error;
/* If this is a blocking stream, try again. */
if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
@@ -923,6 +889,7 @@ static void uv__write(uv_stream_t* stream) {
return;
}
error:
req->error = n;
uv__write_req_finish(req);
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
@@ -932,19 +899,19 @@ static void uv__write(uv_stream_t* stream) {
static void uv__write_callbacks(uv_stream_t* stream) {
uv_write_t* req;
QUEUE* q;
QUEUE pq;
struct uv__queue* q;
struct uv__queue pq;
if (QUEUE_EMPTY(&stream->write_completed_queue))
if (uv__queue_empty(&stream->write_completed_queue))
return;
QUEUE_MOVE(&stream->write_completed_queue, &pq);
uv__queue_move(&stream->write_completed_queue, &pq);
while (!QUEUE_EMPTY(&pq)) {
while (!uv__queue_empty(&pq)) {
/* Pop a req off write_completed_queue. */
q = QUEUE_HEAD(&pq);
req = QUEUE_DATA(q, uv_write_t, queue);
QUEUE_REMOVE(q);
q = uv__queue_head(&pq);
req = uv__queue_data(q, uv_write_t, queue);
uv__queue_remove(q);
uv__req_unregister(stream->loop, req);
if (req->bufs != NULL) {
@@ -1011,57 +978,38 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
}
#if defined(__PASE__)
/* on IBMi PASE the control message length can not exceed 256. */
# define UV__CMSG_FD_COUNT 60
#else
# define UV__CMSG_FD_COUNT 64
#endif
#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int))
static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
struct cmsghdr* cmsg;
int fd;
int err;
size_t i;
size_t count;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
char* start;
char* end;
int err;
void* pv;
int* pi;
unsigned int i;
unsigned int count;
if (cmsg->cmsg_type != SCM_RIGHTS) {
fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
cmsg->cmsg_type);
continue;
}
/* silence aliasing warning */
pv = CMSG_DATA(cmsg);
pi = (int*)pv;
/* Count available fds */
start = (char*) cmsg;
end = (char*) cmsg + cmsg->cmsg_len;
count = 0;
while (start + CMSG_LEN(count * sizeof(*pi)) < end)
count++;
assert(start + CMSG_LEN(count * sizeof(*pi)) == end);
assert(cmsg->cmsg_len >= CMSG_LEN(0));
count = cmsg->cmsg_len - CMSG_LEN(0);
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, pi[i]);
err = uv__stream_queue_fd(stream, fd);
if (err != 0) {
/* Close rest */
for (; i < count; i++)
uv__close(pi[i]);
uv__close(fd);
return err;
}
} else {
stream->accepted_fd = pi[i];
stream->accepted_fd = fd;
}
}
}
@@ -1070,17 +1018,11 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
}
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-folding-constant"
# pragma clang diagnostic ignored "-Wvla-extension"
#endif
static void uv__read(uv_stream_t* stream) {
uv_buf_t buf;
ssize_t nread;
struct msghdr msg;
char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)];
union uv__cmsg cmsg;
int count;
int err;
int is_ipc;
@@ -1126,8 +1068,8 @@ static void uv__read(uv_stream_t* stream) {
msg.msg_name = NULL;
msg.msg_namelen = 0;
/* Set up to receive a descriptor even if one isn't in the message */
msg.msg_controllen = sizeof(cmsg_space);
msg.msg_control = cmsg_space;
msg.msg_controllen = sizeof(cmsg);
msg.msg_control = &cmsg.hdr;
do {
nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
@@ -1211,14 +1153,6 @@ static void uv__read(uv_stream_t* stream) {
}
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#undef UV__CMSG_FD_COUNT
#undef UV__CMSG_FD_SIZE
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
assert(stream->type == UV_TCP ||
stream->type == UV_TTY ||
@@ -1226,7 +1160,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
if (!(stream->flags & UV_HANDLE_WRITABLE) ||
stream->flags & UV_HANDLE_SHUT ||
stream->flags & UV_HANDLE_SHUTTING ||
uv__is_stream_shutting(stream) ||
uv__is_closing(stream)) {
return UV_ENOTCONN;
}
@@ -1239,10 +1173,9 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
req->handle = stream;
req->cb = cb;
stream->shutdown_req = req;
stream->flags |= UV_HANDLE_SHUTTING;
stream->flags &= ~UV_HANDLE_WRITABLE;
if (QUEUE_EMPTY(&stream->write_queue))
if (uv__queue_empty(&stream->write_queue))
uv__io_feed(stream->loop, &stream->io_watcher);
return 0;
@@ -1295,7 +1228,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
uv__write_callbacks(stream);
/* Write queue drained. */
if (QUEUE_EMPTY(&stream->write_queue))
if (uv__queue_empty(&stream->write_queue))
uv__drain(stream);
}
}
@@ -1338,7 +1271,7 @@ static void uv__stream_connect(uv_stream_t* stream) {
stream->connect_req = NULL;
uv__req_unregister(stream->loop, req);
if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) {
if (error < 0 || uv__queue_empty(&stream->write_queue)) {
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
}
@@ -1420,7 +1353,7 @@ int uv_write2(uv_write_t* req,
req->handle = stream;
req->error = 0;
req->send_handle = send_handle;
QUEUE_INIT(&req->queue);
uv__queue_init(&req->queue);
req->bufs = req->bufsml;
if (nbufs > ARRAY_SIZE(req->bufsml))
@@ -1435,7 +1368,7 @@ int uv_write2(uv_write_t* req,
stream->write_queue_size += uv__count_bufs(bufs, nbufs);
/* Append the request to write_queue. */
QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue);
uv__queue_insert_tail(&stream->write_queue, &req->queue);
/* If the queue was empty when this function began, we should attempt to
* do the write immediately. Otherwise start the write_watcher and wait

View File

@@ -28,16 +28,39 @@
#include <errno.h>
static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
struct sockaddr_storage saddr;
static int maybe_bind_socket(int fd) {
union uv__sockaddr s;
socklen_t slen;
slen = sizeof(s);
memset(&s, 0, sizeof(s));
if (getsockname(fd, &s.addr, &slen))
return UV__ERR(errno);
if (s.addr.sa_family == AF_INET)
if (s.in.sin_port != 0)
return 0; /* Already bound to a port. */
if (s.addr.sa_family == AF_INET6)
if (s.in6.sin6_port != 0)
return 0; /* Already bound to a port. */
/* Bind to an arbitrary port. */
if (bind(fd, &s.addr, slen))
return UV__ERR(errno);
return 0;
}
static int new_socket(uv_tcp_t* handle, int domain, unsigned int flags) {
int sockfd;
int err;
err = uv__socket(domain, SOCK_STREAM, 0);
if (err < 0)
return err;
sockfd = err;
sockfd = uv__socket(domain, SOCK_STREAM, 0);
if (sockfd < 0)
return sockfd;
err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
if (err) {
@@ -45,74 +68,44 @@ static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
return err;
}
if (flags & UV_HANDLE_BOUND) {
/* Bind this new socket to an arbitrary port */
slen = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) {
uv__close(sockfd);
return UV__ERR(errno);
}
if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) {
uv__close(sockfd);
return UV__ERR(errno);
}
}
if (flags & UV_HANDLE_BOUND)
return maybe_bind_socket(sockfd);
return 0;
}
static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
struct sockaddr_storage saddr;
socklen_t slen;
static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned int flags) {
int sockfd;
int err;
if (domain == AF_UNSPEC) {
handle->flags |= flags;
return 0;
}
if (domain == AF_UNSPEC)
goto out;
if (uv__stream_fd(handle) != -1) {
sockfd = uv__stream_fd(handle);
if (sockfd == -1)
return new_socket(handle, domain, flags);
if (flags & UV_HANDLE_BOUND) {
if (!(flags & UV_HANDLE_BOUND))
goto out;
if (handle->flags & UV_HANDLE_BOUND) {
/* It is already bound to a port. */
handle->flags |= flags;
return 0;
}
if (handle->flags & UV_HANDLE_BOUND)
goto out; /* Already bound to a port. */
/* Query to see if tcp socket is bound. */
slen = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
return UV__ERR(errno);
err = maybe_bind_socket(sockfd);
if (err)
return err;
if ((saddr.ss_family == AF_INET6 &&
((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
(saddr.ss_family == AF_INET &&
((struct sockaddr_in*) &saddr)->sin_port != 0)) {
/* Handle is already bound to a port. */
handle->flags |= flags;
return 0;
}
out:
/* Bind to arbitrary port */
if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
return UV__ERR(errno);
}
handle->flags |= flags;
return 0;
}
return new_socket(handle, domain, flags);
handle->flags |= flags;
return 0;
}
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
int domain;
int err;
/* Use the lower 8 bits for the domain */
domain = flags & 0xFF;
@@ -129,9 +122,12 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
*/
if (domain != AF_UNSPEC) {
int err = maybe_new_socket(tcp, domain, 0);
err = new_socket(tcp, domain, 0);
if (err) {
QUEUE_REMOVE(&tcp->handle_queue);
uv__queue_remove(&tcp->handle_queue);
if (tcp->io_watcher.fd != -1)
uv__close(tcp->io_watcher.fd);
tcp->io_watcher.fd = -1;
return err;
}
}
@@ -256,7 +252,7 @@ out:
uv__req_init(handle->loop, req, UV_CONNECT);
req->cb = cb;
req->handle = (uv_stream_t*) handle;
QUEUE_INIT(&req->queue);
uv__queue_init(&req->queue);
handle->connect_req = req;
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
@@ -317,7 +313,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
struct linger l = { 1, 0 };
/* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
if (handle->flags & UV_HANDLE_SHUTTING)
if (uv__is_stream_shutting(handle))
return UV_EINVAL;
fd = uv__stream_fd(handle);
@@ -338,24 +334,12 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
static int single_accept_cached = -1;
unsigned long flags;
int single_accept;
unsigned int flags;
int err;
if (tcp->delayed_error)
return tcp->delayed_error;
single_accept = uv__load_relaxed(&single_accept_cached);
if (single_accept == -1) {
const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
uv__store_relaxed(&single_accept_cached, single_accept);
}
if (single_accept)
tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
flags = 0;
#if defined(__MVS__)
/* on zOS the listen call does not bind automatically
@@ -460,10 +444,6 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
if (enable)
handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
else
handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
return 0;
}

View File

@@ -41,126 +41,20 @@
#include <gnu/libc-version.h> /* gnu_get_libc_version() */
#endif
#if defined(__linux__)
# include <sched.h>
# define uv__cpu_set_t cpu_set_t
#elif defined(__FreeBSD__)
# include <sys/param.h>
# include <sys/cpuset.h>
# include <pthread_np.h>
# define uv__cpu_set_t cpuset_t
#endif
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
#if defined(PTHREAD_BARRIER_SERIAL_THREAD)
STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
#endif
/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */
#if defined(_AIX) || \
defined(__OpenBSD__) || \
!defined(PTHREAD_BARRIER_SERIAL_THREAD)
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
struct _uv_barrier* b;
int rc;
if (barrier == NULL || count == 0)
return UV_EINVAL;
b = (_uv_barrier*)uv__malloc(sizeof(*b));
if (b == NULL)
return UV_ENOMEM;
b->in = 0;
b->out = 0;
b->threshold = count;
rc = uv_mutex_init(&b->mutex);
if (rc != 0)
goto error2;
rc = uv_cond_init(&b->cond);
if (rc != 0)
goto error;
barrier->b = b;
return 0;
error:
uv_mutex_destroy(&b->mutex);
error2:
uv__free(b);
return rc;
}
int uv_barrier_wait(uv_barrier_t* barrier) {
struct _uv_barrier* b;
int last;
if (barrier == NULL || barrier->b == NULL)
return UV_EINVAL;
b = barrier->b;
/* Lock the mutex*/
uv_mutex_lock(&b->mutex);
if (++b->in == b->threshold) {
b->in = 0;
b->out = b->threshold;
uv_cond_signal(&b->cond);
} else {
do
uv_cond_wait(&b->cond, &b->mutex);
while (b->in != 0);
}
last = (--b->out == 0);
uv_cond_signal(&b->cond);
uv_mutex_unlock(&b->mutex);
return last;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
struct _uv_barrier* b;
b = barrier->b;
uv_mutex_lock(&b->mutex);
assert(b->in == 0);
while (b->out != 0)
uv_cond_wait(&b->cond, &b->mutex);
if (b->in != 0)
abort();
uv_mutex_unlock(&b->mutex);
uv_mutex_destroy(&b->mutex);
uv_cond_destroy(&b->cond);
uv__free(barrier->b);
barrier->b = NULL;
}
#else
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
}
int uv_barrier_wait(uv_barrier_t* barrier) {
int rc;
rc = pthread_barrier_wait(barrier);
if (rc != 0)
if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
abort();
return rc == PTHREAD_BARRIER_SERIAL_THREAD;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
if (pthread_barrier_destroy(barrier))
abort();
}
#endif
/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
* too small to safely receive signals on.
*
@@ -276,6 +170,106 @@ int uv_thread_create_ex(uv_thread_t* tid,
return UV__ERR(err);
}
#if UV__CPU_AFFINITY_SUPPORTED
int uv_thread_setaffinity(uv_thread_t* tid,
char* cpumask,
char* oldmask,
size_t mask_size) {
int i;
int r;
uv__cpu_set_t cpuset;
int cpumasksize;
cpumasksize = uv_cpumask_size();
if (cpumasksize < 0)
return cpumasksize;
if (mask_size < (size_t)cpumasksize)
return UV_EINVAL;
if (oldmask != NULL) {
r = uv_thread_getaffinity(tid, oldmask, mask_size);
if (r < 0)
return r;
}
CPU_ZERO(&cpuset);
for (i = 0; i < cpumasksize; i++)
if (cpumask[i])
CPU_SET(i, &cpuset);
#if defined(__ANDROID__)
if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
r = errno;
else
r = 0;
#else
r = pthread_setaffinity_np(*tid, sizeof(cpuset), &cpuset);
#endif
return UV__ERR(r);
}
int uv_thread_getaffinity(uv_thread_t* tid,
char* cpumask,
size_t mask_size) {
int r;
int i;
uv__cpu_set_t cpuset;
int cpumasksize;
cpumasksize = uv_cpumask_size();
if (cpumasksize < 0)
return cpumasksize;
if (mask_size < (size_t)cpumasksize)
return UV_EINVAL;
CPU_ZERO(&cpuset);
#if defined(__ANDROID__)
if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
r = errno;
else
r = 0;
#else
r = pthread_getaffinity_np(*tid, sizeof(cpuset), &cpuset);
#endif
if (r)
return UV__ERR(r);
for (i = 0; i < cpumasksize; i++)
cpumask[i] = !!CPU_ISSET(i, &cpuset);
return 0;
}
#else
int uv_thread_setaffinity(uv_thread_t* tid,
char* cpumask,
char* oldmask,
size_t mask_size) {
return UV_ENOTSUP;
}
int uv_thread_getaffinity(uv_thread_t* tid,
char* cpumask,
size_t mask_size) {
return UV_ENOTSUP;
}
#endif /* defined(__linux__) || defined(UV_BSD_H) */
int uv_thread_getcpu(void) {
#if UV__CPU_AFFINITY_SUPPORTED
int cpu;
cpu = sched_getcpu();
if (cpu < 0)
return UV__ERR(errno);
return cpu;
#else
return UV_ENOTSUP;
#endif
}
uv_thread_t uv_thread_self(void) {
return pthread_self();
@@ -577,7 +571,7 @@ static void uv__custom_sem_post(uv_sem_t* sem_) {
uv_mutex_lock(&sem->mutex);
sem->value++;
if (sem->value == 1)
uv_cond_signal(&sem->cond);
uv_cond_signal(&sem->cond); /* Release one to replace us. */
uv_mutex_unlock(&sem->mutex);
}

View File

@@ -21,7 +21,6 @@
#include "uv.h"
#include "internal.h"
#include "spinlock.h"
#include <stdlib.h>
#include <assert.h>
@@ -30,6 +29,8 @@
#include <errno.h>
#include <sys/ioctl.h>
#include <atomic>
#if defined(__MVS__) && !defined(IMAXBEL)
#define IMAXBEL 0
#endif
@@ -64,7 +65,7 @@ static int isreallyatty(int file) {
static int orig_termios_fd = -1;
static struct termios orig_termios;
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
static std::atomic<int> termios_spinlock;
int uv__tcsetattr(int fd, int how, const struct termios *term) {
int rc;
@@ -81,7 +82,7 @@ int uv__tcsetattr(int fd, int how, const struct termios *term) {
static int uv__tty_is_peripheral(const int fd) {
int result;
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#if defined(__linux__) || defined(__FreeBSD__)
int dummy;
result = ioctl(fd, TIOCGPTN, &dummy) != 0;
@@ -114,7 +115,7 @@ static int uv__tty_is_peripheral(const int fd) {
}
/* Lookup stat structure behind the file descriptor. */
if (fstat(fd, &sb) != 0)
if (uv__fstat(fd, &sb) != 0)
abort();
/* Assert character device. */
@@ -223,7 +224,7 @@ skip:
int rc = r;
if (newfd != -1)
uv__close(newfd);
QUEUE_REMOVE(&tty->handle_queue);
uv__queue_remove(&tty->handle_queue);
do
r = fcntl(fd, F_SETFL, saved_flags);
while (r == -1 && errno == EINTR);
@@ -281,6 +282,7 @@ static void uv__tty_make_raw(struct termios* tio) {
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
struct termios tmp;
int expected;
int fd;
int rc;
@@ -297,12 +299,16 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
return UV__ERR(errno);
/* This is used for uv_tty_reset_mode() */
uv_spinlock_lock(&termios_spinlock);
do
expected = 0;
while (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1));
if (orig_termios_fd == -1) {
orig_termios = tty->orig_termios;
orig_termios_fd = fd;
}
uv_spinlock_unlock(&termios_spinlock);
atomic_store(&termios_spinlock, 0);
}
tmp = tty->orig_termios;
@@ -361,7 +367,7 @@ uv_handle_type uv_guess_handle(uv_file file) {
if (isatty(file))
return UV_TTY;
if (fstat(file, &s)) {
if (uv__fstat(file, &s)) {
#if defined(__PASE__)
/* On ibmi receiving RST from TCP instead of FIN immediately puts fd into
* an error state. fstat will return EINVAL, getsockname will also return
@@ -446,14 +452,15 @@ int uv_tty_reset_mode(void) {
int err;
saved_errno = errno;
if (!uv_spinlock_trylock(&termios_spinlock))
if (atomic_exchange(&termios_spinlock, 1))
return UV_EBUSY; /* In uv_tty_set_mode(). */
err = 0;
if (orig_termios_fd != -1)
err = uv__tcsetattr(orig_termios_fd, TCSANOW, &orig_termios);
uv_spinlock_unlock(&termios_spinlock);
atomic_store(&termios_spinlock, 0);
errno = saved_errno;
return err;

View File

@@ -40,12 +40,6 @@
# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
#endif
union uv__sockaddr {
struct sockaddr_in6 in6;
struct sockaddr_in in;
struct sockaddr addr;
};
static void uv__udp_run_completed(uv_udp_t* handle);
static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
static void uv__udp_recvmsg(uv_udp_t* handle);
@@ -54,36 +48,6 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
int domain,
unsigned int flags);
#if HAVE_MMSG
#define UV__MMSG_MAXWIDTH 20
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf);
static void uv__udp_sendmmsg(uv_udp_t* handle);
static int uv__recvmmsg_avail;
static int uv__sendmmsg_avail;
static uv_once_t once = UV_ONCE_INIT;
static void uv__udp_mmsg_init(void) {
int ret;
int s;
s = uv__socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
return;
ret = uv__sendmmsg(s, NULL, 0);
if (ret == 0 || errno != ENOSYS) {
uv__sendmmsg_avail = 1;
uv__recvmmsg_avail = 1;
} else {
ret = uv__recvmmsg(s, NULL, 0);
if (ret == 0 || errno != ENOSYS)
uv__recvmmsg_avail = 1;
}
uv__close(s);
}
#endif
void uv__udp_close(uv_udp_t* handle) {
uv__io_close(handle->loop, &handle->io_watcher);
@@ -98,18 +62,18 @@ void uv__udp_close(uv_udp_t* handle) {
void uv__udp_finish_close(uv_udp_t* handle) {
uv_udp_send_t* req;
QUEUE* q;
struct uv__queue* q;
assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
assert(handle->io_watcher.fd == -1);
while (!QUEUE_EMPTY(&handle->write_queue)) {
q = QUEUE_HEAD(&handle->write_queue);
QUEUE_REMOVE(q);
while (!uv__queue_empty(&handle->write_queue)) {
q = uv__queue_head(&handle->write_queue);
uv__queue_remove(q);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
req = uv__queue_data(q, uv_udp_send_t, queue);
req->status = UV_ECANCELED;
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
}
uv__udp_run_completed(handle);
@@ -126,16 +90,16 @@ void uv__udp_finish_close(uv_udp_t* handle) {
static void uv__udp_run_completed(uv_udp_t* handle) {
uv_udp_send_t* req;
QUEUE* q;
struct uv__queue* q;
assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING));
handle->flags |= UV_HANDLE_UDP_PROCESSING;
while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
q = QUEUE_HEAD(&handle->write_completed_queue);
QUEUE_REMOVE(q);
while (!uv__queue_empty(&handle->write_completed_queue)) {
q = uv__queue_head(&handle->write_completed_queue);
uv__queue_remove(q);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
req = uv__queue_data(q, uv_udp_send_t, queue);
uv__req_unregister(handle->loop, req);
handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
@@ -157,7 +121,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
req->send_cb(req, req->status);
}
if (QUEUE_EMPTY(&handle->write_queue)) {
if (uv__queue_empty(&handle->write_queue)) {
/* Pending queue and completion queue empty, stop watcher. */
uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT);
if (!uv__io_active(&handle->io_watcher, POLLIN))
@@ -183,11 +147,11 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
}
}
#if HAVE_MMSG
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
struct sockaddr_in6 peers[UV__MMSG_MAXWIDTH];
struct iovec iov[UV__MMSG_MAXWIDTH];
struct uv__mmsghdr msgs[UV__MMSG_MAXWIDTH];
#if defined(__linux__) || defined(__FreeBSD__)
struct sockaddr_in6 peers[20];
struct iovec iov[ARRAY_SIZE(peers)];
struct mmsghdr msgs[ARRAY_SIZE(peers)];
ssize_t nread;
uv_buf_t chunk_buf;
size_t chunks;
@@ -212,7 +176,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
}
do
nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks);
nread = recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL);
while (nread == -1 && errno == EINTR);
if (nread < 1) {
@@ -240,8 +204,10 @@ 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__ */
return UV_ENOSYS;
#endif /* __linux__ || ____FreeBSD__ */
}
#endif
static void uv__udp_recvmsg(uv_udp_t* handle) {
struct sockaddr_storage peer;
@@ -268,14 +234,12 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
}
assert(buf.base != NULL);
#if HAVE_MMSG
if (uv_udp_using_recvmmsg(handle)) {
nread = uv__udp_recvmmsg(handle, &buf);
if (nread > 0)
count -= nread;
continue;
}
#endif
memset(&h, 0, sizeof(h));
memset(&peer, 0, sizeof(peer));
@@ -311,25 +275,25 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
&& handle->recv_cb != NULL);
}
#if HAVE_MMSG
static void uv__udp_sendmmsg(uv_udp_t* handle) {
static void uv__udp_sendmsg(uv_udp_t* handle) {
#if defined(__linux__) || defined(__FreeBSD__)
uv_udp_send_t* req;
struct uv__mmsghdr h[UV__MMSG_MAXWIDTH];
struct uv__mmsghdr *p;
QUEUE* q;
struct mmsghdr h[20];
struct mmsghdr* p;
struct uv__queue* q;
ssize_t npkts;
size_t pkts;
size_t i;
if (QUEUE_EMPTY(&handle->write_queue))
if (uv__queue_empty(&handle->write_queue))
return;
write_queue_drain:
for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue);
pkts < UV__MMSG_MAXWIDTH && q != &handle->write_queue;
++pkts, q = QUEUE_HEAD(q)) {
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 = QUEUE_DATA(q, uv_udp_send_t, queue);
req = uv__queue_data(q, uv_udp_send_t, queue);
assert(req != NULL);
p = &h[pkts];
@@ -355,22 +319,22 @@ write_queue_drain:
}
do
npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts);
npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0);
while (npkts == -1 && errno == EINTR);
if (npkts < 1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
return;
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
for (i = 0, q = uv__queue_head(&handle->write_queue);
i < pkts && q != &handle->write_queue;
++i, q = QUEUE_HEAD(&handle->write_queue)) {
++i, q = uv__queue_head(&handle->write_queue)) {
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
req = uv__queue_data(q, uv_udp_send_t, queue);
assert(req != NULL);
req->status = UV__ERR(errno);
QUEUE_REMOVE(&req->queue);
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
uv__queue_remove(&req->queue);
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
}
uv__io_feed(handle->loop, &handle->io_watcher);
return;
@@ -379,11 +343,11 @@ write_queue_drain:
/* Safety: npkts known to be >0 below. Hence cast from ssize_t
* to size_t safe.
*/
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
for (i = 0, q = uv__queue_head(&handle->write_queue);
i < (size_t)npkts && q != &handle->write_queue;
++i, q = QUEUE_HEAD(&handle->write_queue)) {
++i, q = uv__queue_head(&handle->write_queue)) {
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
req = uv__queue_data(q, uv_udp_send_t, queue);
assert(req != NULL);
req->status = req->bufs[0].len;
@@ -393,37 +357,25 @@ write_queue_drain:
* why we don't handle partial writes. Just pop the request
* off the write queue and onto the completed queue, done.
*/
QUEUE_REMOVE(&req->queue);
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
uv__queue_remove(&req->queue);
uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
}
/* couldn't batch everything, continue sending (jump to avoid stack growth) */
if (!QUEUE_EMPTY(&handle->write_queue))
if (!uv__queue_empty(&handle->write_queue))
goto write_queue_drain;
uv__io_feed(handle->loop, &handle->io_watcher);
return;
}
#endif
static void uv__udp_sendmsg(uv_udp_t* handle) {
#else /* __linux__ || ____FreeBSD__ */
uv_udp_send_t* req;
struct msghdr h;
QUEUE* q;
struct uv__queue* q;
ssize_t size;
#if HAVE_MMSG
uv_once(&once, uv__udp_mmsg_init);
if (uv__sendmmsg_avail) {
uv__udp_sendmmsg(handle);
return;
}
#endif
while (!QUEUE_EMPTY(&handle->write_queue)) {
q = QUEUE_HEAD(&handle->write_queue);
while (!uv__queue_empty(&handle->write_queue)) {
q = uv__queue_head(&handle->write_queue);
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
req = uv__queue_data(q, uv_udp_send_t, queue);
assert(req != NULL);
memset(&h, 0, sizeof h);
@@ -462,10 +414,11 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
* why we don't handle partial writes. Just pop the request
* off the write queue and onto the completed queue, done.
*/
QUEUE_REMOVE(&req->queue);
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
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__ */
}
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
@@ -495,7 +448,8 @@ static int uv__set_reuse(int fd) {
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
return UV__ERR(errno);
}
#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__)
#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \
!defined(__sun__)
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
return UV__ERR(errno);
#else
@@ -775,7 +729,7 @@ int uv__udp_send(uv_udp_send_t* req,
memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
handle->send_queue_count++;
QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
uv__queue_insert_tail(&handle->write_queue, &req->queue);
uv__handle_start(handle);
if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) {
@@ -785,7 +739,7 @@ int uv__udp_send(uv_udp_send_t* req,
* away. In such cases the `io_watcher` has to be queued for asynchronous
* write.
*/
if (!QUEUE_EMPTY(&handle->write_queue))
if (!uv__queue_empty(&handle->write_queue))
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
} else {
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
@@ -1053,19 +1007,17 @@ int uv__udp_init_ex(uv_loop_t* loop,
handle->send_queue_size = 0;
handle->send_queue_count = 0;
uv__io_init(&handle->io_watcher, uv__udp_io, fd);
QUEUE_INIT(&handle->write_queue);
QUEUE_INIT(&handle->write_completed_queue);
uv__queue_init(&handle->write_queue);
uv__queue_init(&handle->write_completed_queue);
return 0;
}
int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
#if HAVE_MMSG
if (handle->flags & UV_HANDLE_UDP_RECVMMSG) {
uv_once(&once, uv__udp_mmsg_init);
return uv__recvmmsg_avail;
}
#if defined(__linux__) || defined(__FreeBSD__)
if (handle->flags & UV_HANDLE_UDP_RECVMMSG)
return 1;
#endif
return 0;
}

View File

@@ -128,6 +128,39 @@ int uv_replace_allocator(uv_malloc_func malloc_func,
return 0;
}
void uv_os_free_passwd(uv_passwd_t* pwd) {
if (pwd == NULL)
return;
/* On unix, the memory for name, shell, and homedir are allocated in a single
* uv__malloc() call. The base of the pointer is stored in pwd->username, so
* that is the field that needs to be freed.
*/
uv__free(pwd->username);
#ifdef _WIN32
uv__free(pwd->homedir);
#endif
pwd->username = NULL;
pwd->shell = NULL;
pwd->homedir = NULL;
}
void uv_os_free_group(uv_group_t *grp) {
if (grp == NULL)
return;
/* The memory for is allocated in a single uv__malloc() call. The base of the
* pointer is stored in grp->members, so that is the only field that needs to
* be freed.
*/
uv__free(grp->members);
grp->members = NULL;
grp->groupname = NULL;
}
#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
size_t uv_handle_size(uv_handle_type type) {
@@ -500,17 +533,17 @@ int uv_udp_recv_stop(uv_udp_t* handle) {
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
QUEUE queue;
QUEUE* q;
struct uv__queue queue;
struct uv__queue* q;
uv_handle_t* h;
QUEUE_MOVE(&loop->handle_queue, &queue);
while (!QUEUE_EMPTY(&queue)) {
q = QUEUE_HEAD(&queue);
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
uv__queue_move(&loop->handle_queue, &queue);
while (!uv__queue_empty(&queue)) {
q = uv__queue_head(&queue);
h = uv__queue_data(q, uv_handle_t, handle_queue);
QUEUE_REMOVE(q);
QUEUE_INSERT_TAIL(&loop->handle_queue, q);
uv__queue_remove(q);
uv__queue_insert_tail(&loop->handle_queue, q);
if (h->flags & UV_HANDLE_INTERNAL) continue;
walk_cb(h, arg);
@@ -520,14 +553,14 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
const char* type;
QUEUE* q;
struct uv__queue* q;
uv_handle_t* h;
if (loop == NULL)
loop = uv_default_loop();
QUEUE_FOREACH(q, &loop->handle_queue) {
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
uv__queue_foreach(q, &loop->handle_queue) {
h = uv__queue_data(q, uv_handle_t, handle_queue);
if (only_active && !uv__is_active(h))
continue;
@@ -650,14 +683,22 @@ static unsigned int* uv__get_nbufs(uv_fs_t* req) {
void uv__fs_scandir_cleanup(uv_fs_t* req) {
uv__dirent_t** dents;
unsigned int* nbufs;
unsigned int i;
unsigned int n;
unsigned int* nbufs = uv__get_nbufs(req);
if (req->result >= 0) {
dents = (uv__dirent_t**)(req->ptr);
nbufs = uv__get_nbufs(req);
dents = (uv__dirent_t**)(req->ptr);
if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
(*nbufs)--;
for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
uv__fs_scandir_free(dents[*nbufs]);
i = 0;
if (*nbufs > 0)
i = *nbufs - 1;
n = (unsigned int) req->result;
for (; i < n; i++)
uv__fs_scandir_free(dents[i]);
}
uv__fs_scandir_free(req->ptr);
req->ptr = NULL;
@@ -814,7 +855,7 @@ uv_loop_t* uv_loop_new(void) {
int uv_loop_close(uv_loop_t* loop) {
QUEUE* q;
struct uv__queue* q;
uv_handle_t* h;
#ifndef NDEBUG
void* saved_data;
@@ -823,8 +864,8 @@ int uv_loop_close(uv_loop_t* loop) {
if (uv__has_active_reqs(loop))
return UV_EBUSY;
QUEUE_FOREACH(q, &loop->handle_queue) {
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
uv__queue_foreach(q, &loop->handle_queue) {
h = uv__queue_data(q, uv_handle_t, handle_queue);
if (!(h->flags & UV_HANDLE_INTERNAL))
return UV_EBUSY;
}
@@ -888,12 +929,17 @@ void uv_os_free_environ(uv_env_item_t* envitems, int count) {
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
#ifdef __linux__
(void) &count;
uv__free(cpu_infos);
#else
int i;
for (i = 0; i < count; i++)
uv__free(cpu_infos[i].model);
uv__free(cpu_infos);
#endif /* __linux__ */
}
@@ -905,9 +951,9 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
__attribute__((destructor))
#endif
void uv_library_shutdown(void) {
static int was_shutdown;
static std::atomic<int> was_shutdown;
if (uv__load_relaxed(&was_shutdown))
if (uv__exchange_int_relaxed(&was_shutdown, 1))
return;
uv__process_title_cleanup();
@@ -918,7 +964,6 @@ void uv_library_shutdown(void) {
#else
uv__threadpool_cleanup();
#endif
uv__store_relaxed(&was_shutdown, 1);
}
@@ -964,6 +1009,15 @@ void uv__metrics_set_provider_entry_time(uv_loop_t* loop) {
}
int uv_metrics_info(uv_loop_t* loop, uv_metrics_t* metrics) {
memcpy(metrics,
&uv__get_loop_metrics(loop)->metrics,
sizeof(*metrics));
return 0;
}
uint64_t uv_metrics_idle_time(uv_loop_t* loop) {
uv__loop_metrics_t* loop_metrics;
uint64_t entry_time;

View File

@@ -30,12 +30,9 @@
#include <assert.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
# include "uv/stdint-msvc2008.h"
#else
# include <stdint.h>
#endif
#include <atomic>
#include "uv.h"
#include "uv/tree.h"
@@ -53,19 +50,25 @@ extern int snprintf(char*, size_t, const char*, ...);
#endif
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define ARRAY_END(a) ((a) + ARRAY_SIZE(a))
#define container_of(ptr, type, member) \
((type *) ((char *) (ptr) - offsetof(type, member)))
/* C11 defines static_assert to be a macro which calls _Static_assert. */
#if defined(static_assert)
#define STATIC_ASSERT(expr) static_assert(expr, #expr)
#else
#define STATIC_ASSERT(expr) \
void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
#endif
#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 7)
#define uv__load_relaxed(p) __atomic_load_n(p, __ATOMIC_RELAXED)
#define uv__store_relaxed(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED)
#ifdef _MSC_VER
#define uv__exchange_int_relaxed(p, v) \
InterlockedExchangeNoFence((LONG volatile*)(p), v)
#else
#define uv__load_relaxed(p) (*p)
#define uv__store_relaxed(p, v) do *p = v; while (0)
#define uv__exchange_int_relaxed(p, v) \
std::atomic_exchange_explicit((std::atomic<int>*)(p), v, std::memory_order_relaxed)
#endif
#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)
@@ -83,7 +86,6 @@ enum {
/* Used by streams. */
UV_HANDLE_LISTENING = 0x00000040,
UV_HANDLE_CONNECTION = 0x00000080,
UV_HANDLE_SHUTTING = 0x00000100,
UV_HANDLE_SHUT = 0x00000200,
UV_HANDLE_READ_PARTIAL = 0x00000400,
UV_HANDLE_READ_EOF = 0x00000800,
@@ -263,6 +265,14 @@ void uv__threadpool_cleanup(void);
#define uv__is_closing(h) \
(((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0)
#if defined(_WIN32)
# define uv__is_stream_shutting(h) \
(h->stream.conn.shutdown_req != NULL)
#else
# define uv__is_stream_shutting(h) \
(h->shutdown_req != NULL)
#endif
#define uv__handle_start(h) \
do { \
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \
@@ -311,7 +321,7 @@ void uv__threadpool_cleanup(void);
(h)->loop = (loop_); \
(h)->type = (type_); \
(h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \
QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
uv__queue_insert_tail(&(loop_)->handle_queue, &(h)->handle_queue); \
uv__handle_platform_init(h); \
} \
while (0)
@@ -347,6 +357,21 @@ void uv__threadpool_cleanup(void);
#define uv__get_loop_metrics(loop) \
(&uv__get_internal_fields(loop)->loop_metrics)
#define uv__metrics_inc_loop_count(loop) \
do { \
uv__get_loop_metrics(loop)->metrics.loop_count++; \
} while (0)
#define uv__metrics_inc_events(loop, e) \
do { \
uv__get_loop_metrics(loop)->metrics.events += (e); \
} while (0)
#define uv__metrics_inc_events_waiting(loop, e) \
do { \
uv__get_loop_metrics(loop)->metrics.events_waiting += (e); \
} while (0)
/* Allocator prototypes */
void *uv__calloc(size_t count, size_t size);
char *uv__strdup(const char* s);
@@ -360,6 +385,7 @@ typedef struct uv__loop_metrics_s uv__loop_metrics_t;
typedef struct uv__loop_internal_fields_s uv__loop_internal_fields_t;
struct uv__loop_metrics_s {
uv_metrics_t metrics;
uint64_t provider_entry_time;
uint64_t provider_idle_time;
uv_mutex_t lock;
@@ -368,9 +394,38 @@ struct uv__loop_metrics_s {
void uv__metrics_update_idle_time(uv_loop_t* loop);
void uv__metrics_set_provider_entry_time(uv_loop_t* loop);
#ifdef __linux__
struct uv__iou {
uint32_t* sqhead;
uint32_t* sqtail;
uint32_t* sqarray;
uint32_t sqmask;
uint32_t* sqflags;
uint32_t* cqhead;
uint32_t* cqtail;
uint32_t cqmask;
void* sq; /* pointer to munmap() on event loop teardown */
void* cqe; /* pointer to array of struct uv__io_uring_cqe */
void* sqe; /* pointer to array of struct uv__io_uring_sqe */
size_t sqlen;
size_t cqlen;
size_t maxlen;
size_t sqelen;
int ringfd;
uint32_t in_flight;
uint32_t flags;
};
#endif /* __linux__ */
struct uv__loop_internal_fields_s {
unsigned int flags;
uv__loop_metrics_t loop_metrics;
int current_timeout;
#ifdef __linux__
struct uv__iou ctl;
struct uv__iou iou;
void* inv; /* used by uv__platform_invalidate_fd() */
#endif /* __linux__ */
};
#endif /* UV_COMMON_H_ */

View File

@@ -247,6 +247,9 @@ int uv_loop_init(uv_loop_t* loop) {
err = uv_mutex_init(&lfields->loop_metrics.lock);
if (err)
goto fail_metrics_mutex_init;
memset(&lfields->loop_metrics.metrics,
0,
sizeof(lfields->loop_metrics.metrics));
/* To prevent uninitialized memory access, loop->time must be initialized
* to zero before calling uv_update_time for the first time.
@@ -254,8 +257,8 @@ int uv_loop_init(uv_loop_t* loop) {
loop->time = 0;
uv_update_time(loop);
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->handle_queue);
uv__queue_init(&loop->wq);
uv__queue_init(&loop->handle_queue);
loop->active_reqs.count = 0;
loop->active_handles = 0;
@@ -281,9 +284,6 @@ int uv_loop_init(uv_loop_t* loop) {
memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
loop->active_tcp_streams = 0;
loop->active_udp_streams = 0;
loop->timer_counter = 0;
loop->stop_flag = 0;
@@ -360,7 +360,7 @@ void uv__loop_close(uv_loop_t* loop) {
}
uv_mutex_lock(&loop->wq_mutex);
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
assert(uv__queue_empty(&loop->wq) && "thread pool work queue not empty!");
assert(!uv__has_active_reqs(loop));
uv_mutex_unlock(&loop->wq_mutex);
uv_mutex_destroy(&loop->wq_mutex);
@@ -426,6 +426,7 @@ int uv_backend_timeout(const uv_loop_t* loop) {
static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
uv__loop_internal_fields_t* lfields;
DWORD bytes;
ULONG_PTR key;
OVERLAPPED* overlapped;
@@ -435,9 +436,10 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
uint64_t user_timeout;
int reset_timeout;
lfields = uv__get_internal_fields(loop);
timeout_time = loop->time + timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
if (lfields->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
@@ -452,6 +454,12 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
/* Store the current timeout in a location that's globally accessible so
* other locations like uv__work_done() can determine whether the queue
* of events in the callback were waiting when poll was called.
*/
lfields->current_timeout = timeout;
GetQueuedCompletionStatus(loop->iocp,
&bytes,
&key,
@@ -459,6 +467,8 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
timeout);
if (reset_timeout != 0) {
if (overlapped && timeout == 0)
uv__metrics_inc_events_waiting(loop, 1);
timeout = user_timeout;
reset_timeout = 0;
}
@@ -471,6 +481,8 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
uv__metrics_update_idle_time(loop);
if (overlapped) {
uv__metrics_inc_events(loop, 1);
/* Package was dequeued */
req = uv__overlapped_to_req(overlapped);
uv__insert_pending_req(loop, req);
@@ -505,6 +517,7 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
static void uv__poll(uv_loop_t* loop, DWORD timeout) {
uv__loop_internal_fields_t* lfields;
BOOL success;
uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[128];
@@ -513,11 +526,13 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
int repeat;
uint64_t timeout_time;
uint64_t user_timeout;
uint64_t actual_timeout;
int reset_timeout;
lfields = uv__get_internal_fields(loop);
timeout_time = loop->time + timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
if (lfields->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
@@ -526,12 +541,20 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
}
for (repeat = 0; ; repeat++) {
actual_timeout = timeout;
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
/* Store the current timeout in a location that's globally accessible so
* other locations like uv__work_done() can determine whether the queue
* of events in the callback were waiting when poll was called.
*/
lfields->current_timeout = timeout;
success = pGetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
@@ -545,9 +568,9 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
}
/* Placed here because on success the loop will break whether there is an
* empty package or not, or if GetQueuedCompletionStatus returned early then
* the timeout will be updated and the loop will run again. In either case
* the idle time will need to be updated.
* empty package or not, or if pGetQueuedCompletionStatusEx returned early
* then the timeout will be updated and the loop will run again. In either
* case the idle time will need to be updated.
*/
uv__metrics_update_idle_time(loop);
@@ -557,6 +580,10 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
* meant only to wake us up.
*/
if (overlappeds[i].lpOverlapped) {
uv__metrics_inc_events(loop, 1);
if (actual_timeout == 0)
uv__metrics_inc_events_waiting(loop, 1);
req = uv__overlapped_to_req(overlappeds[i].lpOverlapped);
uv__insert_pending_req(loop, req);
}
@@ -600,10 +627,16 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
if (!r)
uv_update_time(loop);
while (r != 0 && loop->stop_flag == 0) {
/* Maintain backwards compatibility by processing timers before entering the
* while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed
* once, which should be done after polling in order to maintain proper
* execution order of the conceptual event loop. */
if (mode == UV_RUN_DEFAULT && r != 0 && loop->stop_flag == 0) {
uv_update_time(loop);
uv__run_timers(loop);
}
while (r != 0 && loop->stop_flag == 0) {
can_sleep = loop->pending_reqs_tail == NULL && loop->idle_handles == NULL;
uv__process_reqs(loop);
@@ -614,6 +647,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
uv__metrics_inc_loop_count(loop);
if (pGetQueuedCompletionStatusEx)
uv__poll(loop, timeout);
else
@@ -634,18 +669,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
uv__check_invoke(loop);
uv__process_endgames(loop);
if (mode == UV_RUN_ONCE) {
/* UV_RUN_ONCE implies forward progress: at least one callback must have
* been invoked when it returns. uv__io_poll() can return without doing
* I/O (meaning: no callbacks) when its timeout expires - which means we
* have pending timers that satisfy the forward progress constraint.
*
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
* the check.
*/
uv_update_time(loop);
uv__run_timers(loop);
}
uv_update_time(loop);
uv__run_timers(loop);
r = uv__loop_alive(loop);
if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)

View File

@@ -38,6 +38,8 @@
#include "handle-inl.h"
#include "fs-fd-hash-inl.h"
#include <winioctl.h>
#pragma comment(lib, "Advapi32.lib")
#define UV_FS_FREE_PATHS 0x0002
@@ -145,26 +147,97 @@ void uv__fs_init(void) {
}
static int32_t fs__decode_wtf8_char(const char** input) {
uint32_t code_point;
uint8_t b1;
uint8_t b2;
uint8_t b3;
uint8_t b4;
b1 = **input;
if (b1 <= 0x7F)
return b1; /* ASCII code point */
if (b1 < 0xC2)
return -1; /* invalid: continuation byte */
code_point = b1;
b2 = *++*input;
if ((b2 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b2 & 0x3F);
if (b1 <= 0xDF)
return 0x7FF & code_point; /* two-byte character */
b3 = *++*input;
if ((b3 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b3 & 0x3F);
if (b1 <= 0xEF)
return 0xFFFF & code_point; /* three-byte character */
b4 = *++*input;
if ((b4 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b4 & 0x3F);
if (b1 <= 0xF4)
if (code_point <= 0x10FFFF)
return code_point; /* four-byte character */
/* code point too large */
return -1;
}
static ssize_t fs__get_length_wtf8(const char* source_ptr) {
size_t w_target_len = 0;
int32_t code_point;
do {
code_point = fs__decode_wtf8_char(&source_ptr);
if (code_point < 0)
return -1;
if (code_point > 0xFFFF)
w_target_len++;
w_target_len++;
} while (*source_ptr++);
return w_target_len;
}
static void fs__wtf8_to_wide(const char* source_ptr, WCHAR* w_target) {
int32_t code_point;
do {
code_point = fs__decode_wtf8_char(&source_ptr);
/* fs__get_length_wtf8 should have been called and checked first. */
assert(code_point >= 0);
if (code_point > 0x10000) {
assert(code_point < 0x10FFFF);
*w_target++ = (((code_point - 0x10000) >> 10) + 0xD800);
*w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00;
} else {
*w_target++ = code_point;
}
} while (*source_ptr++);
}
INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
const char* new_path, const int copy_path) {
char* buf;
char* pos;
ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
WCHAR* buf;
WCHAR* pos;
size_t buf_sz = 0;
size_t path_len = 0;
ssize_t pathw_len = 0;
ssize_t new_pathw_len = 0;
/* new_path can only be set if path is also set. */
assert(new_path == NULL || path != NULL);
if (path != NULL) {
pathw_len = MultiByteToWideChar(CP_UTF8,
0,
path,
-1,
NULL,
0);
if (pathw_len == 0) {
return GetLastError();
}
pathw_len = fs__get_length_wtf8(path);
if (pathw_len < 0)
return ERROR_INVALID_NAME;
buf_sz += pathw_len * sizeof(WCHAR);
}
@@ -174,16 +247,9 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
}
if (new_path != NULL) {
new_pathw_len = MultiByteToWideChar(CP_UTF8,
0,
new_path,
-1,
NULL,
0);
if (new_pathw_len == 0) {
return GetLastError();
}
new_pathw_len = fs__get_length_wtf8(new_path);
if (new_pathw_len < 0)
return ERROR_INVALID_NAME;
buf_sz += new_pathw_len * sizeof(WCHAR);
}
@@ -195,7 +261,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
return 0;
}
buf = (char*) uv__malloc(buf_sz);
buf = (WCHAR *)uv__malloc(buf_sz);
if (buf == NULL) {
return ERROR_OUTOFMEMORY;
}
@@ -203,29 +269,17 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
pos = buf;
if (path != NULL) {
DWORD r = MultiByteToWideChar(CP_UTF8,
0,
path,
-1,
(WCHAR*) pos,
pathw_len);
assert(r == (DWORD) pathw_len);
req->file.pathw = (WCHAR*) pos;
pos += r * sizeof(WCHAR);
fs__wtf8_to_wide(path, pos);
req->file.pathw = pos;
pos += pathw_len;
} else {
req->file.pathw = NULL;
}
if (new_path != NULL) {
DWORD r = MultiByteToWideChar(CP_UTF8,
0,
new_path,
-1,
(WCHAR*) pos,
new_pathw_len);
assert(r == (DWORD) new_pathw_len);
req->fs.info.new_pathw = (WCHAR*) pos;
pos += r * sizeof(WCHAR);
fs__wtf8_to_wide(new_path, pos);
req->fs.info.new_pathw = pos;
pos += new_pathw_len;
} else {
req->fs.info.new_pathw = NULL;
}
@@ -233,8 +287,8 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
req->path = path;
if (path != NULL && copy_path) {
memcpy(pos, path, path_len);
assert(path_len == buf_sz - (pos - buf));
req->path = pos;
assert(path_len == buf_sz - (pos - buf) * sizeof(WCHAR));
req->path = (char*) pos;
}
req->flags |= UV_FS_FREE_PATHS;
@@ -260,57 +314,115 @@ INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req,
}
static int fs__wide_to_utf8(WCHAR* w_source_ptr,
DWORD w_source_len,
char** target_ptr,
uint64_t* target_len_ptr) {
int r;
int target_len;
static int32_t fs__get_surrogate_value(const WCHAR* w_source_ptr,
size_t w_source_len) {
WCHAR u;
WCHAR next;
u = w_source_ptr[0];
if (u >= 0xD800 && u <= 0xDBFF && w_source_len > 1) {
next = w_source_ptr[1];
if (next >= 0xDC00 && next <= 0xDFFF)
return 0x10000 + ((u - 0xD800) << 10) + (next - 0xDC00);
}
return u;
}
static size_t fs__get_length_wide(const WCHAR* w_source_ptr,
size_t w_source_len) {
size_t target_len;
int32_t code_point;
target_len = 0;
for (; w_source_len; w_source_len--, w_source_ptr++) {
code_point = fs__get_surrogate_value(w_source_ptr, w_source_len);
/* Can be invalid UTF-8 but must be valid WTF-8. */
assert(code_point >= 0);
if (code_point < 0x80)
target_len += 1;
else if (code_point < 0x800)
target_len += 2;
else if (code_point < 0x10000)
target_len += 3;
else {
target_len += 4;
w_source_ptr++;
w_source_len--;
}
}
return target_len;
}
static int fs__wide_to_wtf8(WCHAR* w_source_ptr,
size_t w_source_len,
char** target_ptr,
size_t* target_len_ptr) {
size_t target_len;
char* target;
target_len = WideCharToMultiByte(CP_UTF8,
0,
w_source_ptr,
w_source_len,
NULL,
0,
NULL,
NULL);
int32_t code_point;
if (target_len == 0) {
return -1;
/* If *target_ptr is provided, then *target_len_ptr must be its length
* (excluding space for null), otherwise we will compute the target_len_ptr
* length and may return a new allocation in *target_ptr if target_ptr is
* provided. */
if (target_ptr == NULL || *target_ptr == NULL) {
target_len = fs__get_length_wide(w_source_ptr, w_source_len);
if (target_len_ptr != NULL)
*target_len_ptr = target_len;
} else {
target_len = *target_len_ptr;
}
if (target_len_ptr != NULL) {
*target_len_ptr = target_len;
}
if (target_ptr == NULL) {
if (target_ptr == NULL)
return 0;
if (*target_ptr == NULL) {
target = (char *)uv__malloc(target_len + 1);
if (target == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return -1;
}
*target_ptr = target;
} else {
target = *target_ptr;
}
target = (char*)uv__malloc(target_len + 1);
if (target == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return -1;
}
for (; w_source_len; w_source_len--, w_source_ptr++) {
code_point = fs__get_surrogate_value(w_source_ptr, w_source_len);
/* Can be invalid UTF-8 but must be valid WTF-8. */
assert(code_point >= 0);
if (code_point < 0x80) {
*target++ = code_point;
} else if (code_point < 0x800) {
*target++ = 0xC0 | (code_point >> 6);
*target++ = 0x80 | (code_point & 0x3F);
} else if (code_point < 0x10000) {
*target++ = 0xE0 | (code_point >> 12);
*target++ = 0x80 | ((code_point >> 6) & 0x3F);
*target++ = 0x80 | (code_point & 0x3F);
} else {
*target++ = 0xF0 | (code_point >> 18);
*target++ = 0x80 | ((code_point >> 12) & 0x3F);
*target++ = 0x80 | ((code_point >> 6) & 0x3F);
*target++ = 0x80 | (code_point & 0x3F);
w_source_ptr++;
w_source_len--;
}
}
assert((size_t) (target - *target_ptr) == target_len);
*target++ = '\0';
r = WideCharToMultiByte(CP_UTF8,
0,
w_source_ptr,
w_source_len,
target,
target_len,
NULL,
NULL);
assert(r == target_len);
target[target_len] = '\0';
*target_ptr = target;
return 0;
}
INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
uint64_t* target_len_ptr) {
INLINE static int fs__readlink_handle(HANDLE handle,
char** target_ptr,
size_t* target_len_ptr) {
char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
WCHAR* w_target;
@@ -440,7 +552,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
return -1;
}
return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr);
assert(target_ptr == NULL || *target_ptr == NULL);
return fs__wide_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr);
}
@@ -1430,7 +1543,8 @@ void fs__scandir(uv_fs_t* req) {
uv__dirent_t* dirent;
size_t wchar_len;
size_t utf8_len;
size_t wtf8_len;
char* wtf8;
/* Obtain a pointer to the current directory entry. */
position += next_entry_offset;
@@ -1457,11 +1571,8 @@ void fs__scandir(uv_fs_t* req) {
info->FileName[1] == L'.')
continue;
/* Compute the space required to store the filename as UTF-8. */
utf8_len = WideCharToMultiByte(
CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL);
if (utf8_len == 0)
goto win32_error;
/* Compute the space required to store the filename as WTF-8. */
wtf8_len = fs__get_length_wide(&info->FileName[0], wchar_len);
/* Resize the dirent array if needed. */
if (dirents_used >= dirents_size) {
@@ -1481,26 +1592,17 @@ void fs__scandir(uv_fs_t* req) {
* includes room for the first character of the filename, but `utf8_len`
* doesn't count the NULL terminator at this point.
*/
dirent = (uv__dirent_t*)uv__malloc(sizeof *dirent + utf8_len);
dirent = (uv__dirent_t*)uv__malloc(sizeof *dirent + wtf8_len);
if (dirent == NULL)
goto out_of_memory_error;
dirents[dirents_used++] = dirent;
/* Convert file name to UTF-8. */
if (WideCharToMultiByte(CP_UTF8,
0,
&info->FileName[0],
wchar_len,
&dirent->d_name[0],
utf8_len,
NULL,
NULL) == 0)
wtf8 = &dirent->d_name[0];
if (fs__wide_to_wtf8(&info->FileName[0], wchar_len, &wtf8, &wtf8_len) == -1)
goto win32_error;
/* Add a null terminator to the filename. */
dirent->d_name[utf8_len] = '\0';
/* Fill out the type field. */
if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE)
dirent->d_type = UV__DT_CHAR;
@@ -1709,11 +1811,37 @@ void fs__closedir(uv_fs_t* req) {
INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
int do_lstat) {
size_t target_length = 0;
FILE_FS_DEVICE_INFORMATION device_info;
FILE_ALL_INFORMATION file_info;
FILE_FS_VOLUME_INFORMATION volume_info;
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
nt_status = pNtQueryVolumeInformationFile(handle,
&io_status,
&device_info,
sizeof device_info,
FileFsDeviceInformation);
/* Buffer overflow (a warning status code) is expected here. */
if (NT_ERROR(nt_status)) {
SetLastError(pRtlNtStatusToDosError(nt_status));
return -1;
}
/* 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;
return 0;
}
nt_status = pNtQueryInformationFile(handle,
&io_status,
&file_info,
@@ -1779,9 +1907,10 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
* 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, &statbuf->st_size) != 0)
if (fs__readlink_handle(handle, NULL, &target_length) != 0)
return -1;
statbuf->st_mode |= S_IFLNK;
statbuf->st_size = target_length;
}
if (statbuf->st_mode == 0) {
@@ -1918,6 +2047,37 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
}
INLINE static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) {
DWORD file_type;
/* Each file type is processed differently. */
file_type = uv_guess_handle(fd);
switch (file_type) {
/* Disk files use the existing logic from fs__stat_handle. */
case UV_FILE:
return fs__stat_handle(handle, statbuf, 0);
/* Devices and pipes are processed identically. There is no more information
* for them from any API. Fields are set as reasonably as possible and the
* function returns. */
case UV_TTY:
case UV_NAMED_PIPE:
memset(statbuf, 0, sizeof(uv_stat_t));
statbuf->st_mode = file_type == UV_TTY ? _S_IFCHR : _S_IFIFO;
statbuf->st_nlink = 1;
statbuf->st_rdev = (file_type == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16;
statbuf->st_ino = (uintptr_t) handle;
return 0;
/* If file type is unknown it is an error. */
case UV_UNKNOWN_HANDLE:
default:
SetLastError(ERROR_INVALID_HANDLE);
return -1;
}
}
static void fs__stat(uv_fs_t* req) {
fs__stat_prepare_path(req->file.pathw);
fs__stat_impl(req, 0);
@@ -1943,7 +2103,7 @@ static void fs__fstat(uv_fs_t* req) {
return;
}
if (fs__stat_handle(handle, &req->statbuf, 0) != 0) {
if (fs__fstat_handle(fd, handle, &req->statbuf) != 0) {
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
}
@@ -2224,7 +2384,7 @@ static void fs__fchmod(uv_fs_t* req) {
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
goto fchmod_cleanup;
}
/* Remeber to clear the flag later on */
/* Remember to clear the flag later on */
clear_archive_flag = 1;
} else {
clear_archive_flag = 0;
@@ -2606,8 +2766,12 @@ static void fs__readlink(uv_fs_t* req) {
return;
}
assert(req->ptr == NULL);
if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
SET_REQ_WIN32_ERROR(req, GetLastError());
DWORD error = GetLastError();
SET_REQ_WIN32_ERROR(req, error);
if (error == ERROR_NOT_A_REPARSE_POINT)
req->result = UV_EINVAL;
CloseHandle(handle);
return;
}
@@ -2662,7 +2826,8 @@ static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
return -1;
}
r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL);
assert(*realpath_ptr == NULL);
r = fs__wide_to_wtf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL);
uv__free(w_realpath_buf);
return r;
}
@@ -2682,6 +2847,7 @@ static void fs__realpath(uv_fs_t* req) {
return;
}
assert(req->ptr == NULL);
if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) {
CloseHandle(handle);
SET_REQ_WIN32_ERROR(req, GetLastError());

View File

@@ -75,7 +75,7 @@
#define uv__handle_close(handle) \
do { \
QUEUE_REMOVE(&(handle)->handle_queue); \
uv__queue_remove(&(handle)->handle_queue); \
uv__active_handle_rm((uv_handle_t*) (handle)); \
\
(handle)->flags |= UV_HANDLE_CLOSED; \

View File

@@ -168,18 +168,8 @@ void uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* req);
void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
uv_write_t* req);
/*
* uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it
*/
void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* raw_req);
/*
* uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it
*/
void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
uv_connect_t* req);
#define uv__process_tty_accept_req(loop, handle, req) abort()
#define uv__process_tty_connect_req(loop, handle, req) abort()
void uv__process_tty_shutdown_req(uv_loop_t* loop,
uv_tty_t* stream,
uv_shutdown_t* req);
@@ -267,7 +257,6 @@ void uv__util_init(void);
uint64_t uv__hrtime(unsigned int scale);
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);

View File

@@ -57,7 +57,7 @@ static const int pipe_prefix_len = sizeof(pipe_prefix) - 1;
typedef struct {
uv__ipc_socket_xfer_type_t xfer_type;
uv__ipc_socket_xfer_info_t xfer_info;
QUEUE member;
struct uv__queue member;
} uv__ipc_xfer_queue_item_t;
/* IPC frame header flags. */
@@ -113,7 +113,7 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
handle->name = NULL;
handle->pipe.conn.ipc_remote_pid = 0;
handle->pipe.conn.ipc_data_frame.payload_remaining = 0;
QUEUE_INIT(&handle->pipe.conn.ipc_xfer_queue);
uv__queue_init(&handle->pipe.conn.ipc_xfer_queue);
handle->pipe.conn.ipc_xfer_queue_length = 0;
handle->ipc = ipc;
handle->pipe.conn.non_overlapped_writes_tail = NULL;
@@ -639,13 +639,13 @@ void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
if (handle->flags & UV_HANDLE_CONNECTION) {
/* Free pending sockets */
while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) {
QUEUE* q;
while (!uv__queue_empty(&handle->pipe.conn.ipc_xfer_queue)) {
struct uv__queue* q;
SOCKET socket;
q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue);
QUEUE_REMOVE(q);
xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
q = uv__queue_head(&handle->pipe.conn.ipc_xfer_queue);
uv__queue_remove(q);
xfer_queue_item = uv__queue_data(q, uv__ipc_xfer_queue_item_t, member);
/* Materialize socket and close it */
socket = WSASocketW(FROM_PROTOCOL_INFO,
@@ -696,20 +696,48 @@ void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
/* Creates a pipe server. */
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
return uv_pipe_bind2(handle, name, strlen(name), 0);
}
int uv_pipe_bind2(uv_pipe_t* handle,
const char* name,
size_t namelen,
unsigned int flags) {
uv_loop_t* loop = handle->loop;
int i, err, nameSize;
uv_pipe_accept_t* req;
if (flags & ~UV_PIPE_NO_TRUNCATE) {
return UV_EINVAL;
}
if (name == NULL) {
return UV_EINVAL;
}
if (namelen == 0) {
return UV_EINVAL;
}
if (*name == '\0') {
return UV_EINVAL;
}
if (flags & UV_PIPE_NO_TRUNCATE) {
if (namelen > 256) {
return UV_EINVAL;
}
}
if (handle->flags & UV_HANDLE_BOUND) {
return UV_EINVAL;
}
if (!name) {
return UV_EINVAL;
}
if (uv__is_closing(handle)) {
return UV_EINVAL;
}
if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
handle->pipe.serv.pending_instances = default_pending_pipe_instances;
}
@@ -794,15 +822,17 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
/* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait
* up to 30 seconds for the pipe to become available with WaitNamedPipe. */
while (WaitNamedPipeW(handle->name, 30000)) {
while (WaitNamedPipeW(req->u.connect.name, 30000)) {
/* The pipe is now available, try to connect. */
pipeHandle = open_named_pipe(handle->name, &duplex_flags);
pipeHandle = open_named_pipe(req->u.connect.name, &duplex_flags);
if (pipeHandle != INVALID_HANDLE_VALUE)
break;
SwitchToThread();
}
uv__free(req->u.connect.name);
req->u.connect.name = NULL;
if (pipeHandle != INVALID_HANDLE_VALUE) {
SET_REQ_SUCCESS(req);
req->u.connect.pipeHandle = pipeHandle;
@@ -818,18 +848,53 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
}
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
const char* name, uv_connect_cb cb) {
void uv_pipe_connect(uv_connect_t* req,
uv_pipe_t* handle,
const char* name,
uv_connect_cb cb) {
uv_pipe_connect2(req, handle, name, strlen(name), 0, cb);
}
int uv_pipe_connect2(uv_connect_t* req,
uv_pipe_t* handle,
const char* name,
size_t namelen,
unsigned int flags,
uv_connect_cb cb) {
uv_loop_t* loop = handle->loop;
int err, nameSize;
HANDLE pipeHandle = INVALID_HANDLE_VALUE;
DWORD duplex_flags;
if (flags & ~UV_PIPE_NO_TRUNCATE) {
return UV_EINVAL;
}
if (name == NULL) {
return UV_EINVAL;
}
if (namelen == 0) {
return UV_EINVAL;
}
if (*name == '\0') {
return UV_EINVAL;
}
if (flags & UV_PIPE_NO_TRUNCATE) {
if (namelen > 256) {
return UV_EINVAL;
}
}
UV_REQ_INIT(req, UV_CONNECT);
req->handle = (uv_stream_t*) handle;
req->cb = cb;
req->u.connect.pipeHandle = INVALID_HANDLE_VALUE;
req->u.connect.duplex_flags = 0;
req->u.connect.name = NULL;
if (handle->flags & UV_HANDLE_PIPESERVER) {
err = ERROR_INVALID_PARAMETER;
@@ -861,10 +926,19 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
pipeHandle = open_named_pipe(handle->name, &duplex_flags);
if (pipeHandle == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_PIPE_BUSY) {
req->u.connect.name = (WCHAR *)uv__malloc(nameSize);
if (!req->u.connect.name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
memcpy(req->u.connect.name, handle->name, nameSize);
/* Wait for the server to make a pipe instance available. */
if (!QueueUserWorkItem(&pipe_connect_thread_proc,
req,
WT_EXECUTELONGFUNCTION)) {
uv__free(req->u.connect.name);
req->u.connect.name = NULL;
err = GetLastError();
goto error;
}
@@ -872,7 +946,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
REGISTER_HANDLE_REQ(loop, handle, req);
handle->reqs_pending++;
return;
return 0;
}
err = GetLastError();
@@ -885,7 +959,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
uv__insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);
return;
return 0;
error:
if (handle->name) {
@@ -901,7 +975,7 @@ error:
uv__insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);
return;
return 0;
}
@@ -1052,28 +1126,29 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
uv_loop_t* loop = server->loop;
uv_pipe_t* pipe_client;
uv_pipe_accept_t* req;
QUEUE* q;
struct uv__queue* q;
uv__ipc_xfer_queue_item_t* item;
int err;
if (server->ipc) {
if (QUEUE_EMPTY(&server->pipe.conn.ipc_xfer_queue)) {
if (uv__queue_empty(&server->pipe.conn.ipc_xfer_queue)) {
/* No valid pending sockets. */
return WSAEWOULDBLOCK;
}
q = QUEUE_HEAD(&server->pipe.conn.ipc_xfer_queue);
QUEUE_REMOVE(q);
q = uv__queue_head(&server->pipe.conn.ipc_xfer_queue);
uv__queue_remove(q);
server->pipe.conn.ipc_xfer_queue_length--;
item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
item = uv__queue_data(q, uv__ipc_xfer_queue_item_t, member);
err = uv__tcp_xfer_import(
(uv_tcp_t*) client, item->xfer_type, &item->xfer_info);
uv__free(item);
if (err != 0)
return err;
uv__free(item);
} else {
pipe_client = (uv_pipe_t*) client;
uv__pipe_connection_init(pipe_client);
@@ -1640,9 +1715,13 @@ static DWORD uv__pipe_get_ipc_remote_pid(uv_pipe_t* handle) {
/* If the both ends of the IPC pipe are owned by the same process,
* the remote end pid may not yet be set. If so, do it here.
* TODO: this is weird; it'd probably better to use a handshake. */
if (*pid == 0)
*pid = GetCurrentProcessId();
if (*pid == 0) {
GetNamedPipeClientProcessId(handle->handle, pid);
if (*pid == GetCurrentProcessId()) {
GetNamedPipeServerProcessId(handle->handle, pid);
}
}
return *pid;
}
@@ -1814,7 +1893,7 @@ static void uv__pipe_queue_ipc_xfer_info(
item->xfer_type = xfer_type;
item->xfer_info = *xfer_info;
QUEUE_INSERT_TAIL(&handle->pipe.conn.ipc_xfer_queue, &item->member);
uv__queue_insert_tail(&handle->pipe.conn.ipc_xfer_queue, &item->member);
handle->pipe.conn.ipc_xfer_queue_length++;
}
@@ -2071,9 +2150,9 @@ void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
uv__queue_non_overlapped_write(handle);
}
if (handle->stream.conn.write_reqs_pending == 0)
if (handle->flags & UV_HANDLE_SHUTTING)
uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req);
if (handle->stream.conn.write_reqs_pending == 0 &&
uv__is_stream_shutting(handle))
uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req);
DECREASE_PENDING_REQ_COUNT(handle);
}
@@ -2128,7 +2207,10 @@ void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
if (REQ_SUCCESS(req)) {
pipeHandle = req->u.connect.pipeHandle;
duplex_flags = req->u.connect.duplex_flags;
err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags);
if (handle->flags & UV_HANDLE_CLOSING)
err = UV_ECANCELED;
else
err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags);
if (err)
CloseHandle(pipeHandle);
} else {
@@ -2151,7 +2233,6 @@ 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;
handle->flags &= ~UV_HANDLE_SHUTTING;
UNREGISTER_HANDLE_REQ(loop, handle, req);
if (handle->flags & UV_HANDLE_CLOSING) {
@@ -2344,7 +2425,10 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
if (pipe->ipc) {
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
pipe->pipe.conn.ipc_remote_pid = uv_os_getppid();
GetNamedPipeClientProcessId(os_handle, &pipe->pipe.conn.ipc_remote_pid);
if (pipe->pipe.conn.ipc_remote_pid == GetCurrentProcessId()) {
GetNamedPipeServerProcessId(os_handle, &pipe->pipe.conn.ipc_remote_pid);
}
assert(pipe->pipe.conn.ipc_remote_pid != (DWORD)(uv_pid_t) -1);
}
return 0;

View File

@@ -425,9 +425,8 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
return uv_translate_sys_error(WSAGetLastError());
/* Try to obtain a base handle for the socket. This increases this chances that
* we find an AFD handle and are able to use the fast poll mechanism. This will
* always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE
* ioctl. */
* we find an AFD handle and are able to use the fast poll mechanism.
*/
#ifndef NDEBUG
base_socket = INVALID_SOCKET;
#endif

View File

@@ -145,7 +145,6 @@ static void uv__process_init(uv_loop_t* loop, uv_process_t* handle) {
handle->exit_signal = 0;
handle->wait_handle = INVALID_HANDLE_VALUE;
handle->process_handle = INVALID_HANDLE_VALUE;
handle->child_stdio_buffer = NULL;
handle->exit_cb_pending = 0;
UV_REQ_INIT(&handle->exit_req, UV_PROCESS_EXIT);
@@ -948,9 +947,11 @@ int uv_spawn(uv_loop_t* loop,
STARTUPINFOW startup;
PROCESS_INFORMATION info;
DWORD process_flags;
BYTE* child_stdio_buffer;
uv__process_init(loop, process);
process->exit_cb = options->exit_cb;
child_stdio_buffer = NULL;
if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
return UV_ENOTSUP;
@@ -1041,7 +1042,7 @@ int uv_spawn(uv_loop_t* loop,
}
}
err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
err = uv__stdio_create(loop, options, &child_stdio_buffer);
if (err)
goto done;
@@ -1060,12 +1061,12 @@ int uv_spawn(uv_loop_t* loop,
startup.lpTitle = NULL;
startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
startup.cbReserved2 = uv__stdio_size(child_stdio_buffer);
startup.lpReserved2 = (BYTE*) child_stdio_buffer;
startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
startup.hStdInput = uv__stdio_handle(child_stdio_buffer, 0);
startup.hStdOutput = uv__stdio_handle(child_stdio_buffer, 1);
startup.hStdError = uv__stdio_handle(child_stdio_buffer, 2);
process_flags = CREATE_UNICODE_ENVIRONMENT;
@@ -1179,10 +1180,10 @@ int uv_spawn(uv_loop_t* loop,
uv__free(env);
uv__free(alloc_path);
if (process->child_stdio_buffer != NULL) {
if (child_stdio_buffer != NULL) {
/* Clean up child stdio handles. */
uv__stdio_destroy(process->child_stdio_buffer);
process->child_stdio_buffer = NULL;
uv__stdio_destroy(child_stdio_buffer);
child_stdio_buffer = NULL;
}
return uv_translate_sys_error(err);

View File

@@ -204,7 +204,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
uv_loop_t* loop = handle->loop;
if (!(handle->flags & UV_HANDLE_WRITABLE) ||
handle->flags & UV_HANDLE_SHUTTING ||
uv__is_stream_shutting(handle) ||
uv__is_closing(handle)) {
return UV_ENOTCONN;
}
@@ -214,7 +214,6 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
req->cb = cb;
handle->flags &= ~UV_HANDLE_WRITABLE;
handle->flags |= UV_HANDLE_SHUTTING;
handle->stream.conn.shutdown_req = req;
handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);

View File

@@ -29,14 +29,6 @@
#include "req-inl.h"
/*
* Threshold of active tcp streams for which to preallocate tcp read buffers.
* (Due to node slab allocator performing poorly under this pattern,
* the optimization is temporarily disabled (threshold=0). This will be
* revisited once node allocator is improved.)
*/
const unsigned int uv_active_tcp_streams_threshold = 0;
/*
* Number of simultaneous pending AcceptEx calls.
*/
@@ -183,14 +175,14 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
sock = socket(domain, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
err = WSAGetLastError();
QUEUE_REMOVE(&handle->handle_queue);
uv__queue_remove(&handle->handle_queue);
return uv_translate_sys_error(err);
}
err = uv__tcp_set_socket(handle->loop, handle, sock, domain, 0);
if (err) {
closesocket(sock);
QUEUE_REMOVE(&handle->handle_queue);
uv__queue_remove(&handle->handle_queue);
return uv_translate_sys_error(err);
}
@@ -214,7 +206,6 @@ 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;
stream->flags &= ~UV_HANDLE_SHUTTING;
UNREGISTER_HANDLE_REQ(loop, stream, req);
err = 0;
@@ -274,7 +265,6 @@ void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
}
uv__handle_close(handle);
loop->active_tcp_streams--;
}
@@ -484,26 +474,9 @@ static void uv__tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
req = &handle->read_req;
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
/*
* Preallocate a read buffer if the number of active streams is below
* the threshold.
*/
if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
handle->flags &= ~UV_HANDLE_ZERO_READ;
handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
if (handle->tcp.conn.read_buffer.base == NULL ||
handle->tcp.conn.read_buffer.len == 0) {
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
return;
}
assert(handle->tcp.conn.read_buffer.base != NULL);
buf = handle->tcp.conn.read_buffer;
} else {
handle->flags |= UV_HANDLE_ZERO_READ;
buf.base = (char*) &uv_zero_;
buf.len = 0;
}
handle->flags |= UV_HANDLE_ZERO_READ;
buf.base = (char*) &uv_zero_;
buf.len = 0;
/* Prepare the overlapped structure. */
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
@@ -550,7 +523,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
struct linger l = { 1, 0 };
/* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
if (handle->flags & UV_HANDLE_SHUTTING)
if (uv__is_stream_shutting(handle))
return UV_EINVAL;
if (0 != setsockopt(handle->socket, SOL_SOCKET, SO_LINGER, (const char*)&l, sizeof(l)))
@@ -654,7 +627,6 @@ int uv__tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
uv_loop_t* loop = server->loop;
int err = 0;
int family;
@@ -716,8 +688,6 @@ int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
}
}
loop->active_tcp_streams++;
return err;
}
@@ -1163,7 +1133,7 @@ void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
closesocket(handle->socket);
handle->socket = INVALID_SOCKET;
}
if (handle->flags & UV_HANDLE_SHUTTING)
if (uv__is_stream_shutting(handle))
uv__process_tcp_shutdown_req(loop,
handle,
handle->stream.conn.shutdown_req);
@@ -1248,7 +1218,6 @@ void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
0) == 0) {
uv__connection_init((uv_stream_t*)handle);
handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
loop->active_tcp_streams++;
} else {
err = WSAGetLastError();
}
@@ -1331,7 +1300,6 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
}
tcp->loop->active_tcp_streams++;
return 0;
}
@@ -1432,7 +1400,7 @@ static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) {
uv_tcp_non_ifs_lsp_ipv4;
/* If there are non-ifs LSPs then try to obtain a base handle for the socket.
* This will always fail on Windows XP/3k. */
*/
if (non_ifs_lsp) {
DWORD bytes;
if (WSAIoctl(socket,

View File

@@ -180,6 +180,81 @@ int uv_thread_create_ex(uv_thread_t* tid,
return UV_EIO;
}
int uv_thread_setaffinity(uv_thread_t* tid,
char* cpumask,
char* oldmask,
size_t mask_size) {
int i;
HANDLE hproc;
DWORD_PTR procmask;
DWORD_PTR sysmask;
DWORD_PTR threadmask;
DWORD_PTR oldthreadmask;
int cpumasksize;
cpumasksize = uv_cpumask_size();
assert(cpumasksize > 0);
if (mask_size < (size_t)cpumasksize)
return UV_EINVAL;
hproc = GetCurrentProcess();
if (!GetProcessAffinityMask(hproc, &procmask, &sysmask))
return uv_translate_sys_error(GetLastError());
threadmask = 0;
for (i = 0; i < cpumasksize; i++) {
if (cpumask[i]) {
if (procmask & (1LL << i))
threadmask |= 1LL << i;
else
return UV_EINVAL;
}
}
oldthreadmask = SetThreadAffinityMask(*tid, threadmask);
if (oldthreadmask == 0)
return uv_translate_sys_error(GetLastError());
if (oldmask != NULL) {
for (i = 0; i < cpumasksize; i++)
oldmask[i] = (oldthreadmask >> i) & 1;
}
return 0;
}
int uv_thread_getaffinity(uv_thread_t* tid,
char* cpumask,
size_t mask_size) {
int i;
HANDLE hproc;
DWORD_PTR procmask;
DWORD_PTR sysmask;
DWORD_PTR threadmask;
int cpumasksize;
cpumasksize = uv_cpumask_size();
assert(cpumasksize > 0);
if (mask_size < (size_t)cpumasksize)
return UV_EINVAL;
hproc = GetCurrentProcess();
if (!GetProcessAffinityMask(hproc, &procmask, &sysmask))
return uv_translate_sys_error(GetLastError());
threadmask = SetThreadAffinityMask(*tid, procmask);
if (threadmask == 0 || SetThreadAffinityMask(*tid, threadmask) == 0)
return uv_translate_sys_error(GetLastError());
for (i = 0; i < cpumasksize; i++)
cpumask[i] = (threadmask >> i) & 1;
return 0;
}
int uv_thread_getcpu(void) {
return GetCurrentProcessorNumber();
}
uv_thread_t uv_thread_self(void) {
uv_thread_t key;
@@ -374,6 +449,7 @@ void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
abort();
}
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
return 0;
@@ -383,69 +459,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
}
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
int err;
barrier->n = count;
barrier->count = 0;
err = uv_mutex_init(&barrier->mutex);
if (err)
return err;
err = uv_sem_init(&barrier->turnstile1, 0);
if (err)
goto error2;
err = uv_sem_init(&barrier->turnstile2, 1);
if (err)
goto error;
return 0;
error:
uv_sem_destroy(&barrier->turnstile1);
error2:
uv_mutex_destroy(&barrier->mutex);
return err;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
uv_sem_destroy(&barrier->turnstile2);
uv_sem_destroy(&barrier->turnstile1);
uv_mutex_destroy(&barrier->mutex);
}
int uv_barrier_wait(uv_barrier_t* barrier) {
int serial_thread;
uv_mutex_lock(&barrier->mutex);
if (++barrier->count == barrier->n) {
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile1);
}
uv_mutex_unlock(&barrier->mutex);
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile1);
uv_mutex_lock(&barrier->mutex);
serial_thread = (--barrier->count == 0);
if (serial_thread) {
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile2);
}
uv_mutex_unlock(&barrier->mutex);
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile2);
return serial_thread;
}
int uv_key_create(uv_key_t* key) {
key->tls_index = TlsAlloc();
if (key->tls_index == TLS_OUT_OF_INDEXES)

View File

@@ -25,12 +25,7 @@
#include <io.h>
#include <string.h>
#include <stdlib.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
# include "uv/stdint-msvc2008.h"
#else
# include <stdint.h>
#endif
#include <stdint.h>
#ifndef COMMON_LVB_REVERSE_VIDEO
# define COMMON_LVB_REVERSE_VIDEO 0x4000
@@ -179,14 +174,14 @@ void uv__console_init(void) {
0);
if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
CONSOLE_SCREEN_BUFFER_INFO sb_info;
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
NULL,
WT_EXECUTELONGFUNCTION);
uv_mutex_init(&uv__tty_console_resize_mutex);
if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
uv__tty_console_width = sb_info.dwSize.X;
uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
}
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
NULL,
WT_EXECUTELONGFUNCTION);
}
}
@@ -2243,11 +2238,11 @@ void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
handle->stream.conn.write_reqs_pending--;
if (handle->stream.conn.write_reqs_pending == 0)
if (handle->flags & UV_HANDLE_SHUTTING)
uv__process_tty_shutdown_req(loop,
handle,
handle->stream.conn.shutdown_req);
if (handle->stream.conn.write_reqs_pending == 0 &&
uv__is_stream_shutting(handle))
uv__process_tty_shutdown_req(loop,
handle,
handle->stream.conn.shutdown_req);
DECREASE_PENDING_REQ_COUNT(handle);
}
@@ -2278,7 +2273,6 @@ void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown
assert(req);
stream->stream.conn.shutdown_req = NULL;
stream->flags &= ~UV_HANDLE_SHUTTING;
UNREGISTER_HANDLE_REQ(loop, stream, req);
/* TTY shutdown is really just a no-op */
@@ -2308,26 +2302,6 @@ void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
}
/*
* uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it
*/
void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* raw_req) {
abort();
}
/*
* uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it
*/
void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
uv_connect_t* req) {
abort();
}
int uv_tty_reset_mode(void) {
/* Not necessary to do anything. */
return 0;
@@ -2433,7 +2407,6 @@ static void uv__tty_console_signal_resize(void) {
height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
uv_mutex_lock(&uv__tty_console_resize_mutex);
assert(uv__tty_console_width != -1 && uv__tty_console_height != -1);
if (width != uv__tty_console_width || height != uv__tty_console_height) {
uv__tty_console_width = width;
uv__tty_console_height = height;

View File

@@ -29,11 +29,6 @@
#include "req-inl.h"
/*
* Threshold of active udp streams for which to preallocate udp read buffers.
*/
const unsigned int uv_active_udp_streams_threshold = 0;
/* A zero-size buffer for use by uv_udp_read */
static char uv_zero_[] = "";
int uv_udp_getpeername(const uv_udp_t* handle,
@@ -151,14 +146,14 @@ int uv__udp_init_ex(uv_loop_t* loop,
sock = socket(domain, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) {
err = WSAGetLastError();
QUEUE_REMOVE(&handle->handle_queue);
uv__queue_remove(&handle->handle_queue);
return uv_translate_sys_error(err);
}
err = uv__udp_set_socket(handle->loop, handle, sock, domain);
if (err) {
closesocket(sock);
QUEUE_REMOVE(&handle->handle_queue);
uv__queue_remove(&handle->handle_queue);
return uv_translate_sys_error(err);
}
}
@@ -276,84 +271,35 @@ static void uv__udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
req = &handle->recv_req;
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
/*
* Preallocate a read buffer if the number of active streams is below
* the threshold.
*/
if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
handle->flags &= ~UV_HANDLE_ZERO_READ;
handle->flags |= UV_HANDLE_ZERO_READ;
handle->recv_buffer = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &handle->recv_buffer);
if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
return;
}
assert(handle->recv_buffer.base != NULL);
buf.base = (char*) uv_zero_;
buf.len = 0;
flags = MSG_PEEK;
buf = handle->recv_buffer;
memset(&handle->recv_from, 0, sizeof handle->recv_from);
handle->recv_from_len = sizeof handle->recv_from;
flags = 0;
result = handle->func_wsarecvfrom(handle->socket,
(WSABUF*) &buf,
1,
&bytes,
&flags,
(struct sockaddr*) &handle->recv_from,
&handle->recv_from_len,
&req->u.io.overlapped,
NULL);
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
/* Process the req without IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
req->u.io.overlapped.InternalHigh = bytes;
handle->reqs_pending++;
uv__insert_pending_req(loop, req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* The req will be processed with IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
} else {
/* Make this req pending reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError());
uv__insert_pending_req(loop, req);
handle->reqs_pending++;
}
result = handle->func_wsarecv(handle->socket,
(WSABUF*) &buf,
1,
&bytes,
&flags,
&req->u.io.overlapped,
NULL);
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
/* Process the req without IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
req->u.io.overlapped.InternalHigh = bytes;
handle->reqs_pending++;
uv__insert_pending_req(loop, req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* The req will be processed with IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
} else {
handle->flags |= UV_HANDLE_ZERO_READ;
buf.base = (char*) uv_zero_;
buf.len = 0;
flags = MSG_PEEK;
result = handle->func_wsarecv(handle->socket,
(WSABUF*) &buf,
1,
&bytes,
&flags,
&req->u.io.overlapped,
NULL);
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
/* Process the req without IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
req->u.io.overlapped.InternalHigh = bytes;
handle->reqs_pending++;
uv__insert_pending_req(loop, req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* The req will be processed with IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
} else {
/* Make this req pending reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError());
uv__insert_pending_req(loop, req);
handle->reqs_pending++;
}
/* Make this req pending reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError());
uv__insert_pending_req(loop, req);
handle->reqs_pending++;
}
}
@@ -376,7 +322,6 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
handle->flags |= UV_HANDLE_READING;
INCREASE_ACTIVE_COUNT(loop, handle);
loop->active_udp_streams++;
handle->recv_cb = recv_cb;
handle->alloc_cb = alloc_cb;
@@ -393,7 +338,6 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
int uv__udp_recv_stop(uv_udp_t* handle) {
if (handle->flags & UV_HANDLE_READING) {
handle->flags &= ~UV_HANDLE_READING;
handle->loop->active_udp_streams--;
DECREASE_ACTIVE_COUNT(loop, handle);
}
@@ -497,57 +441,68 @@ void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
DWORD bytes, err, flags;
struct sockaddr_storage from;
int from_len;
int count;
/* Do a nonblocking receive.
* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
buf = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
if (buf.base == NULL || buf.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
goto done;
}
assert(buf.base != NULL);
/* Prevent loop starvation when the data comes in as fast as
* (or faster than) we can read it. */
count = 32;
memset(&from, 0, sizeof from);
from_len = sizeof from;
do {
/* Do at most `count` nonblocking receive. */
buf = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
if (buf.base == NULL || buf.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
goto done;
}
flags = 0;
memset(&from, 0, sizeof from);
from_len = sizeof from;
if (WSARecvFrom(handle->socket,
(WSABUF*)&buf,
1,
&bytes,
&flags,
(struct sockaddr*) &from,
&from_len,
NULL,
NULL) != SOCKET_ERROR) {
flags = 0;
/* Message received */
handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
} else {
err = WSAGetLastError();
if (err == WSAEMSGSIZE) {
/* Message truncated */
handle->recv_cb(handle,
bytes,
&buf,
(const struct sockaddr*) &from,
UV_UDP_PARTIAL);
} else if (err == WSAEWOULDBLOCK) {
/* Kernel buffer empty */
handle->recv_cb(handle, 0, &buf, NULL, 0);
} else if (err == WSAECONNRESET || err == WSAENETRESET) {
/* WSAECONNRESET/WSANETRESET is ignored because this just indicates
* that a previous sendto operation failed.
*/
handle->recv_cb(handle, 0, &buf, NULL, 0);
if (WSARecvFrom(handle->socket,
(WSABUF*)&buf,
1,
&bytes,
&flags,
(struct sockaddr*) &from,
&from_len,
NULL,
NULL) != SOCKET_ERROR) {
/* Message received */
err = ERROR_SUCCESS;
handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
} else {
/* Any other error that we want to report back to the user. */
uv_udp_recv_stop(handle);
handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
err = WSAGetLastError();
if (err == WSAEMSGSIZE) {
/* Message truncated */
handle->recv_cb(handle,
bytes,
&buf,
(const struct sockaddr*) &from,
UV_UDP_PARTIAL);
} else if (err == WSAEWOULDBLOCK) {
/* Kernel buffer empty */
handle->recv_cb(handle, 0, &buf, NULL, 0);
} else if (err == WSAECONNRESET || err == WSAENETRESET) {
/* WSAECONNRESET/WSANETRESET is ignored because this just indicates
* that a previous sendto operation failed.
*/
handle->recv_cb(handle, 0, &buf, NULL, 0);
} else {
/* Any other error that we want to report back to the user. */
uv_udp_recv_stop(handle);
handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
}
}
}
while (err == ERROR_SUCCESS &&
count-- > 0 &&
/* The recv_cb callback may decide to pause or close the handle. */
(handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING));
}
done:

View File

@@ -31,6 +31,7 @@
#include "internal.h"
/* clang-format off */
#include <sysinfoapi.h>
#include <winsock2.h>
#include <winperf.h>
#include <iphlpapi.h>
@@ -72,7 +73,9 @@ static char *process_title;
static CRITICAL_SECTION process_title_lock;
#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib, "Dbghelp.lib")
#pragma comment(lib, "IPHLPAPI.lib")
#pragma comment(lib, "Ole32.lib")
#pragma comment(lib, "Psapi.lib")
#pragma comment(lib, "Userenv.lib")
#pragma comment(lib, "kernel32.lib")
@@ -129,9 +132,6 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
goto error;
}
/* utf16_len contains the length, *not* including the terminating null. */
utf16_buffer[utf16_len] = L'\0';
/* Convert to UTF-8 */
utf8_len = WideCharToMultiByte(CP_UTF8,
0,
@@ -159,6 +159,51 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
}
static int uv__cwd(WCHAR** buf, DWORD *len) {
WCHAR* p;
DWORD n;
DWORD t;
t = GetCurrentDirectoryW(0, NULL);
for (;;) {
if (t == 0)
return uv_translate_sys_error(GetLastError());
/* |t| is the size of the buffer _including_ nul. */
p = (WCHAR *)uv__malloc(t * sizeof(*p));
if (p == NULL)
return UV_ENOMEM;
/* |n| is the size of the buffer _excluding_ nul but _only on success_.
* If |t| was too small because another thread changed the working
* directory, |n| is the size the buffer should be _including_ nul.
* It therefore follows we must resize when n >= t and fail when n == 0.
*/
n = GetCurrentDirectoryW(t, p);
if (n > 0)
if (n < t)
break;
uv__free(p);
t = n;
}
/* The returned directory should not have a trailing slash, unless it points
* at a drive root, like c:\. Remove it if needed.
*/
t = n - 1;
if (p[t] == L'\\' && !(n == 3 && p[1] == L':')) {
p[t] = L'\0';
n = t;
}
*buf = p;
*len = n;
return 0;
}
int uv_cwd(char* buffer, size_t* size) {
DWORD utf16_len;
WCHAR *utf16_buffer;
@@ -168,30 +213,9 @@ int uv_cwd(char* buffer, size_t* size) {
return UV_EINVAL;
}
utf16_len = GetCurrentDirectoryW(0, NULL);
if (utf16_len == 0) {
return uv_translate_sys_error(GetLastError());
}
utf16_buffer = (WCHAR*)uv__malloc(utf16_len * sizeof(WCHAR));
if (utf16_buffer == NULL) {
return UV_ENOMEM;
}
utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
if (utf16_len == 0) {
uv__free(utf16_buffer);
return uv_translate_sys_error(GetLastError());
}
/* utf16_len contains the length, *not* including the terminating null. */
utf16_buffer[utf16_len] = L'\0';
/* The returned directory should not have a trailing slash, unless it points
* at a drive root, like c:\. Remove it if needed. */
if (utf16_buffer[utf16_len - 1] == L'\\' &&
!(utf16_len == 3 && utf16_buffer[1] == L':')) {
utf16_len--;
utf16_buffer[utf16_len] = L'\0';
r = uv__cwd(&utf16_buffer, &utf16_len);
if (r < 0) {
return r;
}
/* Check how much space we need */
@@ -234,8 +258,9 @@ int uv_cwd(char* buffer, size_t* size) {
int uv_chdir(const char* dir) {
WCHAR *utf16_buffer;
size_t utf16_len, new_utf16_len;
DWORD utf16_len;
WCHAR drive_letter, env_var[4];
int r;
if (dir == NULL) {
return UV_EINVAL;
@@ -270,32 +295,22 @@ int uv_chdir(const char* dir) {
return uv_translate_sys_error(GetLastError());
}
/* uv__cwd() will return a new buffer. */
uv__free(utf16_buffer);
utf16_buffer = NULL;
/* Windows stores the drive-local path in an "hidden" environment variable,
* which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
* this, so we'll have to do it. */
new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
if (new_utf16_len > utf16_len ) {
uv__free(utf16_buffer);
utf16_buffer = (WCHAR*)uv__malloc(new_utf16_len * sizeof(WCHAR));
if (utf16_buffer == NULL) {
/* When updating the environment variable fails, return UV_OK anyway.
* We did successfully change current working directory, only updating
* hidden env variable failed. */
return 0;
}
new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer);
}
if (utf16_len == 0) {
uv__free(utf16_buffer);
r = uv__cwd(&utf16_buffer, &utf16_len);
if (r == UV_ENOMEM) {
/* When updating the environment variable fails, return UV_OK anyway.
* We did successfully change current working directory, only updating
* hidden env variable failed. */
return 0;
}
/* The returned directory should not have a trailing slash, unless it points
* at a drive root, like c:\. Remove it if needed. */
if (utf16_buffer[utf16_len - 1] == L'\\' &&
!(utf16_len == 3 && utf16_buffer[1] == L':')) {
utf16_len--;
utf16_buffer[utf16_len] = L'\0';
if (r < 0) {
return r;
}
if (utf16_len < 2 || utf16_buffer[1] != L':') {
@@ -338,7 +353,7 @@ uint64_t uv_get_free_memory(void) {
memory_status.dwLength = sizeof(memory_status);
if (!GlobalMemoryStatusEx(&memory_status)) {
return -1;
return 0;
}
return (uint64_t)memory_status.ullAvailPhys;
@@ -350,7 +365,7 @@ uint64_t uv_get_total_memory(void) {
memory_status.dwLength = sizeof(memory_status);
if (!GlobalMemoryStatusEx(&memory_status)) {
return -1;
return 0;
}
return (uint64_t)memory_status.ullTotalPhys;
@@ -362,6 +377,11 @@ uint64_t uv_get_constrained_memory(void) {
}
uint64_t uv_get_available_memory(void) {
return uv_get_free_memory();
}
uv_pid_t uv_os_getpid(void) {
return GetCurrentProcessId();
}
@@ -500,6 +520,7 @@ uint64_t uv_hrtime(void) {
return uv__hrtime(UV__NANOSEC);
}
uint64_t uv__hrtime(unsigned int scale) {
LARGE_INTEGER counter;
double scaled_freq;
@@ -686,71 +707,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
}
static int is_windows_version_or_greater(DWORD os_major,
DWORD os_minor,
WORD service_pack_major,
WORD service_pack_minor) {
OSVERSIONINFOEX osvi;
DWORDLONG condition_mask = 0;
int op = VER_GREATER_EQUAL;
/* Initialize the OSVERSIONINFOEX structure. */
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osvi.dwMajorVersion = os_major;
osvi.dwMinorVersion = os_minor;
osvi.wServicePackMajor = service_pack_major;
osvi.wServicePackMinor = service_pack_minor;
/* Initialize the condition mask. */
VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
/* Perform the test. */
return (int) VerifyVersionInfo(
&osvi,
VER_MAJORVERSION | VER_MINORVERSION |
VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
condition_mask);
}
static int address_prefix_match(int family,
struct sockaddr* address,
struct sockaddr* prefix_address,
int prefix_len) {
uint8_t* address_data;
uint8_t* prefix_address_data;
int i;
assert(address->sa_family == family);
assert(prefix_address->sa_family == family);
if (family == AF_INET6) {
address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
prefix_address_data =
(uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
} else {
address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
prefix_address_data =
(uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
}
for (i = 0; i < prefix_len >> 3; i++) {
if (address_data[i] != prefix_address_data[i])
return 0;
}
if (prefix_len % 8)
return prefix_address_data[i] ==
(address_data[i] & (0xff << (8 - prefix_len % 8)));
return 1;
}
int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
int* count_ptr) {
IP_ADAPTER_ADDRESSES* win_address_buf;
@@ -763,26 +719,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
uv_interface_address_t* uv_address;
int count;
int is_vista_or_greater;
ULONG flags;
*addresses_ptr = NULL;
*count_ptr = 0;
is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
if (is_vista_or_greater) {
flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER;
} else {
/* We need at least XP SP1. */
if (!is_windows_version_or_greater(5, 1, 1, 0))
return UV_ENOTSUP;
flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
}
flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER;
/* Fetch the size of the adapters reported by windows, and then get the list
* itself. */
@@ -947,37 +890,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
sa = unicast_address->Address.lpSockaddr;
/* XP has no OnLinkPrefixLength field. */
if (is_vista_or_greater) {
prefix_len =
((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
} else {
/* Prior to Windows Vista the FirstPrefix pointed to the list with
* single prefix for each IP address assigned to the adapter.
* Order of FirstPrefix does not match order of FirstUnicastAddress,
* so we need to find corresponding prefix.
*/
IP_ADAPTER_PREFIX* prefix;
prefix_len = 0;
for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
/* We want the longest matching prefix. */
if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
prefix->PrefixLength <= prefix_len)
continue;
if (address_prefix_match(sa->sa_family, sa,
prefix->Address.lpSockaddr, prefix->PrefixLength)) {
prefix_len = prefix->PrefixLength;
}
}
/* If there is no matching prefix information, return a single-host
* subnet mask (e.g. 255.255.255.255 for IPv4).
*/
if (!prefix_len)
prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
}
prefix_len =
((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
memset(uv_address, 0, sizeof *uv_address);
@@ -1102,8 +1016,8 @@ int uv_os_homedir(char* buffer, size_t* size) {
if (r != UV_ENOENT)
return r;
/* USERPROFILE is not set, so call uv__getpwuid_r() */
r = uv__getpwuid_r(&pwd);
/* USERPROFILE is not set, so call uv_os_get_passwd() */
r = uv_os_get_passwd(&pwd);
if (r != 0) {
return r;
@@ -1190,17 +1104,6 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
}
void uv_os_free_passwd(uv_passwd_t* pwd) {
if (pwd == NULL)
return;
uv__free(pwd->username);
uv__free(pwd->homedir);
pwd->username = NULL;
pwd->homedir = NULL;
}
/*
* Converts a UTF-16 string into a UTF-8 one. The resulting string is
* null-terminated.
@@ -1297,7 +1200,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
}
int uv__getpwuid_r(uv_passwd_t* pwd) {
static int uv__getpwuid_r(uv_passwd_t* pwd) {
HANDLE token;
wchar_t username[UNLEN + 1];
wchar_t *path;
@@ -1375,6 +1278,16 @@ int uv_os_get_passwd(uv_passwd_t* pwd) {
}
int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) {
return UV_ENOTSUP;
}
int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
return UV_ENOTSUP;
}
int uv_os_environ(uv_env_item_t** envitems, int* count) {
wchar_t* env;
wchar_t* penv;
@@ -1778,6 +1691,22 @@ int uv_os_uname(uv_utsname_t* buffer) {
RegCloseKey(registry_key);
if (r == ERROR_SUCCESS) {
/* Windows 11 shares dwMajorVersion with Windows 10
* this workaround tries to disambiguate that by checking
* if the dwBuildNumber is from Windows 11 releases (>= 22000).
*
* This workaround replaces the ProductName key value
* from "Windows 10 *" to "Windows 11 *" */
if (os_info.dwMajorVersion == 10 &&
os_info.dwBuildNumber >= 22000 &&
product_name_w_size >= ARRAY_SIZE(L"Windows 10")) {
/* If ProductName starts with "Windows 10" */
if (wcsncmp(product_name_w, L"Windows 10", ARRAY_SIZE(L"Windows 10") - 1) == 0) {
/* Bump 10 to 11 */
product_name_w[9] = '1';
}
}
version_size = WideCharToMultiByte(CP_UTF8,
0,
product_name_w,