Commit 103c4dff authored by Jason Madden's avatar Jason Madden Committed by GitHub

Merge pull request #1757 from gevent/libuv-1.40

Update libuv from 1.38.0 to 1.40.0.
parents 7fa9deca 0e403afb
......@@ -27,6 +27,7 @@ Maciej Małecki <maciej.malecki@notimplemented.org> <me@mmalecki.com>
Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com>
Michael <michael_dawson@ca.ibm.com>
Michael Neumann <mneumann@think.localnet> <mneumann@ntecs.de>
Michael Penick <michael.penick@datastax.com> <mpenick@users.noreply.github.com>
Nicholas Vavilov <vvnicholas@gmail.com>
Nick Logan <ugexe@cpan.org> <nlogan@gmail.com>
Rasmus Christian Pedersen <zerhacken@yahoo.com>
......@@ -41,10 +42,12 @@ Santiago Gimeno <santiago.gimeno@quantion.es> <santiago.gimeno@gmail.com>
Saúl Ibarra Corretgé <saghul@gmail.com>
Saúl Ibarra Corretgé <saghul@gmail.com> <s@saghul.net>
Shigeki Ohtsu <ohtsu@iij.ad.jp> <ohtsu@ohtsu.org>
TK-one <tk5641@naver.com>
Timothy J. Fontaine <tjfontaine@gmail.com>
Yasuhiro Matsumoto <mattn.jp@gmail.com>
Yazhong Liu <yorkiefixer@gmail.com>
Yuki Okumura <mjt@cltn.org>
gengjiawen <technicalcute@gmail.com>
jBarz <jBarz@users.noreply.github.com> <jbarboza@ca.ibm.com>
jBarz <jBarz@users.noreply.github.com> <jbarz@users.noreply.github.com>
ptlomholt <pt@lomholt.com>
......
......@@ -432,3 +432,19 @@ Philip Chimento <philip.chimento@gmail.com>
Michal Artazov <michal@artazov.cz>
Jeroen Roovers <jer@gentoo.org>
MasterDuke17 <MasterDuke17@users.noreply.github.com>
Alexander Tokmakov <avtokmakov@yandex-team.ru>
Arenoros <arenoros@gmail.com>
lander0s <dh.landeros08@gmail.com>
Turbinya <wownucleos@gmail.com>
OleksandrKvl <oleksandrdvl@gmail.com>
Carter Li <carter.li@eoitek.com>
Juan Sebastian velez Posada <jvelezpo@users.noreply.github.com>
escherstair <ernestviga@gmail.com>
Evan Lucas <evanlucas@me.com>
tjarlama <59913901+tjarlama@users.noreply.github.com>
司徒玟琅 <sanjusss@qq.com>
YuMeiJie <yumeijie@huawei.com>
Aleksej Lebedev <root@zta.lk>
Nikolay Mitev <github@hmel.org>
Ulrik Strid <ulrik.strid@outlook.com>
Elad Lahav <elahav@qnx.com>
......@@ -56,6 +56,8 @@ check_c_compiler_flag(-Wno-unused-parameter UV_LINT_NO_UNUSED_PARAMETER)
check_c_compiler_flag(-Wstrict-prototypes UV_LINT_STRICT_PROTOTYPES)
check_c_compiler_flag(-Wextra UV_LINT_EXTRA)
check_c_compiler_flag(/utf-8 UV_LINT_UTF8_MSVC)
set(lint-no-unused-parameter $<$<BOOL:${UV_LINT_NO_UNUSED_PARAMETER}>:-Wno-unused-parameter>)
set(lint-strict-prototypes $<$<BOOL:${UV_LINT_STRICT_PROTOTYPES}>:-Wstrict-prototypes>)
set(lint-extra $<$<BOOL:${UV_LINT_EXTRA}>:-Wextra>)
......@@ -76,6 +78,7 @@ set(lint-no-unsafe-msvc $<$<BOOL:${UV_LINT_NO_UNSAFE_MSVC}>:/wd4996>)
string(CONCAT lint-default $<
$<AND:$<BOOL:${UV_LINT_WALL}>,$<NOT:${is-msvc}>>:-Wall
>)
set(lint-utf8-msvc $<$<BOOL:${UV_LINT_UTF8_MSVC}>:/utf-8>)
list(APPEND uv_cflags ${lint-strict-prototypes} ${lint-extra} ${lint-default} ${lint-w4})
list(APPEND uv_cflags ${lint-no-unused-parameter})
......@@ -90,6 +93,7 @@ list(APPEND uv_cflags ${lint-no-hides-param-msvc})
list(APPEND uv_cflags ${lint-no-hides-global-msvc})
list(APPEND uv_cflags ${lint-no-conditional-assignment-msvc})
list(APPEND uv_cflags ${lint-no-unsafe-msvc})
list(APPEND uv_cflags ${lint-utf8-msvc} )
set(uv_sources
src/fs-poll.c
......@@ -107,6 +111,8 @@ if(WIN32)
list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0600)
list(APPEND uv_libraries
psapi
user32
advapi32
iphlpapi
userenv
ws2_32)
......@@ -140,7 +146,7 @@ if(WIN32)
list(APPEND uv_test_sources src/win/snprintf.c test/runner-win.c)
else()
list(APPEND uv_defines _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE)
if(NOT CMAKE_SYSTEM_NAME MATCHES "Android|OS390")
if(NOT CMAKE_SYSTEM_NAME MATCHES "Android|OS390|QNX")
# TODO: This should be replaced with find_package(Threads) if possible
# Android has pthread as part of its c library, not as a separate
# libpthread.so.
......@@ -182,6 +188,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
list(APPEND uv_defines _GNU_SOURCE)
list(APPEND uv_libraries dl)
list(APPEND uv_sources
src/unix/android-ifaddrs.c
......@@ -192,8 +199,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android")
src/unix/pthread-fixes.c
src/unix/random-getentropy.c
src/unix/random-getrandom.c
src/unix/random-sysctl-linux.c
src/unix/sysinfo-loadavg.c)
src/unix/random-sysctl-linux.c)
endif()
if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Android|Linux|OS390")
......@@ -206,7 +212,6 @@ endif()
if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|NetBSD|OpenBSD")
list(APPEND uv_sources src/unix/posix-hrtime.c src/unix/bsd-proctitle.c)
list(APPEND uv_libraries kvm)
endif()
if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|NetBSD|OpenBSD")
......@@ -238,12 +243,12 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
src/unix/linux-syscalls.c
src/unix/procfs-exepath.c
src/unix/random-getrandom.c
src/unix/random-sysctl-linux.c
src/unix/sysinfo-loadavg.c)
src/unix/random-sysctl-linux.c)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
list(APPEND uv_sources src/unix/netbsd.c)
list(APPEND uv_libraries kvm)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
......@@ -284,7 +289,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS400")
src/unix/aix-common.c
src/unix/ibmi.c
src/unix/no-fsevents.c
src/unix/no-proctitle.c
src/unix/posix-poll.c)
endif()
......@@ -294,6 +298,30 @@ if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
list(APPEND uv_sources src/unix/no-proctitle.c src/unix/sunos.c)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
list(APPEND uv_defines _BSD_SOURCE)
list(APPEND uv_libraries bsd network)
list(APPEND uv_sources
src/unix/haiku.c
src/unix/bsd-ifaddrs.c
src/unix/no-fsevents.c
src/unix/no-proctitle.c
src/unix/posix-hrtime.c
src/unix/posix-poll.c)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
list(APPEND uv_sources
src/unix/posix-hrtime.c
src/unix/posix-poll.c
src/unix/qnx.c
src/unix/bsd-ifaddrs.c
src/unix/no-proctitle.c
src/unix/no-fsevents.c)
list(APPEND uv_cflags -fno-strict-aliasing)
list(APPEND uv_libraries socket)
endif()
if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD")
list(APPEND uv_test_libraries util)
endif()
......@@ -417,6 +445,7 @@ if(LIBUV_BUILD_TESTS)
test/test-loop-handles.c
test/test-loop-stop.c
test/test-loop-time.c
test/test-metrics.c
test/test-multiple-listen.c
test/test-mutexes.c
test/test-osx-select.c
......@@ -474,6 +503,7 @@ if(LIBUV_BUILD_TESTS)
test/test-tcp-oob.c
test/test-tcp-open.c
test/test-tcp-read-stop.c
test/test-tcp-read-stop-start.c
test/test-tcp-shutdown-after-write.c
test/test-tcp-try-write.c
test/test-tcp-try-write-error.c
......@@ -483,6 +513,7 @@ if(LIBUV_BUILD_TESTS)
test/test-tcp-write-queue-order.c
test/test-tcp-write-to-half-open-connection.c
test/test-tcp-writealot.c
test/test-test-macros.c
test/test-thread-equal.c
test/test-thread.c
test/test-threadpool-cancel.c
......@@ -500,6 +531,7 @@ if(LIBUV_BUILD_TESTS)
test/test-udp-create-socket-early.c
test/test-udp-dgram-too-big.c
test/test-udp-ipv6.c
test/test-udp-mmsg.c
test/test-udp-multicast-interface.c
test/test-udp-multicast-interface6.c
test/test-udp-multicast-join.c
......@@ -510,6 +542,7 @@ if(LIBUV_BUILD_TESTS)
test/test-udp-send-and-recv.c
test/test-udp-send-hang-loop.c
test/test-udp-send-immediate.c
test/test-udp-sendmmsg-error.c
test/test-udp-send-unreachable.c
test/test-udp-try-send.c
test/test-uname.c
......@@ -541,7 +574,7 @@ if(LIBUV_BUILD_TESTS)
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif()
if(UNIX)
if(UNIX OR MINGW)
# Now for some gibbering horrors from beyond the stars...
foreach(lib IN LISTS uv_libraries)
list(APPEND LIBS "-l${lib}")
......@@ -559,16 +592,17 @@ if(UNIX)
set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
set(prefix ${CMAKE_INSTALL_PREFIX})
configure_file(libuv.pc.in libuv.pc @ONLY)
configure_file(libuv-static.pc.in libuv-static.pc @ONLY)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(FILES ${PROJECT_BINARY_DIR}/libuv.pc
install(FILES ${PROJECT_BINARY_DIR}/libuv.pc ${PROJECT_BINARY_DIR}/libuv-static.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install(TARGETS uv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
if(WIN32)
if(MSVC)
install(DIRECTORY include/ DESTINATION include)
install(FILES LICENSE DESTINATION .)
install(TARGETS uv uv_a
......
2020.05.18, Version 1.38.0 (Stable)
2020.09.26, Version 1.40.0 (Stable)
Changes since version 1.39.0:
* udp: add UV_UDP_MMSG_FREE recv_cb flag (Ryan Liptak)
* include: re-map UV__EPROTO from 4046 to -4046 (YuMeiJie)
* doc: correct UV_UDP_MMSG_FREE version added (cjihrig)
* doc: add uv_metrics_idle_time() version metadata (Ryan Liptak)
* win,tty: pass through utf-16 surrogate pairs (Mustafa M)
* unix: fix DragonFly BSD build (Aleksej Lebedev)
* win,udp: fix error code returned by connect() (Santiago Gimeno)
* src: suppress user_timeout maybe-uninitialized (Daniel Bevenius)
* test: fix compiler warning (Vladimír Čunát)
* build: fix the Haiku cmake build (David Carlier)
* linux: fix i386 sendmmsg/recvmmsg support (Ben Noordhuis)
* build: add libuv-static pkg-config file (Nikolay Mitev)
* unix,win: add uv_timer_get_due_in() (Ulrik Strid)
* build,unix: add QNX support (Elad Lahav)
* include: remove incorrect UV__ERR() for EPROTO (cjihrig)
2020.08.26, Version 1.39.0 (Stable), 25f4b8b8a3c0f934158cd37a37b0525d75ca488e
Changes since version 1.38.1:
* unix: use relaxed loads/stores for clock id (Ben Noordhuis)
* build,win: link to user32.lib and advapi32.lib (George Zhao)
* unix: squelch harmless valgrind warning (ssrlive)
* include: fx c++ style comments warnings (Turbinya)
* build,cmake: Change installation location on MinGW (erw7)
* linux: use copy_file_range for uv_fs_copyfile when possible (Carter Li)
* win,tcp: avoid reinserting a pending request (
* docs: improve the descriptions for get memory info (Juan Sebastian velez
Posada)
* test: add udp-mmsg test (Ryan Liptak)
* udp: add uv_udp_using_recvmmsg query (Ryan Liptak)
* doc: add more error constants (TK-one)
* zos: fix potential event loop stall (Trevor Norris)
* include: add internal fields struct to uv_loop_t (Trevor Norris)
* core: add API to measure event loop idle time (Trevor Norris)
* win,fs: use CreateDirectoryW instead of _wmkdir (Mustafa M)
* win,nfc: fix integer comparison signedness (escherstair)
* win,nfc: use
* win,nfc: removed some unused variables (escherstair)
* win,nfc: add missing return statement (escherstair)
* win,nfc: disable clang-format for
* darwin: use IOKit for uv_cpu_info (Evan Lucas)
* test: fix thread race in process_title_threadsafe (Ben Noordhuis)
* win,fs: avoid implicit access to _doserrno (Jameson Nash)
* test: give hrtime test a custom 20s timeout (Jameson Nash)
* build: add more failed test, for qemu version bump (gengjiawen)
* unix: handle src, dest same in uv_fs_copyfile() (cjihrig)
* unix: error when uv_setup_args() is not called (Ryan Liptak)
* aix: protect uv_exepath() from uv_set_process_title() (Richard Lau)
* fs: clobber req->path on uv_fs_mkstemp() error (tjarlama)
* cmake: fix compile error C2001 on Chinese Windows (司徒玟琅)
* test: avoid double evaluation in ASSERT_BASE macro (tjarlama)
* tcp: fail instantly if local port is unbound (Bartosz Sosnowski)
* doc: fix most sphinx warnings (Jameson Nash)
* nfci: address some style nits (Jameson Nash)
* unix: don't use _POSIX_PATH_MAX (Ben Noordhuis)
2020.07.04, Version 1.38.1 (Stable), e8b989ea1f7f9d4083511a2caec7791e9abd1871
Changes since version 1.38.0:
* test: use last matching qemu version (cjihrig)
* win, util: rearrange uv_hrtime (Bartosz Sosnowski)
* test: skip signal_multiple_loops test on QEMU (gengjiawen)
* build: add android build to CI (gengjiawen)
* test: extend fs_event_error_reporting timeout (cjihrig)
* build: link libkvm on netbsd only (Alexander Tokmakov)
* linux: refactor /proc file reader logic (Ben Noordhuis)
* linux: read load average from /proc/loadavg (Ben Noordhuis)
* android: remove patch code for below 21 (gengjiawen)
* win: fix visual studio 2008 build (Arenoros)
* win,tty: fix deadlock caused by inconsistent state (lander0s)
* unix: use relaxed loads/stores for feature checks (Ben Noordhuis)
* build: don't .gitignore m4/ax_pthread.m4 (Ben Noordhuis)
* unix: fix gcc atomics feature check (Ben Noordhuis)
* darwin: work around clock jumping back in time (Ben Noordhuis)
* udp: fix write_queue cleanup on sendmmsg error (Santiago Gimeno)
* src: build fix for Android (David Carlier)
2020.05.18, Version 1.38.0 (Stable), 1ab9ea3790378f9f25c4e78e9e2b511c75f9c9ed
Changes since version 1.37.0:
......
......@@ -203,6 +203,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-loop-stop.c \
test/test-loop-time.c \
test/test-loop-configure.c \
test/test-metrics.c \
test/test-multiple-listen.c \
test/test-mutexes.c \
test/test-osx-select.c \
......@@ -259,6 +260,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-tcp-flags.c \
test/test-tcp-open.c \
test/test-tcp-read-stop.c \
test/test-tcp-read-stop-start.c \
test/test-tcp-shutdown-after-write.c \
test/test-tcp-unexpected-read.c \
test/test-tcp-oob.c \
......@@ -269,6 +271,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-tcp-try-write.c \
test/test-tcp-try-write-error.c \
test/test-tcp-write-queue-order.c \
test/test-test-macros.c \
test/test-thread-equal.c \
test/test-thread.c \
test/test-threadpool-cancel.c \
......@@ -286,6 +289,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-udp-create-socket-early.c \
test/test-udp-dgram-too-big.c \
test/test-udp-ipv6.c \
test/test-udp-mmsg.c \
test/test-udp-multicast-interface.c \
test/test-udp-multicast-interface6.c \
test/test-udp-multicast-join.c \
......@@ -296,6 +300,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-udp-send-and-recv.c \
test/test-udp-send-hang-loop.c \
test/test-udp-send-immediate.c \
test/test-udp-sendmmsg-error.c \
test/test-udp-send-unreachable.c \
test/test-udp-try-send.c \
test/test-uname.c \
......@@ -373,12 +378,12 @@ uvinclude_HEADERS += include/uv/posix.h
libuv_la_SOURCES += src/unix/aix-common.c \
src/unix/ibmi.c \
src/unix/posix-poll.c \
src/unix/no-fsevents.c \
src/unix/no-proctitle.c
src/unix/no-fsevents.c
endif
if ANDROID
uvinclude_HEADERS += include/uv/android-ifaddrs.h
libuv_la_CFLAGS += -D_GNU_SOURCE
libuv_la_SOURCES += src/unix/android-ifaddrs.c \
src/unix/linux-core.c \
src/unix/linux-inotify.c \
......@@ -386,8 +391,7 @@ libuv_la_SOURCES += src/unix/android-ifaddrs.c \
src/unix/procfs-exepath.c \
src/unix/pthread-fixes.c \
src/unix/random-getrandom.c \
src/unix/random-sysctl-linux.c \
src/unix/sysinfo-loadavg.c
src/unix/random-sysctl-linux.c
endif
if CYGWIN
......@@ -468,8 +472,7 @@ libuv_la_SOURCES += src/unix/linux-core.c \
src/unix/procfs-exepath.c \
src/unix/proctitle.c \
src/unix/random-getrandom.c \
src/unix/random-sysctl-linux.c \
src/unix/sysinfo-loadavg.c
src/unix/random-sysctl-linux.c
test_run_tests_LDFLAGS += -lutil
endif
......
......@@ -13,7 +13,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57)
AC_INIT([libuv], [1.38.0], [https://github.com/libuv/libuv/issues])
AC_INIT([libuv], [1.40.0], [https://github.com/libuv/libuv/issues])
AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4])
m4_include([m4/as_case.m4])
......
......@@ -247,7 +247,8 @@ typedef struct uv_utsname_s uv_utsname_t;
typedef struct uv_statfs_s uv_statfs_t;
typedef enum {
UV_LOOP_BLOCK_SIGNAL
UV_LOOP_BLOCK_SIGNAL = 0,
UV_METRICS_IDLE_TIME
} uv_loop_option;
typedef enum {
......@@ -613,6 +614,12 @@ enum uv_udp_flags {
* must not be freed by the recv_cb callback.
*/
UV_UDP_MMSG_CHUNK = 8,
/*
* Indicates that the buffer provided has been fully utilized by recvmmsg and
* that it should now be freed by the recv_cb callback. When this flag is set
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
*/
UV_UDP_MMSG_FREE = 16,
/*
* Indicates that recvmmsg should be used, if available.
......@@ -693,6 +700,7 @@ UV_EXTERN int uv_udp_try_send(uv_udp_t* handle,
UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
uv_alloc_cb alloc_cb,
uv_udp_recv_cb recv_cb);
UV_EXTERN int uv_udp_using_recvmmsg(const uv_udp_t* handle);
UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
UV_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle);
UV_EXTERN size_t uv_udp_get_send_queue_count(const uv_udp_t* handle);
......@@ -863,6 +871,7 @@ UV_EXTERN int uv_timer_stop(uv_timer_t* handle);
UV_EXTERN int uv_timer_again(uv_timer_t* handle);
UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat);
UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle);
UV_EXTERN uint64_t uv_timer_get_due_in(const uv_timer_t* handle);
/*
......@@ -1191,12 +1200,12 @@ UV_EXTERN uv_pid_t uv_os_getppid(void);
#if defined(__PASE__)
/* On IBM i PASE, the highest process priority is -10 */
# define UV_PRIORITY_LOW 39 // RUNPTY(99)
# define UV_PRIORITY_BELOW_NORMAL 15 // RUNPTY(50)
# define UV_PRIORITY_NORMAL 0 // RUNPTY(20)
# define UV_PRIORITY_ABOVE_NORMAL -4 // RUNTY(12)
# define UV_PRIORITY_HIGH -7 // RUNPTY(6)
# define UV_PRIORITY_HIGHEST -10 // RUNPTY(1)
# define UV_PRIORITY_LOW 39 /* RUNPTY(99) */
# define UV_PRIORITY_BELOW_NORMAL 15 /* RUNPTY(50) */
# define UV_PRIORITY_NORMAL 0 /* RUNPTY(20) */
# define UV_PRIORITY_ABOVE_NORMAL -4 /* RUNTY(12) */
# define UV_PRIORITY_HIGH -7 /* RUNPTY(6) */
# define UV_PRIORITY_HIGHEST -10 /* RUNPTY(1) */
#else
# define UV_PRIORITY_LOW 19
# define UV_PRIORITY_BELOW_NORMAL 10
......@@ -1243,6 +1252,7 @@ UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size);
UV_EXTERN int uv_os_uname(uv_utsname_t* buffer);
UV_EXTERN uint64_t uv_metrics_idle_time(uv_loop_t* loop);
typedef enum {
UV_FS_UNKNOWN = -1,
......@@ -1774,9 +1784,11 @@ struct uv_loop_s {
unsigned int active_handles;
void* handle_queue[2];
union {
void* unused[2];
void* unused;
unsigned int count;
} active_reqs;
/* Internal storage for future extensions. */
void* internal_fields;
/* Internal flag to signal loop stop. */
unsigned int stop_flag;
UV_LOOP_PRIVATE_FIELDS
......
......@@ -317,7 +317,7 @@
#if defined(EPROTO) && !defined(_WIN32)
# define UV__EPROTO UV__ERR(EPROTO)
#else
# define UV__EPROTO UV__ERR(4046)
# define UV__EPROTO (-4046)
#endif
#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
......
......@@ -69,6 +69,8 @@
# include "uv/posix.h"
#elif defined(__HAIKU__)
# include "uv/posix.h"
#elif defined(__QNX__)
# include "uv/posix.h"
#endif
#ifndef NI_MAXHOST
......
......@@ -31,7 +31,7 @@
*/
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 38
#define UV_VERSION_MINOR 40
#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""
......
prefix=@prefix@
exec_prefix=${prefix}
libdir=@libdir@
includedir=@includedir@
Name: libuv-static
Version: @PACKAGE_VERSION@
Description: multi-platform support library with a focus on asynchronous I/O.
URL: http://libuv.org/
Libs: -L${libdir} -luv_a @LIBS@
Cflags: -I${includedir}
# Ignore libtoolize-generated files.
*.m4
!as_case.m4
!ax_pthread.m4
!libuv-check-flags.m4
......@@ -33,7 +33,7 @@ static int uv__random(void* buf, size_t buflen) {
#if defined(__PASE__)
rc = uv__random_readpath("/dev/urandom", buf, buflen);
#elif defined(_AIX)
#elif defined(_AIX) || defined(__QNX__)
rc = uv__random_readpath("/dev/random", buf, buflen);
#elif defined(__APPLE__) || defined(__OpenBSD__) || \
(defined(__ANDROID_API__) && __ANDROID_API__ >= 28)
......
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "strscpy.h"
#include <limits.h> /* SSIZE_MAX */
......
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_STRSCPY_H_
#define UV_STRSCPY_H_
......
......@@ -130,6 +130,14 @@ uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
}
uint64_t uv_timer_get_due_in(const uv_timer_t* handle) {
if (handle->loop->time >= handle->timeout)
return 0;
return handle->timeout - handle->loop->time;
}
int uv__next_timeout(const uv_loop_t* loop) {
const struct heap_node* heap_node;
const uv_timer_t* handle;
......
......@@ -22,42 +22,23 @@
#include "uv.h"
#include "internal.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in6_var.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <utmp.h>
#include <libgen.h>
#include <sys/protosw.h>
#include <procinfo.h>
#include <sys/proc.h>
#include <sys/procfs.h>
#include <sys/poll.h>
#include <sys/pollset.h>
#include <ctype.h>
#include <sys/mntctl.h>
#include <sys/vmount.h>
#include <limits.h>
#include <strings.h>
#include <sys/vnode.h>
extern char* original_exepath;
extern uv_mutex_t process_title_mutex;
extern uv_once_t process_title_mutex_once;
extern void init_process_title_mutex_once(void);
uint64_t uv__hrtime(uv_clocktype_t type) {
uint64_t G = 1000000000;
......@@ -78,80 +59,31 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
*/
int uv_exepath(char* buffer, size_t* size) {
int res;
char args[PATH_MAX];
char abspath[PATH_MAX];
size_t abspath_size;
char args[UV__PATH_MAX];
size_t cached_len;
struct procsinfo pi;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
pi.pi_pid = getpid();
res = getargs(&pi, sizeof(pi), args, sizeof(args));
if (res < 0)
return UV_EINVAL;
/*
* Possibilities for args:
* i) an absolute path such as: /home/user/myprojects/nodejs/node
* ii) a relative path such as: ./node or ../myprojects/nodejs/node
* iii) a bare filename such as "node", after exporting PATH variable
* to its location.
*/
/* Case i) and ii) absolute or relative paths */
if (strchr(args, '/') != NULL) {
if (realpath(args, abspath) != abspath)
return UV__ERR(errno);
abspath_size = strlen(abspath);
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
if (original_exepath != NULL) {
cached_len = strlen(original_exepath);
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
if (*size > cached_len)
*size = cached_len;
memcpy(buffer, original_exepath, *size);
buffer[*size] = '\0';
uv_mutex_unlock(&process_title_mutex);
return 0;
} else {
/* Case iii). Search PATH environment variable */
char trypath[PATH_MAX];
char *clonedpath = NULL;
char *token = NULL;
char *path = getenv("PATH");
if (path == NULL)
return UV_EINVAL;
clonedpath = uv__strdup(path);
if (clonedpath == NULL)
return UV_ENOMEM;
token = strtok(clonedpath, ":");
while (token != NULL) {
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
if (realpath(trypath, abspath) == abspath) {
/* Check the match is executable */
if (access(abspath, X_OK) == 0) {
abspath_size = strlen(abspath);
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
uv__free(clonedpath);
return 0;
}
}
token = strtok(NULL, ":");
}
uv__free(clonedpath);
}
uv_mutex_unlock(&process_title_mutex);
pi.pi_pid = getpid();
res = getargs(&pi, sizeof(pi), args, sizeof(args));
/* Out of tokens (path entries), and no match found */
if (res < 0)
return UV_EINVAL;
}
return uv__search_path(args, buffer, size);
}
......@@ -65,14 +65,15 @@
#define RDWR_BUF_SIZE 4096
#define EQ(a,b) (strcmp(a,b) == 0)
static uv_mutex_t process_title_mutex;
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
char* original_exepath = NULL;
uv_mutex_t process_title_mutex;
uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static void* args_mem = NULL;
static char** process_argv = NULL;
static int process_argc = 0;
static char* process_title_ptr = NULL;
static void init_process_title_mutex_once(void) {
void init_process_title_mutex_once(void) {
uv_mutex_init(&process_title_mutex);
}
......@@ -145,6 +146,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int i;
int rc;
int add_failed;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
......@@ -214,7 +217,21 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (;;) {
/* 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);
nfds = pollset_poll(loop->backend_fd,
events,
ARRAY_SIZE(events),
......@@ -227,6 +244,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
if (timeout == -1)
continue;
if (timeout > 0)
goto update_timeout;
}
assert(timeout != -1);
return;
}
......@@ -236,6 +262,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
abort();
}
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
......@@ -280,16 +311,25 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher)
if (w == &loop->signal_io_watcher) {
have_signals = 1;
else
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->revents);
}
nevents++;
}
if (have_signals != 0)
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
......@@ -830,6 +870,7 @@ void uv__fs_event_close(uv_fs_event_t* handle) {
char** uv_setup_args(int argc, char** argv) {
char exepath[UV__PATH_MAX];
char** new_argv;
size_t size;
char* s;
......@@ -845,6 +886,15 @@ char** uv_setup_args(int argc, char** argv) {
process_argv = argv;
process_argc = argc;
/* Use argv[0] to determine value for uv_exepath(). */
size = sizeof(exepath);
if (uv__search_path(argv[0], exepath, &size) == 0) {
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
original_exepath = uv__strdup(exepath);
uv_mutex_unlock(&process_title_mutex);
}
/* Calculate how much memory we need for the argv strings. */
size = 0;
for (i = 0; i < argc; i++)
......@@ -875,6 +925,10 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
char* new_title;
/* If uv_setup_args wasn't called or failed, we can't continue. */
if (process_argv == NULL || args_mem == NULL)
return UV_ENOBUFS;
/* We cannot free this pointer when libuv shuts down,
* the process may still be using it.
*/
......@@ -908,6 +962,10 @@ int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return UV_EINVAL;
/* If uv_setup_args wasn't called, we can't continue. */
if (process_argv == NULL)
return UV_ENOBUFS;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
......
......@@ -113,7 +113,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
}
if (ent->ifa_netmask->sa_family == AF_INET6) {
if (ent->ifa_netmask == NULL) {
memset(&address->netmask, 0, sizeof(address->netmask));
} else if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
......
......@@ -79,10 +79,6 @@ extern char** environ;
# endif
#endif
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
# include <dlfcn.h> /* for dlsym */
#endif
#if defined(__MVS__)
#include <sys/ioctl.h>
#endif
......@@ -220,15 +216,23 @@ int uv__getiovmax(void) {
#if defined(IOV_MAX)
return IOV_MAX;
#elif defined(_SC_IOV_MAX)
static int iovmax = -1;
if (iovmax == -1) {
iovmax = sysconf(_SC_IOV_MAX);
/* On some embedded devices (arm-linux-uclibc based ip camera),
* sysconf(_SC_IOV_MAX) can not get the correct value. The return
* value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
*/
if (iovmax == -1) iovmax = 1;
}
static int iovmax_cached = -1;
int iovmax;
iovmax = uv__load_relaxed(&iovmax_cached);
if (iovmax != -1)
return iovmax;
/* On some embedded devices (arm-linux-uclibc based ip camera),
* sysconf(_SC_IOV_MAX) can not get the correct value. The return
* value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
*/
iovmax = sysconf(_SC_IOV_MAX);
if (iovmax == -1)
iovmax = 1;
uv__store_relaxed(&iovmax_cached, iovmax);
return iovmax;
#else
return 1024;
......@@ -379,6 +383,14 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
timeout = uv_backend_timeout(loop);
uv__io_poll(loop, timeout);
/* Run one final update on the provider_idle_time in case uv__io_poll
* returned because the timeout expired, but no events were received. This
* call will be ignored if the provider_entry_time was either never set (if
* the timeout == 0) or was already updated b/c an event was received.
*/
uv__metrics_update_idle_time(loop);
uv__run_check(loop);
uv__run_closing_handles(loop);
......@@ -662,7 +674,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
int* end;
#if defined(__linux__)
static int no_msg_cmsg_cloexec;
if (no_msg_cmsg_cloexec == 0) {
if (0 == uv__load_relaxed(&no_msg_cmsg_cloexec)) {
rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
if (rc != -1)
return rc;
......@@ -671,7 +683,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
rc = recvmsg(fd, msg, flags);
if (rc == -1)
return UV__ERR(errno);
no_msg_cmsg_cloexec = 1;
uv__store_relaxed(&no_msg_cmsg_cloexec, 1);
} else {
rc = recvmsg(fd, msg, flags);
}
......@@ -1142,13 +1154,6 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
size_t shell_size;
long initsize;
int r;
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
if (getpwuid_r == NULL)
return UV_ENOSYS;
#endif
if (pwd == NULL)
return UV_EINVAL;
......@@ -1531,3 +1536,78 @@ void uv_sleep(unsigned int msec) {
assert(rc == 0);
}
int uv__search_path(const char* prog, char* buf, size_t* buflen) {
char abspath[UV__PATH_MAX];
size_t abspath_size;
char trypath[UV__PATH_MAX];
char* cloned_path;
char* path_env;
char* token;
if (buf == NULL || buflen == NULL || *buflen == 0)
return UV_EINVAL;
/*
* Possibilities for prog:
* i) an absolute path such as: /home/user/myprojects/nodejs/node
* ii) a relative path such as: ./node or ../myprojects/nodejs/node
* iii) a bare filename such as "node", after exporting PATH variable
* to its location.
*/
/* Case i) and ii) absolute or relative paths */
if (strchr(prog, '/') != NULL) {
if (realpath(prog, abspath) != abspath)
return UV__ERR(errno);
abspath_size = strlen(abspath);
*buflen -= 1;
if (*buflen > abspath_size)
*buflen = abspath_size;
memcpy(buf, abspath, *buflen);
buf[*buflen] = '\0';
return 0;
}
/* Case iii). Search PATH environment variable */
cloned_path = NULL;
token = NULL;
path_env = getenv("PATH");
if (path_env == NULL)
return UV_EINVAL;
cloned_path = uv__strdup(path_env);
if (cloned_path == NULL)
return UV_ENOMEM;
token = strtok(cloned_path, ":");
while (token != NULL) {
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog);
if (realpath(trypath, abspath) == abspath) {
/* Check the match is executable */
if (access(abspath, X_OK) == 0) {
abspath_size = strlen(abspath);
*buflen -= 1;
if (*buflen > abspath_size)
*buflen = abspath_size;
memcpy(buf, abspath, *buflen);
buf[*buflen] = '\0';
uv__free(cloned_path);
return 0;
}
}
token = strtok(NULL, ":");
}
uv__free(cloned_path);
/* Out of tokens (path entries), and no match found */
return UV_EINVAL;
}
......@@ -27,6 +27,7 @@
struct CFArrayCallBacks;
struct CFRunLoopSourceContext;
struct FSEventStreamContext;
struct CFRange;
typedef double CFAbsoluteTime;
typedef double CFTimeInterval;
......@@ -42,13 +43,23 @@ 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,
......@@ -69,6 +80,11 @@ struct FSEventStreamContext {
void* pad[3];
};
struct CFRange {
CFIndex location;
CFIndex length;
};
static const CFStringEncoding kCFStringEncodingUTF8 = 0x8000100;
static const OSStatus noErr = 0;
......
......@@ -25,6 +25,7 @@
#include <stdint.h>
#include <errno.h>
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
......@@ -32,6 +33,15 @@
#include <sys/sysctl.h>
#include <unistd.h> /* sysconf */
#if !TARGET_OS_IPHONE
#include "darwin-stub.h"
#endif
static uv_once_t once = UV_ONCE_INIT;
static uint64_t (*time_func)(void);
static mach_timebase_info_data_t timebase;
typedef unsigned char UInt8;
int uv__platform_loop_init(uv_loop_t* loop) {
loop->cf_state = NULL;
......@@ -48,15 +58,19 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
uint64_t uv__hrtime(uv_clocktype_t type) {
static mach_timebase_info_data_t info;
if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
ACCESS_ONCE(uint32_t, info.denom) == 0) &&
mach_timebase_info(&info) != KERN_SUCCESS)
static void uv__hrtime_init_once(void) {
if (KERN_SUCCESS != mach_timebase_info(&timebase))
abort();
return mach_absolute_time() * info.numer / info.denom;
time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time");
if (time_func == NULL)
time_func = mach_absolute_time;
}
uint64_t uv__hrtime(uv_clocktype_t type) {
uv_once(&once, uv__hrtime_init_once);
return time_func() * timebase.numer / timebase.denom;
}
......@@ -171,17 +185,149 @@ 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/"
"Versions/A/CoreFoundation",
RTLD_LAZY | RTLD_LOCAL);
iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/"
"Versions/A/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)
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) {
uint32_t freq;
CFIndex len = pCFDataGetLength(freq_ref);
CFRange range;
range.location = 0;
range.length = len;
pCFDataGetBytes(freq_ref, range, (UInt8*)&freq);
*speed = freq;
pCFRelease(freq_ref);
pCFRelease(data);
break;
}
}
pCFRelease(data);
}
service = pIOIteratorNext(it);
}
pIOObjectRelease(it);
err = 0;
out:
if (core_foundation_handle != NULL)
dlclose(core_foundation_handle);
if (iokit_handle != NULL)
dlclose(iokit_handle);
mach_port_deallocate(mach_task_self(), mach_port);
return err;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks);
char model[512];
uint64_t cpuspeed;
size_t size;
unsigned int i;
natural_t numcpus;
mach_msg_type_number_t msg_type;
processor_cpu_load_info_data_t *info;
uv_cpu_info_t* cpu_info;
uint64_t cpuspeed;
int err;
size = sizeof(model);
if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
......@@ -189,9 +335,9 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
return UV__ERR(errno);
}
size = sizeof(cpuspeed);
if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0))
return UV__ERR(errno);
err = uv__get_cpu_speed(&cpuspeed);
if (err < 0)
return err;
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
(processor_info_array_t*)&info,
......
......@@ -56,31 +56,6 @@ int uv__platform_loop_init(uv_loop_t* loop) {
void uv__platform_loop_delete(uv_loop_t* loop) {
}
#ifdef __DragonFly__
int uv_exepath(char* buffer, size_t* size) {
char abspath[PATH_MAX * 2 + 1];
ssize_t abspath_size;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
if (abspath_size < 0)
return UV__ERR(errno);
assert(abspath_size > 0);
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
return 0;
}
#else
int uv_exepath(char* buffer, size_t* size) {
char abspath[PATH_MAX * 2 + 1];
int mib[4];
......@@ -110,7 +85,6 @@ int uv_exepath(char* buffer, size_t* size) {
return 0;
}
#endif
uint64_t uv_get_free_memory(void) {
int freecount;
......@@ -290,25 +264,18 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
}
int uv__sendmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags) {
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if __FreeBSD__ >= 11
return sendmmsg(fd, mmsg, vlen, flags);
return sendmmsg(fd, mmsg, vlen, /* flags */ 0);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__recvmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags,
struct timespec* timeout) {
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if __FreeBSD__ >= 11
return recvmmsg(fd, mmsg, vlen, flags, timeout);
return recvmmsg(fd, mmsg, vlen, 0 /* flags */, NULL /* timeout */);
#else
return errno = ENOSYS, -1;
#endif
......
......@@ -79,7 +79,11 @@
defined(__NetBSD__)
# include <sys/param.h>
# include <sys/mount.h>
#elif defined(__sun) || defined(__MVS__) || defined(__NetBSD__) || defined(__HAIKU__)
#elif defined(__sun) || \
defined(__MVS__) || \
defined(__NetBSD__) || \
defined(__HAIKU__) || \
defined(__QNX__)
# include <sys/statvfs.h>
#else
# include <sys/statfs.h>
......@@ -229,11 +233,7 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime);
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
return utimensat(req->file, NULL, ts, 0);
#else
return futimens(req->file, ts);
#endif
#elif defined(__APPLE__) \
|| defined(__DragonFly__) \
|| defined(__FreeBSD__) \
......@@ -310,13 +310,14 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
if (path_length < pattern_size ||
strcmp(path + path_length - pattern_size, pattern)) {
errno = EINVAL;
return -1;
r = -1;
goto clobber;
}
uv_once(&once, uv__mkostemp_initonce);
#ifdef O_CLOEXEC
if (no_cloexec_support == 0 && uv__mkostemp != NULL) {
if (uv__load_relaxed(&no_cloexec_support) == 0 && uv__mkostemp != NULL) {
r = uv__mkostemp(path, O_CLOEXEC);
if (r >= 0)
......@@ -325,11 +326,11 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
/* If mkostemp() returns EINVAL, it means the kernel doesn't
support O_CLOEXEC, so we just fallback to mkstemp() below. */
if (errno != EINVAL)
return r;
goto clobber;
/* We set the static variable so that next calls don't even
try to use mkostemp. */
no_cloexec_support = 1;
uv__store_relaxed(&no_cloexec_support, 1);
}
#endif /* O_CLOEXEC */
......@@ -351,6 +352,9 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
if (req->cb != NULL)
uv_rwlock_rdunlock(&req->loop->cloexec_lock);
clobber:
if (r < 0)
path[0] = '\0';
return r;
}
......@@ -460,7 +464,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if defined(__linux__)
if (no_preadv) retry:
if (uv__load_relaxed(&no_preadv)) retry:
# endif
{
result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
......@@ -472,7 +476,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
req->nbufs,
req->off);
if (result == -1 && errno == ENOSYS) {
no_preadv = 1;
uv__store_relaxed(&no_preadv, 1);
goto retry;
}
}
......@@ -629,7 +633,11 @@ static int uv__fs_closedir(uv_fs_t* req) {
static int uv__fs_statfs(uv_fs_t* req) {
uv_statfs_t* stat_fs;
#if defined(__sun) || defined(__MVS__) || defined(__NetBSD__) || defined(__HAIKU__)
#if defined(__sun) || \
defined(__MVS__) || \
defined(__NetBSD__) || \
defined(__HAIKU__) || \
defined(__QNX__)
struct statvfs buf;
if (0 != statvfs(req->path, &buf))
......@@ -646,7 +654,12 @@ static int uv__fs_statfs(uv_fs_t* req) {
return -1;
}
#if defined(__sun) || defined(__MVS__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__)
#if defined(__sun) || \
defined(__MVS__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__) || \
defined(__HAIKU__) || \
defined(__QNX__)
stat_fs->f_type = 0; /* f_type is not supported. */
#else
stat_fs->f_type = buf.f_type;
......@@ -887,8 +900,27 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
ssize_t r;
off = req->off;
#ifdef __linux__
{
static int copy_file_range_support = 1;
if (copy_file_range_support) {
r = uv__fs_copy_file_range(in_fd, NULL, out_fd, &off, req->bufsml[0].len, 0);
if (r == -1 && errno == ENOSYS) {
errno = 0;
copy_file_range_support = 0;
} else {
goto ok;
}
}
}
#endif
r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len);
ok:
/* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
* it still writes out data. Fortunately, we can detect it by checking if
* the offset has been updated.
......@@ -1131,7 +1163,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
goto out;
}
dst_flags = O_WRONLY | O_CREAT | O_TRUNC;
dst_flags = O_WRONLY | O_CREAT;
if (req->flags & UV_FS_COPYFILE_EXCL)
dst_flags |= O_EXCL;
......@@ -1150,16 +1182,26 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
goto out;
}
/* Get the destination file's mode. */
if (fstat(dstfd, &dst_statsbuf)) {
err = UV__ERR(errno);
goto out;
}
/* If the file is not being opened exclusively, verify that the source and
destination are not the same file. If they are the same, bail out early. */
if ((req->flags & UV_FS_COPYFILE_EXCL) == 0) {
/* Get the destination file's mode. */
if (fstat(dstfd, &dst_statsbuf)) {
err = UV__ERR(errno);
goto out;
}
/* Check if srcfd and dstfd refer to the same file */
if (src_statsbuf.st_dev == dst_statsbuf.st_dev &&
src_statsbuf.st_ino == dst_statsbuf.st_ino) {
goto out;
/* Check if srcfd and dstfd refer to the same file */
if (src_statsbuf.st_dev == dst_statsbuf.st_dev &&
src_statsbuf.st_ino == dst_statsbuf.st_ino) {
goto out;
}
/* Truncate the file in case the destination already existed. */
if (ftruncate(dstfd, 0) != 0) {
err = UV__ERR(errno);
goto out;
}
}
if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
......@@ -1355,7 +1397,7 @@ static int uv__fs_statx(int fd,
int mode;
int rc;
if (no_statx)
if (uv__load_relaxed(&no_statx))
return UV_ENOSYS;
dirfd = AT_FDCWD;
......@@ -1388,7 +1430,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.
*/
no_statx = 1;
uv__store_relaxed(&no_statx, 1);
return UV_ENOSYS;
}
......@@ -2031,7 +2073,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
/* Only necessary for asychronous requests, i.e., requests with a callback.
* Synchronous ones don't copy their arguments and have req->path and
* req->new_path pointing to user-owned memory. UV_FS_MKDTEMP 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.
*/
if (req->path != NULL &&
......
......@@ -58,6 +58,9 @@
#include <as400_protos.h>
#include <as400_types.h>
char* original_exepath = NULL;
uv_mutex_t process_title_mutex;
uv_once_t process_title_mutex_once = UV_ONCE_INIT;
typedef struct {
int bytes_available;
......@@ -171,6 +174,9 @@ static void iconv_a2e(const char* src, unsigned char dst[], size_t length) {
dst[i] = a2e[' '];
}
void init_process_title_mutex_once(void) {
uv_mutex_init(&process_title_mutex);
}
static int get_ibmi_system_status(SSTS0200* rcvr) {
/* rcvrlen is input parameter 2 to QWCRSSTS */
......@@ -459,3 +465,37 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
uv__free(addresses);
}
char** uv_setup_args(int argc, char** argv) {
char exepath[UV__PATH_MAX];
char* s;
size_t size;
if (argc > 0) {
/* Use argv[0] to determine value for uv_exepath(). */
size = sizeof(exepath);
if (uv__search_path(argv[0], exepath, &size) == 0) {
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
original_exepath = uv__strdup(exepath);
uv_mutex_unlock(&process_title_mutex);
}
}
return argv;
}
int uv_set_process_title(const char* title) {
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return UV_EINVAL;
buffer[0] = '\0';
return 0;
}
void uv__process_title_cleanup(void) {
}
\ No newline at end of file
......@@ -62,9 +62,7 @@
# include <AvailabilityMacros.h>
#endif
#if defined(_POSIX_PATH_MAX)
# define UV__PATH_MAX _POSIX_PATH_MAX
#elif defined(PATH_MAX)
#if defined(PATH_MAX)
# define UV__PATH_MAX PATH_MAX
#else
# define UV__PATH_MAX 8192
......@@ -268,6 +266,7 @@ void uv__udp_finish_close(uv_udp_t* handle);
uv_handle_type uv__handle_type(int fd);
FILE* uv__open_file(const char* path);
int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__search_path(const char* prog, char* buf, size_t* buflen);
/* random */
int uv__random_devurandom(void* buf, size_t buflen);
......@@ -335,15 +334,8 @@ struct uv__mmsghdr {
unsigned int msg_len;
};
int uv__recvmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags,
struct timespec* timeout);
int uv__sendmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags);
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
......
......@@ -82,7 +82,7 @@ int uv__io_fork(uv_loop_t* loop) {
process. So we sidestep the issue by pretending like we never
started it in the first place.
*/
uv__has_forked_with_cfrunloop = 1;
uv__store_relaxed(&uv__has_forked_with_cfrunloop, 1);
uv__free(loop->cf_state);
loop->cf_state = NULL;
}
......@@ -129,6 +129,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int fd;
int op;
int i;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
......@@ -202,7 +204,21 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (;; nevents = 0) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
if (timeout != -1) {
spec.tv_sec = timeout / 1000;
spec.tv_nsec = (timeout % 1000) * 1000000;
......@@ -228,6 +244,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
if (timeout == -1)
continue;
if (timeout > 0)
goto update_timeout;
}
assert(timeout != -1);
return;
}
......@@ -236,6 +261,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == 0)
return;
......@@ -276,6 +306,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (ev->filter == EVFILT_VNODE) {
assert(w->events == POLLIN);
assert(w->pevents == POLLIN);
uv__metrics_update_idle_time(loop);
w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
nevents++;
continue;
......@@ -337,16 +368,25 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher)
if (w == &loop->signal_io_watcher) {
have_signals = 1;
else
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, revents);
}
nevents++;
}
if (have_signals != 0)
if (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;
......@@ -487,7 +527,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
if (!(statbuf.st_mode & S_IFDIR))
goto fallback;
if (!uv__has_forked_with_cfrunloop) {
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) {
int r;
/* The fallback fd is no longer needed */
uv__close_nocheckstdio(fd);
......@@ -522,8 +562,9 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
uv__handle_stop(handle);
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if (!uv__has_forked_with_cfrunloop && handle->cf_cb != NULL)
r = uv__fsevents_close(handle);
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop))
if (handle->cf_cb != NULL)
r = uv__fsevents_close(handle);
#endif
if (handle->event_watcher.fd != -1) {
......
......@@ -85,17 +85,7 @@ static uint64_t read_cpufreq(unsigned int cpunum);
int uv__platform_loop_init(uv_loop_t* loop) {
int fd;
/* It was reported that EPOLL_CLOEXEC is not defined on Android API < 21,
* a.k.a. Lollipop. Since EPOLL_CLOEXEC is an alias for O_CLOEXEC on all
* architectures, we just use that instead.
*/
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
fd = -1;
errno = ENOSYS;
#else
fd = epoll_create1(O_CLOEXEC);
#endif
/* epoll_create1() can fail either because it's not implemented (old kernel)
* or because it doesn't understand the O_CLOEXEC flag.
......@@ -208,8 +198,10 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
* 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;
static int no_epoll_wait;
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;
......@@ -226,6 +218,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int fd;
int op;
int i;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
......@@ -281,7 +275,31 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
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.
*/
......@@ -293,25 +311,24 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
abort();
if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
nfds = -1;
errno = ENOSYS;
#else
nfds = epoll_pwait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout,
&sigset);
#endif
if (nfds == -1 && errno == ENOSYS)
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)
if (nfds == -1 && errno == ENOSYS) {
uv__store_relaxed(&no_epoll_wait_cached, 1);
no_epoll_wait = 1;
}
}
if (sigmask != 0 && no_epoll_pwait != 0)
......@@ -327,6 +344,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (nfds == 0) {
assert(timeout != -1);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
return;
......@@ -346,6 +371,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
......@@ -425,17 +455,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher)
if (w == &loop->signal_io_watcher) {
have_signals = 1;
else
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->events);
}
nevents++;
}
}
if (have_signals != 0)
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
......@@ -483,18 +522,22 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
/* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
* when it has microsecond granularity or better (unlikely).
*/
if (type == UV_CLOCK_FAST && fast_clock_id == -1) {
if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 &&
t.tv_nsec <= 1 * 1000 * 1000) {
fast_clock_id = CLOCK_MONOTONIC_COARSE;
} else {
fast_clock_id = CLOCK_MONOTONIC;
}
}
clock_id = CLOCK_MONOTONIC;
if (type != UV_CLOCK_FAST)
goto done;
clock_id = uv__load_relaxed(&fast_clock_id);
if (clock_id != -1)
goto done;
clock_id = CLOCK_MONOTONIC;
if (type == UV_CLOCK_FAST)
clock_id = fast_clock_id;
if (0 == clock_getres(CLOCK_MONOTONIC_COARSE, &t))
if (t.tv_nsec <= 1 * 1000 * 1000)
clock_id = CLOCK_MONOTONIC_COARSE;
uv__store_relaxed(&fast_clock_id, clock_id);
done:
if (clock_gettime(clock_id, &t))
return 0; /* Not really possible. */
......@@ -982,43 +1025,51 @@ void uv__set_process_title(const char* title) {
}
static uint64_t uv__read_proc_meminfo(const char* what) {
uint64_t rc;
static int uv__slurp(const char* filename, char* buf, size_t len) {
ssize_t n;
char* p;
int fd;
char buf[4096]; /* Large enough to hold all of /proc/meminfo. */
rc = 0;
fd = uv__open_cloexec("/proc/meminfo", O_RDONLY);
assert(len > 0);
fd = uv__open_cloexec(filename, O_RDONLY);
if (fd < 0)
return 0;
return fd;
n = read(fd, buf, sizeof(buf) - 1);
do
n = read(fd, buf, len - 1);
while (n == -1 && errno == EINTR);
if (n <= 0)
goto out;
if (uv__close_nocheckstdio(fd))
abort();
if (n < 0)
return UV__ERR(errno);
buf[n] = '\0';
p = strstr(buf, what);
if (p == NULL)
goto out;
return 0;
}
p += strlen(what);
if (1 != sscanf(p, "%" PRIu64 " kB", &rc))
goto out;
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;
rc *= 1024;
p = strstr(buf, what);
out:
if (p == NULL)
return 0;
if (uv__close_nocheckstdio(fd))
abort();
p += strlen(what);
return rc;
rc = 0;
sscanf(p, "%" PRIu64 " kB", &rc);
return rc * 1024;
}
......@@ -1056,28 +1107,13 @@ uint64_t uv_get_total_memory(void) {
static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) {
char filename[256];
uint64_t rc;
int fd;
ssize_t n;
char buf[32]; /* Large enough to hold an encoded uint64_t. */
snprintf(filename, 256, "/sys/fs/cgroup/%s/%s", cgroup, param);
uint64_t rc;
rc = 0;
fd = uv__open_cloexec(filename, O_RDONLY);
if (fd < 0)
return 0;
n = read(fd, buf, sizeof(buf) - 1);
if (n > 0) {
buf[n] = '\0';
snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/%s", cgroup, param);
if (0 == uv__slurp(filename, buf, sizeof(buf)))
sscanf(buf, "%" PRIu64, &rc);
}
if (uv__close_nocheckstdio(fd))
abort();
return rc;
}
......@@ -1091,3 +1127,20 @@ uint64_t uv_get_constrained_memory(void) {
*/
return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes");
}
void uv_loadavg(double avg[3]) {
struct sysinfo info;
char buf[128]; /* Large enough to hold all of /proc/loadavg. */
if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf)))
if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2]))
return;
if (sysinfo(&info) < 0)
return;
avg[0] = (double) info.loads[0] / 65536.0;
avg[1] = (double) info.loads[1] / 65536.0;
avg[2] = (double) info.loads[2] / 65536.0;
}
......@@ -37,8 +37,6 @@
#ifndef __NR_recvmmsg
# if defined(__x86_64__)
# define __NR_recvmmsg 299
# elif defined(__i386__)
# define __NR_recvmmsg 337
# elif defined(__arm__)
# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
# endif
......@@ -47,8 +45,6 @@
#ifndef __NR_sendmmsg
# if defined(__x86_64__)
# define __NR_sendmmsg 307
# elif defined(__i386__)
# define __NR_sendmmsg 345
# elif defined(__arm__)
# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
# endif
......@@ -94,6 +90,24 @@
# endif
#endif /* __NR_pwritev */
#ifndef __NR_copy_file_range
# if defined(__x86_64__)
# define __NR_copy_file_range 326
# elif defined(__i386__)
# define __NR_copy_file_range 377
# elif defined(__s390__)
# define __NR_copy_file_range 375
# elif defined(__arm__)
# define __NR_copy_file_range (UV_SYSCALL_BASE + 391)
# elif defined(__aarch64__)
# define __NR_copy_file_range 285
# elif defined(__powerpc__)
# define __NR_copy_file_range 379
# elif defined(__arc__)
# define __NR_copy_file_range 285
# endif
#endif /* __NR_copy_file_range */
#ifndef __NR_statx
# if defined(__x86_64__)
# define __NR_statx 332
......@@ -128,25 +142,51 @@
struct uv__mmsghdr;
int uv__sendmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags) {
#if defined(__NR_sendmmsg)
return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
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,
unsigned int flags,
struct timespec* timeout) {
#if defined(__NR_recvmmsg)
return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
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
......@@ -180,6 +220,28 @@ int uv__dup3(int oldfd, int newfd, int flags) {
}
ssize_t
uv__fs_copy_file_range(int fd_in,
ssize_t* off_in,
int fd_out,
ssize_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,
......
......@@ -64,6 +64,13 @@ struct uv__statx {
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,
ssize_t* off_in,
int fd_out,
ssize_t* off_out,
size_t len,
unsigned int flags);
int uv__statx(int dirfd,
const char* path,
int flags,
......
......@@ -28,6 +28,7 @@
#include <unistd.h>
int uv_loop_init(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
void* saved_data;
int err;
......@@ -36,6 +37,15 @@ int uv_loop_init(uv_loop_t* loop) {
memset(loop, 0, sizeof(*loop));
loop->data = saved_data;
lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
if (lfields == NULL)
return UV_ENOMEM;
loop->internal_fields = lfields;
err = uv_mutex_init(&lfields->loop_metrics.lock);
if (err)
goto fail_metrics_mutex_init;
heap_init((struct heap*) &loop->timer_heap);
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->idle_handles);
......@@ -66,7 +76,7 @@ int uv_loop_init(uv_loop_t* loop) {
err = uv__platform_loop_init(loop);
if (err)
return err;
goto fail_platform_init;
uv__signal_global_once_init();
err = uv_signal_init(loop, &loop->child_watcher);
......@@ -106,6 +116,13 @@ fail_rwlock_init:
fail_signal_init:
uv__platform_loop_delete(loop);
fail_platform_init:
uv_mutex_destroy(&lfields->loop_metrics.lock);
fail_metrics_mutex_init:
uv__free(lfields);
loop->internal_fields = NULL;
uv__free(loop->watchers);
loop->nwatchers = 0;
return err;
......@@ -146,6 +163,8 @@ int uv_loop_fork(uv_loop_t* loop) {
void uv__loop_close(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
uv__signal_loop_cleanup(loop);
uv__platform_loop_delete(loop);
uv__async_stop(loop);
......@@ -181,10 +200,23 @@ void uv__loop_close(uv_loop_t* loop) {
uv__free(loop->watchers);
loop->watchers = NULL;
loop->nwatchers = 0;
lfields = uv__get_internal_fields(loop);
uv_mutex_destroy(&lfields->loop_metrics.lock);
uv__free(lfields);
loop->internal_fields = NULL;
}
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
uv__loop_internal_fields_t* lfields;
lfields = uv__get_internal_fields(loop);
if (option == UV_METRICS_IDLE_TIME) {
lfields->flags |= UV_METRICS_IDLE_TIME;
return 0;
}
if (option != UV_LOOP_BLOCK_SIGNAL)
return UV_ENOSYS;
......
......@@ -33,7 +33,6 @@
#pragma linkage(BPX4CTW, OS)
#pragma linkage(BPX1CTW, OS)
static int number_of_epolls;
static QUEUE global_epoll_queue;
static uv_mutex_t global_epoll_lock;
static uv_once_t once = UV_ONCE_INIT;
......
......@@ -254,8 +254,6 @@ static int getexe(const int pid, char* buf, size_t len) {
int uv_exepath(char* buffer, size_t* size) {
int res;
char args[PATH_MAX];
char abspath[PATH_MAX];
size_t abspath_size;
int pid;
if (buffer == NULL || size == NULL || *size == 0)
......@@ -266,69 +264,7 @@ int uv_exepath(char* buffer, size_t* size) {
if (res < 0)
return UV_EINVAL;
/*
* Possibilities for args:
* i) an absolute path such as: /home/user/myprojects/nodejs/node
* ii) a relative path such as: ./node or ../myprojects/nodejs/node
* iii) a bare filename such as "node", after exporting PATH variable
* to its location.
*/
/* Case i) and ii) absolute or relative paths */
if (strchr(args, '/') != NULL) {
if (realpath(args, abspath) != abspath)
return UV__ERR(errno);
abspath_size = strlen(abspath);
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
return 0;
} else {
/* Case iii). Search PATH environment variable */
char trypath[PATH_MAX];
char* clonedpath = NULL;
char* token = NULL;
char* path = getenv("PATH");
if (path == NULL)
return UV_EINVAL;
clonedpath = uv__strdup(path);
if (clonedpath == NULL)
return UV_ENOMEM;
token = strtok(clonedpath, ":");
while (token != NULL) {
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
if (realpath(trypath, abspath) == abspath) {
/* Check the match is executable */
if (access(abspath, X_OK) == 0) {
abspath_size = strlen(abspath);
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
uv__free(clonedpath);
return 0;
}
}
token = strtok(NULL, ":");
}
uv__free(clonedpath);
/* Out of tokens (path entries), and no match found */
return UV_EINVAL;
}
return uv__search_path(args, buffer, size);
}
......@@ -818,6 +754,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int fd;
int op;
int i;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
......@@ -870,8 +808,22 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
real_timeout = timeout;
int nevents = 0;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
nfds = 0;
for (;;) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
timeout = max_safe_timeout;
......@@ -887,12 +839,21 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (nfds == 0) {
assert(timeout != -1);
if (timeout > 0) {
timeout = real_timeout - timeout;
continue;
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
return;
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) {
......@@ -900,6 +861,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
......@@ -954,6 +920,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
pe->events |= w->pevents & (POLLIN | POLLOUT);
if (pe->events != 0) {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->events);
nevents++;
}
......@@ -961,6 +928,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
......
......@@ -144,6 +144,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int have_signals;
struct pollfd* pe;
int fd;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
......@@ -177,11 +179,25 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
assert(timeout >= -1);
time_base = loop->time;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
/* Loop calls to poll() and processing of results. If we get some
* results from poll() but they turn out not to be interesting to
* our caller then we need to loop around and poll() again.
*/
for (;;) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
if (pset != NULL)
if (pthread_sigmask(SIG_BLOCK, pset, NULL))
abort();
......@@ -197,6 +213,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
if (timeout == -1)
continue;
if (timeout > 0)
goto update_timeout;
}
assert(timeout != -1);
return;
}
......@@ -205,6 +230,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
......@@ -254,6 +284,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (w == &loop->signal_io_watcher) {
have_signals = 1;
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->revents);
}
......@@ -261,8 +292,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
}
}
if (have_signals != 0)
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->poll_fds_iterating = 0;
......
......@@ -100,6 +100,10 @@ int uv_set_process_title(const char* title) {
struct uv__process_title* pt;
size_t len;
/* If uv_setup_args wasn't called or failed, we can't continue. */
if (args_mem == NULL)
return UV_ENOBUFS;
pt = &process_title;
len = strlen(title);
......@@ -126,6 +130,10 @@ int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return UV_EINVAL;
/* If uv_setup_args wasn't called or failed, we can't continue. */
if (args_mem == NULL)
return UV_ENOBUFS;
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
......
......@@ -30,6 +30,8 @@
*/
/* Android versions < 4.1 have a broken pthread_sigmask. */
#include "uv-common.h"
#include <errno.h>
#include <pthread.h>
#include <signal.h>
......@@ -38,13 +40,13 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
static int workaround;
int err;
if (workaround) {
if (uv__load_relaxed(&workaround)) {
return sigprocmask(how, set, oset);
} else {
err = pthread_sigmask(how, set, oset);
if (err) {
if (err == EINVAL && sigprocmask(how, set, oset) == 0) {
workaround = 1;
uv__store_relaxed(&workaround, 1);
return 0;
} else {
return -1;
......
/* 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 <string.h>
#include <sys/process.h>
#include <sys/neutrino.h>
#include <sys/memmsg.h>
#include <sys/syspage.h>
#include <sys/procfs.h>
static void
get_mem_info(uint64_t* totalmem, uint64_t* freemem) {
mem_info_t msg;
memset(&msg, 0, sizeof(msg));
msg.i.type = _MEM_INFO;
msg.i.fd = -1;
if (MsgSend(MEMMGR_COID, &msg.i, sizeof(msg.i), &msg.o, sizeof(msg.o))
!= -1) {
*totalmem = msg.o.info.__posix_tmi_total;
*freemem = msg.o.info.posix_tmi_length;
} else {
*totalmem = 0;
*freemem = 0;
}
}
void uv_loadavg(double avg[3]) {
avg[0] = 0.0;
avg[1] = 0.0;
avg[2] = 0.0;
}
int uv_exepath(char* buffer, size_t* size) {
char path[PATH_MAX];
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
realpath(_cmdname(NULL), path);
strlcpy(buffer, path, *size);
*size = strlen(buffer);
return 0;
}
uint64_t uv_get_free_memory(void) {
uint64_t totalmem;
uint64_t freemem;
get_mem_info(&totalmem, &freemem);
return freemem;
}
uint64_t uv_get_total_memory(void) {
uint64_t totalmem;
uint64_t freemem;
get_mem_info(&totalmem, &freemem);
return totalmem;
}
uint64_t uv_get_constrained_memory(void) {
return 0;
}
int uv_resident_set_memory(size_t* rss) {
int fd;
procfs_asinfo asinfo;
fd = uv__open_cloexec("/proc/self/ctl", O_RDONLY);
if (fd == -1)
return UV__ERR(errno);
if (devctl(fd, DCMD_PROC_ASINFO, &asinfo, sizeof(asinfo), 0) == -1) {
uv__close(fd);
return UV__ERR(errno);
}
uv__close(fd);
*rss = asinfo.rss;
return 0;
}
int uv_uptime(double* uptime) {
struct qtime_entry* qtime = _SYSPAGE_ENTRY(_syspage_ptr, qtime);
*uptime = (qtime->nsec / 1000000000.0);
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
struct cpuinfo_entry* cpuinfo =
(struct cpuinfo_entry*)_SYSPAGE_ENTRY(_syspage_ptr, new_cpuinfo);
size_t cpuinfo_size = _SYSPAGE_ELEMENT_SIZE(_syspage_ptr, cpuinfo);
struct strings_entry* strings = _SYSPAGE_ENTRY(_syspage_ptr, strings);
int num_cpus = _syspage_ptr->num_cpu;
int i;
*count = num_cpus;
*cpu_infos = uv__malloc(num_cpus * sizeof(**cpu_infos));
if (*cpu_infos == NULL)
return UV_ENOMEM;
for (i = 0; i < num_cpus; i++) {
(*cpu_infos)[i].model = strdup(&strings->data[cpuinfo->name]);
(*cpu_infos)[i].speed = cpuinfo->speed;
SYSPAGE_ARRAY_ADJ_OFFSET(cpuinfo, cpuinfo, cpuinfo_size);
}
return 0;
}
......@@ -143,6 +143,8 @@ static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
if (sigfillset(&new_mask))
abort();
/* to shut up valgrind */
sigemptyset(saved_sigmask);
if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
abort();
......
......@@ -154,6 +154,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
sigset_t set;
uint64_t base;
uint64_t diff;
uint64_t idle_poll;
unsigned int nfds;
unsigned int i;
int saved_errno;
......@@ -162,6 +163,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int count;
int err;
int fd;
int user_timeout;
int reset_timeout;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
......@@ -199,7 +202,21 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (;;) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
if (timeout != -1) {
spec.tv_sec = timeout / 1000;
spec.tv_nsec = (timeout % 1000) * 1000000;
......@@ -242,6 +259,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
SAVE_ERRNO(uv__update_time(loop));
if (events[0].portev_source == 0) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == 0)
return;
......@@ -282,10 +304,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher)
if (w == &loop->signal_io_watcher) {
have_signals = 1;
else
} else {
uv__metrics_update_idle_time(loop);
w->cb(loop, w, pe->portev_events);
}
nevents++;
......@@ -297,8 +321,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
}
if (have_signals != 0)
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (have_signals != 0) {
uv__metrics_update_idle_time(loop);
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
......
......@@ -326,16 +326,19 @@ 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 = -1;
static int single_accept_cached = -1;
unsigned long flags;
int single_accept;
int err;
if (tcp->delayed_error)
return tcp->delayed_error;
single_accept = uv__load_relaxed(&single_accept_cached);
if (single_accept == -1) {
const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
uv__store_relaxed(&single_accept_cached, single_accept);
}
if (single_accept)
......
......@@ -709,11 +709,9 @@ int uv_cond_init(uv_cond_t* cond) {
if (err)
return UV__ERR(err);
#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21)
err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
if (err)
goto error2;
#endif
err = pthread_cond_init(cond, &attr);
if (err)
......@@ -805,16 +803,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
#endif
ts.tv_sec = timeout / NANOSEC;
ts.tv_nsec = timeout % NANOSEC;
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
/*
* The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
* but has this alternative function instead.
*/
r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
#else
r = pthread_cond_timedwait(cond, mutex, &ts);
#endif /* __ANDROID_API__ */
#endif
......
......@@ -73,12 +73,12 @@ static void uv__udp_mmsg_init(void) {
s = uv__socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
return;
ret = uv__sendmmsg(s, NULL, 0, 0);
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, 0, NULL);
ret = uv__recvmmsg(s, NULL, 0);
if (ret == 0 || errno != ENOSYS)
uv__recvmmsg_avail = 1;
}
......@@ -213,7 +213,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
}
do
nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL);
nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks);
while (nread == -1 && errno == EINTR);
if (nread < 1) {
......@@ -238,7 +238,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
/* one last callback so the original buffer is freed */
if (handle->recv_cb != NULL)
handle->recv_cb(handle, 0, buf, NULL, 0);
handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE);
}
return nread;
}
......@@ -270,14 +270,11 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
assert(buf.base != NULL);
#if HAVE_MMSG
if (handle->flags & UV_HANDLE_UDP_RECVMMSG) {
uv_once(&once, uv__udp_mmsg_init);
if (uv__recvmmsg_avail) {
nread = uv__udp_recvmmsg(handle, &buf);
if (nread > 0)
count -= nread;
continue;
}
if (uv_udp_using_recvmmsg(handle)) {
nread = uv__udp_recvmmsg(handle, &buf);
if (nread > 0)
count -= nread;
continue;
}
#endif
......@@ -359,7 +356,7 @@ write_queue_drain:
}
do
npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts, 0);
npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts);
while (npkts == -1 && errno == EINTR);
if (npkts < 1) {
......@@ -367,7 +364,7 @@ write_queue_drain:
return;
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
i < pkts && q != &handle->write_queue;
++i, q = QUEUE_HEAD(q)) {
++i, q = QUEUE_HEAD(&handle->write_queue)) {
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
assert(req != NULL);
......@@ -854,7 +851,11 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
}
#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__)
#if !defined(__OpenBSD__) && \
!defined(__NetBSD__) && \
!defined(__ANDROID__) && \
!defined(__DragonFly__) & \
!defined(__QNX__)
static int uv__udp_set_source_membership4(uv_udp_t* handle,
const struct sockaddr_in* multicast_addr,
const char* interface_addr,
......@@ -976,6 +977,17 @@ int uv__udp_init_ex(uv_loop_t* loop,
}
int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
#if HAVE_MMSG
if (handle->flags & UV_HANDLE_UDP_RECVMMSG) {
uv_once(&once, uv__udp_mmsg_init);
return uv__recvmmsg_avail;
}
#endif
return 0;
}
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
int err;
......@@ -1031,7 +1043,11 @@ int uv_udp_set_source_membership(uv_udp_t* handle,
const char* interface_addr,
const char* source_addr,
uv_membership membership) {
#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__)
#if !defined(__OpenBSD__) && \
!defined(__NetBSD__) && \
!defined(__ANDROID__) && \
!defined(__DragonFly__) && \
!defined(__QNX__)
int err;
union uv__sockaddr mcast_addr;
union uv__sockaddr src_addr;
......@@ -1138,7 +1154,7 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
* and use the general uv__setsockopt_maybe_char call on other platforms.
*/
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
defined(__MVS__)
defined(__MVS__) || defined(__QNX__)
return uv__setsockopt(handle,
IP_TTL,
......@@ -1147,7 +1163,7 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
sizeof(ttl));
#else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
defined(__MVS__)) */
defined(__MVS__) || defined(__QNX__)) */
return uv__setsockopt_maybe_char(handle,
IP_TTL,
......@@ -1155,7 +1171,7 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
ttl);
#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
defined(__MVS__) */
defined(__MVS__) || defined(__QNX__) */
}
......@@ -1167,7 +1183,7 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
* and use the general uv__setsockopt_maybe_char call otherwise.
*/
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
defined(__MVS__)
defined(__MVS__) || defined(__QNX__)
if (handle->flags & UV_HANDLE_IPV6)
return uv__setsockopt(handle,
IP_MULTICAST_TTL,
......@@ -1175,7 +1191,7 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
&ttl,
sizeof(ttl));
#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
defined(__MVS__) */
defined(__MVS__) || defined(__QNX__) */
return uv__setsockopt_maybe_char(handle,
IP_MULTICAST_TTL,
......@@ -1192,7 +1208,7 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
* and use the general uv__setsockopt_maybe_char call otherwise.
*/
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
defined(__MVS__)
defined(__MVS__) || defined(__QNX__)
if (handle->flags & UV_HANDLE_IPV6)
return uv__setsockopt(handle,
IP_MULTICAST_LOOP,
......@@ -1200,7 +1216,7 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
&on,
sizeof(on));
#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) ||
defined(__MVS__) */
defined(__MVS__) || defined(__QNX__) */
return uv__setsockopt_maybe_char(handle,
IP_MULTICAST_LOOP,
......
......@@ -859,11 +859,70 @@ __attribute__((destructor))
void uv_library_shutdown(void) {
static int was_shutdown;
if (was_shutdown)
if (uv__load_relaxed(&was_shutdown))
return;
uv__process_title_cleanup();
uv__signal_cleanup();
uv__threadpool_cleanup();
was_shutdown = 1;
uv__store_relaxed(&was_shutdown, 1);
}
void uv__metrics_update_idle_time(uv_loop_t* loop) {
uv__loop_metrics_t* loop_metrics;
uint64_t entry_time;
uint64_t exit_time;
if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME))
return;
loop_metrics = uv__get_loop_metrics(loop);
/* The thread running uv__metrics_update_idle_time() is always the same
* thread that sets provider_entry_time. So it's unnecessary to lock before
* retrieving this value.
*/
if (loop_metrics->provider_entry_time == 0)
return;
exit_time = uv_hrtime();
uv_mutex_lock(&loop_metrics->lock);
entry_time = loop_metrics->provider_entry_time;
loop_metrics->provider_entry_time = 0;
loop_metrics->provider_idle_time += exit_time - entry_time;
uv_mutex_unlock(&loop_metrics->lock);
}
void uv__metrics_set_provider_entry_time(uv_loop_t* loop) {
uv__loop_metrics_t* loop_metrics;
uint64_t now;
if (!(uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME))
return;
now = uv_hrtime();
loop_metrics = uv__get_loop_metrics(loop);
uv_mutex_lock(&loop_metrics->lock);
loop_metrics->provider_entry_time = now;
uv_mutex_unlock(&loop_metrics->lock);
}
uint64_t uv_metrics_idle_time(uv_loop_t* loop) {
uv__loop_metrics_t* loop_metrics;
uint64_t entry_time;
uint64_t idle_time;
loop_metrics = uv__get_loop_metrics(loop);
uv_mutex_lock(&loop_metrics->lock);
idle_time = loop_metrics->provider_idle_time;
entry_time = loop_metrics->provider_entry_time;
uv_mutex_unlock(&loop_metrics->lock);
if (entry_time > 0)
idle_time += uv_hrtime() - entry_time;
return idle_time;
}
......@@ -60,6 +60,14 @@ extern int snprintf(char*, size_t, const char*, ...);
#define STATIC_ASSERT(expr) \
void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 7)
#define uv__load_relaxed(p) __atomic_load_n(p, __ATOMIC_RELAXED)
#define uv__store_relaxed(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED)
#else
#define uv__load_relaxed(p) (*p)
#define uv__store_relaxed(p, v) do *p = v; while (0)
#endif
/* Handle flags. Some flags are specific to Windows or UNIX. */
enum {
/* Used by all handles. */
......@@ -325,6 +333,12 @@ void uv__threadpool_cleanup(void);
} \
while (0)
#define uv__get_internal_fields(loop) \
((uv__loop_internal_fields_t*) loop->internal_fields)
#define uv__get_loop_metrics(loop) \
(&uv__get_internal_fields(loop)->loop_metrics)
/* Allocator prototypes */
void *uv__calloc(size_t count, size_t size);
char *uv__strdup(const char* s);
......@@ -334,4 +348,21 @@ void uv__free(void* ptr);
void* uv__realloc(void* ptr, size_t size);
void* uv__reallocf(void* ptr, size_t size);
typedef struct uv__loop_metrics_s uv__loop_metrics_t;
typedef struct uv__loop_internal_fields_s uv__loop_internal_fields_t;
struct uv__loop_metrics_s {
uint64_t provider_entry_time;
uint64_t provider_idle_time;
uv_mutex_t lock;
};
void uv__metrics_update_idle_time(uv_loop_t* loop);
void uv__metrics_set_provider_entry_time(uv_loop_t* loop);
struct uv__loop_internal_fields_s {
unsigned int flags;
uv__loop_metrics_t loop_metrics;
};
#endif /* UV_COMMON_H_ */
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
const char* uv_handle_type_name(uv_handle_type type) {
......
......@@ -222,6 +222,7 @@ static void uv_init(void) {
int uv_loop_init(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
struct heap* timer_heap;
int err;
......@@ -233,6 +234,15 @@ int uv_loop_init(uv_loop_t* loop) {
if (loop->iocp == NULL)
return uv_translate_sys_error(GetLastError());
lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
if (lfields == NULL)
return UV_ENOMEM;
loop->internal_fields = lfields;
err = uv_mutex_init(&lfields->loop_metrics.lock);
if (err)
goto fail_metrics_mutex_init;
/* To prevent uninitialized memory access, loop->time must be initialized
* to zero before calling uv_update_time for the first time.
*/
......@@ -297,6 +307,11 @@ fail_mutex_init:
loop->timer_heap = NULL;
fail_timers_alloc:
uv_mutex_destroy(&lfields->loop_metrics.lock);
fail_metrics_mutex_init:
uv__free(lfields);
loop->internal_fields = NULL;
CloseHandle(loop->iocp);
loop->iocp = INVALID_HANDLE_VALUE;
......@@ -317,6 +332,7 @@ void uv__once_init(void) {
void uv__loop_close(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
size_t i;
uv__loops_remove(loop);
......@@ -347,11 +363,24 @@ void uv__loop_close(uv_loop_t* loop) {
uv__free(loop->timer_heap);
loop->timer_heap = NULL;
lfields = uv__get_internal_fields(loop);
uv_mutex_destroy(&lfields->loop_metrics.lock);
uv__free(lfields);
loop->internal_fields = NULL;
CloseHandle(loop->iocp);
}
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
uv__loop_internal_fields_t* lfields;
lfields = uv__get_internal_fields(loop);
if (option == UV_METRICS_IDLE_TIME) {
lfields->flags |= UV_METRICS_IDLE_TIME;
return 0;
}
return UV_ENOSYS;
}
......@@ -393,16 +422,44 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
uv_req_t* req;
int repeat;
uint64_t timeout_time;
uint64_t user_timeout;
int reset_timeout;
timeout_time = loop->time + timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (repeat = 0; ; repeat++) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
GetQueuedCompletionStatus(loop->iocp,
&bytes,
&key,
&overlapped,
timeout);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
/* Placed here because on success the loop will break whether there is an
* empty package or not, or if GetQueuedCompletionStatus returned early then
* the timeout will be updated and the loop will run again. In either case
* the idle time will need to be updated.
*/
uv__metrics_update_idle_time(loop);
if (overlapped) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlapped);
......@@ -445,10 +502,26 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
ULONG i;
int repeat;
uint64_t timeout_time;
uint64_t user_timeout;
int reset_timeout;
timeout_time = loop->time + timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (repeat = 0; ; repeat++) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
success = pGetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
......@@ -456,6 +529,18 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
timeout,
FALSE);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
/* Placed here because on success the loop will break whether there is an
* empty package or not, or if GetQueuedCompletionStatus returned early then
* the timeout will be updated and the loop will run again. In either case
* the idle time will need to be updated.
*/
uv__metrics_update_idle_time(loop);
if (success) {
for (i = 0; i < count; i++) {
/* Package was dequeued, but see if it is not a empty package
......@@ -534,6 +619,12 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
else
uv__poll_wine(loop, timeout);
/* Run one final update on the provider_idle_time in case uv__poll*
* returned because the timeout expired, but no events were received. This
* call will be ignored if the provider_entry_time was either never set (if
* the timeout == 0) or was already updated b/c an event was received.
*/
uv__metrics_update_idle_time(loop);
uv_check_invoke(loop);
uv_process_endgames(loop);
......
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include "winapi.h"
......
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_WIN_FS_FD_HASH_INL_H_
#define UV_WIN_FS_FD_HASH_INL_H_
......@@ -53,7 +74,8 @@ static struct uv__fd_hash_bucket_s uv__fd_hash[UV__FD_HASH_SIZE];
INLINE static void uv__fd_hash_init(void) {
int i, err;
size_t i;
int err;
err = uv_mutex_init(&uv__fd_hash_mutex);
if (err) {
......
......@@ -70,10 +70,7 @@
#define SET_REQ_RESULT(req, result_value) \
do { \
req->result = (result_value); \
if (req->result == -1) { \
req->sys_errno_ = _doserrno; \
req->result = uv_translate_sys_error(req->sys_errno_); \
} \
assert(req->result != -1); \
} while (0)
#define SET_REQ_WIN32_ERROR(req, sys_errno) \
......@@ -730,14 +727,14 @@ void fs__close(uv_fs_t* req) {
assert(errno == EBADF);
SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE);
} else {
req->result = 0;
SET_REQ_RESULT(req, 0);
}
}
LONG fs__filemap_ex_filter(LONG excode, PEXCEPTION_POINTERS pep,
int* perror) {
if (excode != EXCEPTION_IN_PAGE_ERROR) {
if (excode != (LONG)EXCEPTION_IN_PAGE_ERROR) {
return EXCEPTION_CONTINUE_SEARCH;
}
......@@ -816,10 +813,10 @@ void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) {
for (index = 0;
index < req->fs.info.nbufs && done_read < read_size;
++index) {
int err = 0;
size_t this_read_size = MIN(req->fs.info.bufs[index].len,
read_size - done_read);
#ifdef _MSC_VER
int err = 0;
__try {
#endif
memcpy(req->fs.info.bufs[index].base,
......@@ -938,7 +935,7 @@ void fs__write_filemap(uv_fs_t* req, HANDLE file,
(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
size_t write_size, done_write;
unsigned int index;
LARGE_INTEGER zero, pos, end_pos;
LARGE_INTEGER pos, end_pos;
size_t view_offset;
LARGE_INTEGER view_base;
void* view;
......@@ -963,7 +960,6 @@ void fs__write_filemap(uv_fs_t* req, HANDLE file,
return;
}
zero.QuadPart = 0;
if (force_append) {
pos = fd_info->size;
} else if (req->fs.info.offset == -1) {
......@@ -1014,8 +1010,8 @@ void fs__write_filemap(uv_fs_t* req, HANDLE file,
done_write = 0;
for (index = 0; index < req->fs.info.nbufs; ++index) {
int err = 0;
#ifdef _MSC_VER
int err = 0;
__try {
#endif
memcpy((char*)view + view_offset + done_write,
......@@ -1128,7 +1124,10 @@ void fs__write(uv_fs_t* req) {
void fs__rmdir(uv_fs_t* req) {
int result = _wrmdir(req->file.pathw);
SET_REQ_RESULT(req, result);
if (result == -1)
SET_REQ_WIN32_ERROR(req, _doserrno);
else
SET_REQ_RESULT(req, 0);
}
......@@ -1221,12 +1220,12 @@ void fs__unlink(uv_fs_t* req) {
void fs__mkdir(uv_fs_t* req) {
/* TODO: use req->mode. */
req->result = _wmkdir(req->file.pathw);
if (req->result == -1) {
req->sys_errno_ = _doserrno;
req->result = req->sys_errno_ == ERROR_INVALID_NAME
? UV_EINVAL
: uv_translate_sys_error(req->sys_errno_);
if (CreateDirectoryW(req->file.pathw, NULL)) {
SET_REQ_RESULT(req, 0);
} else {
SET_REQ_WIN32_ERROR(req, GetLastError());
if (req->sys_errno_ == ERROR_INVALID_NAME)
req->result = UV_EINVAL;
}
}
......@@ -1242,19 +1241,21 @@ void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) {
unsigned int tries, i;
size_t len;
uint64_t v;
char* path;
path = req->path;
len = wcslen(req->file.pathw);
ep = req->file.pathw + len;
if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
return;
goto clobber;
}
tries = TMP_MAX;
do {
if (uv__random_rtlgenrandom((void *)&v, sizeof(v)) < 0) {
SET_REQ_UV_ERROR(req, UV_EIO, ERROR_IO_DEVICE);
break;
goto clobber;
}
cp = ep - num_x;
......@@ -1265,25 +1266,29 @@ void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) {
if (func(req)) {
if (req->result >= 0) {
len = strlen(req->path);
wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
len = strlen(path);
wcstombs(path + len - num_x, ep - num_x, num_x);
}
break;
return;
}
} while (--tries);
if (tries == 0) {
SET_REQ_RESULT(req, -1);
}
SET_REQ_WIN32_ERROR(req, GetLastError());
clobber:
path[0] = '\0';
}
static int fs__mkdtemp_func(uv_fs_t* req) {
if (_wmkdir(req->file.pathw) == 0) {
DWORD error;
if (CreateDirectoryW(req->file.pathw, NULL)) {
SET_REQ_RESULT(req, 0);
return 1;
} else if (errno != EEXIST) {
SET_REQ_RESULT(req, -1);
}
error = GetLastError();
if (error != ERROR_ALREADY_EXISTS) {
SET_REQ_WIN32_ERROR(req, error);
return 1;
}
......@@ -1404,7 +1409,7 @@ void fs__scandir(uv_fs_t* req) {
/* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER.
* This should be reported back as UV_ENOTDIR.
*/
if (status == STATUS_INVALID_PARAMETER)
if (status == (NTSTATUS)STATUS_INVALID_PARAMETER)
goto not_a_directory_error;
while (NT_SUCCESS(status)) {
......@@ -1895,7 +1900,7 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
}
req->ptr = &req->statbuf;
req->result = 0;
SET_REQ_RESULT(req, 0);
}
......@@ -1930,7 +1935,7 @@ static void fs__fstat(uv_fs_t* req) {
}
req->ptr = &req->statbuf;
req->result = 0;
SET_REQ_RESULT(req, 0);
}
......@@ -2157,7 +2162,10 @@ static void fs__access(uv_fs_t* req) {
static void fs__chmod(uv_fs_t* req) {
int result = _wchmod(req->file.pathw, req->fs.info.mode);
SET_REQ_RESULT(req, result);
if (result == -1)
SET_REQ_WIN32_ERROR(req, _doserrno);
else
SET_REQ_RESULT(req, 0);
}
......@@ -2315,7 +2323,7 @@ INLINE static void fs__utime_impl(uv_fs_t* req, int do_lutime) {
return;
}
req->result = 0;
SET_REQ_RESULT(req, 0);
}
static void fs__utime(uv_fs_t* req) {
......@@ -2340,7 +2348,7 @@ static void fs__futime(uv_fs_t* req) {
return;
}
req->result = 0;
SET_REQ_RESULT(req, 0);
}
static void fs__lutime(uv_fs_t* req) {
......@@ -2350,11 +2358,10 @@ static void fs__lutime(uv_fs_t* req) {
static void fs__link(uv_fs_t* req) {
DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
if (r == 0) {
if (r == 0)
SET_REQ_WIN32_ERROR(req, GetLastError());
} else {
req->result = 0;
}
else
SET_REQ_RESULT(req, 0);
}
......@@ -2674,17 +2681,17 @@ static void fs__realpath(uv_fs_t* req) {
static void fs__chown(uv_fs_t* req) {
req->result = 0;
SET_REQ_RESULT(req, 0);
}
static void fs__fchown(uv_fs_t* req) {
req->result = 0;
SET_REQ_RESULT(req, 0);
}
static void fs__lchown(uv_fs_t* req) {
req->result = 0;
SET_REQ_RESULT(req, 0);
}
......@@ -2829,7 +2836,7 @@ static void uv__fs_done(struct uv__work* w, int status) {
if (status == UV_ECANCELED) {
assert(req->result == 0);
req->result = UV_ECANCELED;
SET_REQ_UV_ERROR(req, UV_ECANCELED, 0);
}
req->cb(req);
......
......@@ -266,7 +266,7 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
*/
void uv__util_init(void);
uint64_t uv__hrtime(double scale);
uint64_t uv__hrtime(unsigned int scale);
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
......
......@@ -244,9 +244,8 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
return 0;
error:
if (pipeHandle != INVALID_HANDLE_VALUE) {
if (pipeHandle != INVALID_HANDLE_VALUE)
CloseHandle(pipeHandle);
}
return err;
}
......@@ -554,7 +553,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
/* Convert name to UTF16. */
nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
handle->name = (WCHAR*)uv__malloc(nameSize);
handle->name = uv__malloc(nameSize);
if (!handle->name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
......@@ -621,9 +620,8 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
while (WaitNamedPipeW(handle->name, 30000)) {
/* The pipe is now available, try to connect. */
pipeHandle = open_named_pipe(handle->name, &duplex_flags);
if (pipeHandle != INVALID_HANDLE_VALUE) {
if (pipeHandle != INVALID_HANDLE_VALUE)
break;
}
SwitchToThread();
}
......@@ -655,7 +653,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
/* Convert name to UTF16. */
nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
handle->name = (WCHAR*)uv__malloc(nameSize);
handle->name = uv__malloc(nameSize);
if (!handle->name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
......@@ -2147,7 +2145,7 @@ 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();
assert(pipe->pipe.conn.ipc_remote_pid != (DWORD) -1);
assert(pipe->pipe.conn.ipc_remote_pid != (DWORD)(uv_pid_t) -1);
}
return 0;
}
......
......@@ -523,16 +523,15 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
&req->u.io.overlapped,
NULL);
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
/* Process the req without IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
req->u.io.overlapped.InternalHigh = bytes;
handle->reqs_pending++;
uv_insert_pending_req(loop, (uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* The req will be processed with IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
req->wait_handle == INVALID_HANDLE_VALUE &&
!RegisterWaitForSingleObject(&req->wait_handle,
......@@ -545,7 +544,6 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
/* Make this req pending reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req);
handle->reqs_pending++;
}
}
......@@ -750,6 +748,40 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
return 0;
}
static int uv__is_loopback(const struct sockaddr_storage* storage) {
const struct sockaddr_in* in4;
const struct sockaddr_in6* in6;
int i;
if (storage->ss_family == AF_INET) {
in4 = (const struct sockaddr_in*) storage;
return in4->sin_addr.S_un.S_un_b.s_b1 == 127;
}
if (storage->ss_family == AF_INET6) {
in6 = (const struct sockaddr_in6*) storage;
for (i = 0; i < 7; ++i) {
if (in6->sin6_addr.u.Word[i] != 0)
return 0;
}
return in6->sin6_addr.u.Word[7] == htons(1);
}
return 0;
}
// Check if Windows version is 10.0.16299 or later
static int uv__is_fast_loopback_fail_supported() {
OSVERSIONINFOW os_info;
if (!pRtlGetVersion)
return 0;
pRtlGetVersion(&os_info);
if (os_info.dwMajorVersion < 10)
return 0;
if (os_info.dwMajorVersion > 10)
return 1;
if (os_info.dwMinorVersion > 0)
return 1;
return os_info.dwBuildNumber >= 16299;
}
static int uv_tcp_try_connect(uv_connect_t* req,
uv_tcp_t* handle,
......@@ -757,6 +789,7 @@ static int uv_tcp_try_connect(uv_connect_t* req,
unsigned int addrlen,
uv_connect_cb cb) {
uv_loop_t* loop = handle->loop;
TCP_INITIAL_RTO_PARAMETERS retransmit_ioctl;
const struct sockaddr* bind_addr;
struct sockaddr_storage converted;
BOOL success;
......@@ -792,6 +825,25 @@ static int uv_tcp_try_connect(uv_connect_t* req,
}
}
/* This makes connect() fail instantly if the target port on the localhost
* is not reachable, instead of waiting for 2s. We do not care if this fails.
* This only works on Windows version 10.0.16299 and later.
*/
if (uv__is_fast_loopback_fail_supported() && uv__is_loopback(&converted)) {
memset(&retransmit_ioctl, 0, sizeof(retransmit_ioctl));
retransmit_ioctl.Rtt = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS;
retransmit_ioctl.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS;
WSAIoctl(handle->socket,
SIO_TCP_INITIAL_RTO,
&retransmit_ioctl,
sizeof(retransmit_ioctl),
NULL,
0,
&bytes,
NULL,
NULL);
}
UV_REQ_INIT(req, UV_CONNECT);
req->handle = (uv_stream_t*) handle;
req->cb = cb;
......
......@@ -517,6 +517,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
if (status == TRAP_REQUESTED) {
SET_REQ_SUCCESS(req);
InterlockedExchange(&uv__read_console_status, COMPLETED);
req->u.io.overlapped.InternalHigh = 0;
POST_COMPLETION_FOR_REQ(loop, req);
return 0;
......@@ -2121,13 +2122,6 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
abort();
}
/* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the windows
* console doesn't really support UTF-16, so just emit the replacement
* character. */
if (utf8_codepoint > 0xffff) {
utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
}
if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
/* EOL conversion - emit \r\n when we see \n. */
......@@ -2154,6 +2148,12 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
ENSURE_BUFFER_SPACE(1);
utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
previous_eol = 0;
} else {
ENSURE_BUFFER_SPACE(2);
utf8_codepoint -= 0x10000;
utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint / 0x400 + 0xD800);
utf16_buf[utf16_buf_used++] = (WCHAR) (utf8_codepoint % 0x400 + 0xDC00);
previous_eol = 0;
}
}
}
......@@ -2412,6 +2412,7 @@ static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) {
uv__tty_console_signal_resize();
ResetEvent(uv__tty_console_resized);
}
return 0;
}
static void uv__tty_console_signal_resize(void) {
......
......@@ -189,6 +189,11 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
}
int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
return 0;
}
static int uv_udp_maybe_bind(uv_udp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen,
......@@ -752,6 +757,9 @@ int uv__udp_set_source_membership6(uv_udp_t* handle,
int optname;
int err;
STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
return UV_EINVAL;
......@@ -774,8 +782,6 @@ int uv__udp_set_source_membership6(uv_udp_t* handle,
mreq.gsr_interface = 0;
}
// STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
// STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
......@@ -846,7 +852,7 @@ int uv_udp_set_source_membership(uv_udp_t* handle,
src_addr6,
membership);
}
err = uv_ip4_addr(source_addr, 0, src_addr4);
if (err)
return err;
......@@ -1067,7 +1073,7 @@ int uv__udp_connect(uv_udp_t* handle,
err = connect(handle->socket, addr, addrlen);
if (err)
return uv_translate_sys_error(err);
return uv_translate_sys_error(WSAGetLastError());
handle->flags |= UV_HANDLE_UDP_CONNECTED;
......@@ -1083,7 +1089,7 @@ int uv__udp_disconnect(uv_udp_t* handle) {
err = connect(handle->socket, &addr, sizeof(addr));
if (err)
return uv_translate_sys_error(err);
return uv_translate_sys_error(WSAGetLastError());
handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
return 0;
......
......@@ -30,12 +30,14 @@
#include "uv.h"
#include "internal.h"
/* clang-format off */
#include <winsock2.h>
#include <winperf.h>
#include <iphlpapi.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <windows.h>
/* clang-format on */
#include <userenv.h>
#include <math.h>
......@@ -67,8 +69,8 @@ extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
static char *process_title;
static CRITICAL_SECTION process_title_lock;
/* Interval (in seconds) of the high-resolution clock. */
static double hrtime_interval_ = 0;
/* Frequency of the high-resolution clock. */
static uint64_t hrtime_frequency_ = 0;
/*
......@@ -84,9 +86,9 @@ void uv__util_init(void) {
* and precompute its reciprocal.
*/
if (QueryPerformanceFrequency(&perf_frequency)) {
hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
hrtime_frequency_ = perf_frequency.QuadPart;
} else {
hrtime_interval_= 0;
uv_fatal_error(GetLastError(), "QueryPerformanceFrequency");
}
}
......@@ -490,23 +492,25 @@ uint64_t uv_hrtime(void) {
return uv__hrtime(UV__NANOSEC);
}
uint64_t uv__hrtime(double scale) {
uint64_t uv__hrtime(unsigned int scale) {
LARGE_INTEGER counter;
double scaled_freq;
double result;
/* If the performance interval is zero, there's no support. */
if (hrtime_interval_ == 0) {
return 0;
}
assert(hrtime_frequency_ != 0);
assert(scale != 0);
if (!QueryPerformanceCounter(&counter)) {
return 0;
uv_fatal_error(GetLastError(), "QueryPerformanceCounter");
}
assert(counter.QuadPart != 0);
/* Because we have no guarantee about the order of magnitude of the
* performance counter interval, integer math could cause this computation
* to overflow. Therefore we resort to floating point math.
*/
return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale);
scaled_freq = (double) hrtime_frequency_ / scale;
result = (double) counter.QuadPart / scaled_freq;
return (uint64_t) result;
}
......@@ -1804,7 +1808,9 @@ int uv_os_uname(uv_utsname_t* buffer) {
pRtlGetVersion(&os_info);
} else {
/* Silence GetVersionEx() deprecation warning. */
#ifdef _MSC_VER
#pragma warning(suppress : 4996)
#endif
if (GetVersionExW(&os_info) == 0) {
r = uv_translate_sys_error(GetLastError());
goto error;
......@@ -1871,7 +1877,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
"MINGW32_NT-%u.%u",
(unsigned int) os_info.dwMajorVersion,
(unsigned int) os_info.dwMinorVersion);
assert(r < sizeof(buffer->sysname));
assert((size_t)r < sizeof(buffer->sysname));
#else
uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
#endif
......@@ -1883,7 +1889,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
(unsigned int) os_info.dwMajorVersion,
(unsigned int) os_info.dwMinorVersion,
(unsigned int) os_info.dwBuildNumber);
assert(r < sizeof(buffer->release));
assert((size_t)r < sizeof(buffer->release));
/* Populate the machine field. */
GetSystemInfo(&system_info);
......
......@@ -4726,6 +4726,18 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
DWORD idThread,
UINT dwflags);
/* From mstcpip.h */
typedef struct _TCP_INITIAL_RTO_PARAMETERS {
USHORT Rtt;
UCHAR MaxSynRetransmissions;
} TCP_INITIAL_RTO_PARAMETERS, *PTCP_INITIAL_RTO_PARAMETERS;
#ifndef TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS
# define TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS ((UCHAR) -2)
#endif
#ifndef SIO_TCP_INITIAL_RTO
# define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17)
#endif
/* Ntdll function pointers */
extern sRtlGetVersion pRtlGetVersion;
......
Update the embedded libuv from 1.38.0 to 1.40.0.
......@@ -160,7 +160,7 @@ if sys.platform.startswith('linux'):
_libuv_source('unix/linux-syscalls.c'),
_libuv_source('unix/procfs-exepath.c'),
_libuv_source('unix/proctitle.c'),
_libuv_source('unix/sysinfo-loadavg.c'),
_libuv_source('unix/random-sysctl-linux.c'),
]
elif sys.platform == 'darwin':
LIBUV_SOURCES += [
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment