mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-28 02:11:43 +00:00
[wpinet] Upgrade to libuv 1.46.0 (#5446)
This commit is contained in:
@@ -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,
|
||||
- ®istry_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: {
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
297
upstream_utils/libuv_patches/0003-Fix-warnings.patch
Normal file
297
upstream_utils/libuv_patches/0003-Fix-warnings.patch
Normal 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>
|
||||
@@ -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... */
|
||||
@@ -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;
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 @@
|
||||
|
||||
@@ -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
|
||||
@@ -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 { \
|
||||
531
upstream_utils/libuv_patches/0008-Use-C-atomics.patch
Normal file
531
upstream_utils/libuv_patches/0008-Use-C-atomics.patch
Normal 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)
|
||||
@@ -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");
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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))
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; \
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
|
||||
@@ -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; \
|
||||
|
||||
@@ -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))
|
||||
|
||||
148
wpinet/src/main/native/thirdparty/libuv/src/queue.h
vendored
148
wpinet/src/main/native/thirdparty/libuv/src/queue.h
vendored
@@ -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_ */
|
||||
|
||||
175
wpinet/src/main/native/thirdparty/libuv/src/thread-common.cpp
vendored
Normal file
175
wpinet/src/main/native/thirdparty/libuv/src/thread-common.cpp
vendored
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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_ */
|
||||
2526
wpinet/src/main/native/thirdparty/libuv/src/unix/linux.cpp
vendored
Normal file
2526
wpinet/src/main/native/thirdparty/libuv/src/unix/linux.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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); \
|
||||
} \
|
||||
} \
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "linux-syscalls.h"
|
||||
|
||||
#define uv__random_getrandom_init() 0
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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; \
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user