summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE4
-rw-r--r--include/pthread-barrier.h1
-rw-r--r--include/uv-errno.h12
-rw-r--r--include/uv-os390.h3
-rw-r--r--include/uv-unix.h96
-rw-r--r--include/uv-version.h2
-rw-r--r--include/uv-win.h28
-rw-r--r--include/uv.h63
-rw-r--r--src/threadpool.c18
-rw-r--r--src/unix/aix-common.c292
-rw-r--r--src/unix/aix.c242
-rw-r--r--src/unix/android-ifaddrs.c49
-rw-r--r--src/unix/atomic-ops.h5
-rw-r--r--src/unix/bsd-ifaddrs.c23
-rw-r--r--src/unix/core.c45
-rw-r--r--src/unix/freebsd.c87
-rw-r--r--src/unix/fs.c177
-rw-r--r--src/unix/fsevents.c28
-rw-r--r--src/unix/getaddrinfo.c30
-rw-r--r--src/unix/ibmi.c112
-rw-r--r--src/unix/internal.h15
-rw-r--r--src/unix/kqueue.c38
-rw-r--r--src/unix/linux-core.c14
-rw-r--r--src/unix/loop.c2
-rw-r--r--src/unix/netbsd.c57
-rw-r--r--src/unix/openbsd.c33
-rw-r--r--src/unix/os390-syscalls.c229
-rw-r--r--src/unix/os390-syscalls.h3
-rw-r--r--src/unix/os390.c175
-rw-r--r--src/unix/pipe.c53
-rw-r--r--src/unix/poll.c25
-rw-r--r--src/unix/process.c42
-rw-r--r--src/unix/proctitle.c35
-rw-r--r--src/unix/pthread-barrier.c121
-rw-r--r--src/unix/signal.c7
-rw-r--r--src/unix/stream.c39
-rw-r--r--src/unix/sunos.c4
-rw-r--r--src/unix/tcp.c101
-rw-r--r--src/unix/thread.c197
-rw-r--r--src/unix/tty.c36
-rw-r--r--src/unix/udp.c8
-rw-r--r--src/uv-data-getter-setters.c96
-rw-r--r--src/win/dl.c55
-rw-r--r--src/win/error.c2
-rw-r--r--src/win/fs.c581
-rw-r--r--src/win/getaddrinfo.c71
-rw-r--r--src/win/handle.c5
-rw-r--r--src/win/internal.h1
-rw-r--r--src/win/pipe.c137
-rw-r--r--src/win/process.c31
-rw-r--r--src/win/signal.c2
-rw-r--r--src/win/stream-inl.h3
-rw-r--r--src/win/tcp.c32
-rw-r--r--src/win/thread.c6
-rw-r--r--src/win/timer.c2
-rw-r--r--src/win/tty.c121
-rw-r--r--src/win/udp.c51
-rw-r--r--src/win/util.c11
-rw-r--r--src/win/winapi.c10
-rw-r--r--src/win/winapi.h26
-rw-r--r--src/win/winsock.c28
-rw-r--r--src/win/winsock.h3
62 files changed, 2806 insertions, 1019 deletions
diff --git a/LICENSE b/LICENSE
index 41ba44c285..28f17339e2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -62,8 +62,8 @@ The externally maintained libraries used by libuv are:
- stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three
clause BSD license.
- - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile
- Communications AB. Three clause BSD license.
+ - pthread-fixes.c, copyright Google Inc. and Sony Mobile Communications AB.
+ Three clause BSD license.
- android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design
Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement
diff --git a/include/pthread-barrier.h b/include/pthread-barrier.h
index 900ebedd30..07db9b8a6a 100644
--- a/include/pthread-barrier.h
+++ b/include/pthread-barrier.h
@@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#endif
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
+#define UV__PTHREAD_BARRIER_FALLBACK 1
/*
* To maintain ABI compatibility with
diff --git a/include/uv-errno.h b/include/uv-errno.h
index f1371517cc..8a41533147 100644
--- a/include/uv-errno.h
+++ b/include/uv-errno.h
@@ -416,4 +416,16 @@
# define UV__EHOSTDOWN (-4031)
#endif
+#if defined(EREMOTEIO) && !defined(_WIN32)
+# define UV__EREMOTEIO (-EREMOTEIO)
+#else
+# define UV__EREMOTEIO (-4030)
+#endif
+
+#if defined(ENOTTY) && !defined(_WIN32)
+# define UV__ENOTTY (-ENOTTY)
+#else
+# define UV__ENOTTY (-4029)
+#endif
+
#endif /* UV_ERRNO_H_ */
diff --git a/include/uv-os390.h b/include/uv-os390.h
index 58f926111a..39e7384db3 100644
--- a/include/uv-os390.h
+++ b/include/uv-os390.h
@@ -27,4 +27,7 @@
#define UV_PLATFORM_LOOP_FIELDS \
void* ep; \
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ char rfis_rftok[8]; \
+
#endif /* UV_MVS_H */
diff --git a/include/uv-unix.h b/include/uv-unix.h
index d7754509b1..da32f86e84 100644
--- a/include/uv-unix.h
+++ b/include/uv-unix.h
@@ -48,6 +48,8 @@
# include "uv-linux.h"
#elif defined (__MVS__)
# include "uv-os390.h"
+#elif defined(_PASE)
+# include "uv-posix.h"
#elif defined(_AIX)
# include "uv-aix.h"
#elif defined(__sun)
@@ -123,6 +125,7 @@ typedef struct uv_buf_t {
typedef int uv_file;
typedef int uv_os_sock_t;
typedef int uv_os_fd_t;
+typedef pid_t uv_pid_t;
#define UV_ONCE_INIT PTHREAD_ONCE_INIT
@@ -365,4 +368,97 @@ typedef struct {
uv_fs_event_cb cb; \
UV_PLATFORM_FS_EVENT_FIELDS \
+/* fs open() flags supported on this platform: */
+#if defined(O_APPEND)
+# define UV_FS_O_APPEND O_APPEND
+#else
+# define UV_FS_O_APPEND 0
+#endif
+#if defined(O_CREAT)
+# define UV_FS_O_CREAT O_CREAT
+#else
+# define UV_FS_O_CREAT 0
+#endif
+#if defined(O_DIRECT)
+# define UV_FS_O_DIRECT O_DIRECT
+#else
+# define UV_FS_O_DIRECT 0
+#endif
+#if defined(O_DIRECTORY)
+# define UV_FS_O_DIRECTORY O_DIRECTORY
+#else
+# define UV_FS_O_DIRECTORY 0
+#endif
+#if defined(O_DSYNC)
+# define UV_FS_O_DSYNC O_DSYNC
+#else
+# define UV_FS_O_DSYNC 0
+#endif
+#if defined(O_EXCL)
+# define UV_FS_O_EXCL O_EXCL
+#else
+# define UV_FS_O_EXCL 0
+#endif
+#if defined(O_EXLOCK)
+# define UV_FS_O_EXLOCK O_EXLOCK
+#else
+# define UV_FS_O_EXLOCK 0
+#endif
+#if defined(O_NOATIME)
+# define UV_FS_O_NOATIME O_NOATIME
+#else
+# define UV_FS_O_NOATIME 0
+#endif
+#if defined(O_NOCTTY)
+# define UV_FS_O_NOCTTY O_NOCTTY
+#else
+# define UV_FS_O_NOCTTY 0
+#endif
+#if defined(O_NOFOLLOW)
+# define UV_FS_O_NOFOLLOW O_NOFOLLOW
+#else
+# define UV_FS_O_NOFOLLOW 0
+#endif
+#if defined(O_NONBLOCK)
+# define UV_FS_O_NONBLOCK O_NONBLOCK
+#else
+# define UV_FS_O_NONBLOCK 0
+#endif
+#if defined(O_RDONLY)
+# define UV_FS_O_RDONLY O_RDONLY
+#else
+# define UV_FS_O_RDONLY 0
+#endif
+#if defined(O_RDWR)
+# define UV_FS_O_RDWR O_RDWR
+#else
+# define UV_FS_O_RDWR 0
+#endif
+#if defined(O_SYMLINK)
+# define UV_FS_O_SYMLINK O_SYMLINK
+#else
+# define UV_FS_O_SYMLINK 0
+#endif
+#if defined(O_SYNC)
+# define UV_FS_O_SYNC O_SYNC
+#else
+# define UV_FS_O_SYNC 0
+#endif
+#if defined(O_TRUNC)
+# define UV_FS_O_TRUNC O_TRUNC
+#else
+# define UV_FS_O_TRUNC 0
+#endif
+#if defined(O_WRONLY)
+# define UV_FS_O_WRONLY O_WRONLY
+#else
+# define UV_FS_O_WRONLY 0
+#endif
+
+/* fs open() flags supported on other platforms: */
+#define UV_FS_O_RANDOM 0
+#define UV_FS_O_SHORT_LIVED 0
+#define UV_FS_O_SEQUENTIAL 0
+#define UV_FS_O_TEMPORARY 0
+
#endif /* UV_UNIX_H */
diff --git a/include/uv-version.h b/include/uv-version.h
index e16580903c..1dc63e57c1 100644
--- a/include/uv-version.h
+++ b/include/uv-version.h
@@ -31,7 +31,7 @@
*/
#define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 11
+#define UV_VERSION_MINOR 19
#define UV_VERSION_PATCH 1
#define UV_VERSION_IS_RELEASE 0
#define UV_VERSION_SUFFIX "dev"
diff --git a/include/uv-win.h b/include/uv-win.h
index 9677ff164b..4c6c50a29c 100644
--- a/include/uv-win.h
+++ b/include/uv-win.h
@@ -20,7 +20,7 @@
*/
#ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0502
+# define _WIN32_WINNT 0x0600
#endif
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
@@ -222,6 +222,7 @@ typedef struct uv_buf_t {
typedef int uv_file;
typedef SOCKET uv_os_sock_t;
typedef HANDLE uv_os_fd_t;
+typedef int uv_pid_t;
typedef HANDLE uv_thread_t;
@@ -648,3 +649,28 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
#ifndef X_OK
#define X_OK 1
#endif
+
+/* fs open() flags supported on this platform: */
+#define UV_FS_O_APPEND _O_APPEND
+#define UV_FS_O_CREAT _O_CREAT
+#define UV_FS_O_EXCL _O_EXCL
+#define UV_FS_O_RANDOM _O_RANDOM
+#define UV_FS_O_RDONLY _O_RDONLY
+#define UV_FS_O_RDWR _O_RDWR
+#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL
+#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED
+#define UV_FS_O_TEMPORARY _O_TEMPORARY
+#define UV_FS_O_TRUNC _O_TRUNC
+#define UV_FS_O_WRONLY _O_WRONLY
+
+/* fs open() flags supported on other platforms (or mapped on this platform): */
+#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */
+#define UV_FS_O_DIRECTORY 0
+#define UV_FS_O_DSYNC 0x04000000 /* FILE_FLAG_WRITE_THROUGH */
+#define UV_FS_O_EXLOCK 0x10000000 /* EXCLUSIVE SHARING MODE */
+#define UV_FS_O_NOATIME 0
+#define UV_FS_O_NOCTTY 0
+#define UV_FS_O_NOFOLLOW 0
+#define UV_FS_O_NONBLOCK 0
+#define UV_FS_O_SYMLINK 0
+#define UV_FS_O_SYNC 0x08000000 /* FILE_FLAG_WRITE_THROUGH */
diff --git a/include/uv.h b/include/uv.h
index 40f5a4bd53..3a061132cc 100644
--- a/include/uv.h
+++ b/include/uv.h
@@ -140,6 +140,8 @@ extern "C" {
XX(ENXIO, "no such device or address") \
XX(EMLINK, "too many links") \
XX(EHOSTDOWN, "host is down") \
+ XX(EREMOTEIO, "remote I/O error") \
+ XX(ENOTTY, "inappropriate ioctl for device") \
#define UV_HANDLE_TYPE_MAP(XX) \
XX(ASYNC, async) \
@@ -423,7 +425,17 @@ struct uv_handle_s {
};
UV_EXTERN size_t uv_handle_size(uv_handle_type type);
+UV_EXTERN uv_handle_type uv_handle_get_type(const uv_handle_t* handle);
+UV_EXTERN const char* uv_handle_type_name(uv_handle_type type);
+UV_EXTERN void* uv_handle_get_data(const uv_handle_t* handle);
+UV_EXTERN uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle);
+UV_EXTERN void uv_handle_set_data(uv_handle_t* handle, void* data);
+
UV_EXTERN size_t uv_req_size(uv_req_type type);
+UV_EXTERN void* uv_req_get_data(const uv_req_t* req);
+UV_EXTERN void uv_req_set_data(uv_req_t* req, void* data);
+UV_EXTERN uv_req_type uv_req_get_type(const uv_req_t* req);
+UV_EXTERN const char* uv_req_type_name(uv_req_type type);
UV_EXTERN int uv_is_active(const uv_handle_t* handle);
@@ -463,6 +475,8 @@ struct uv_stream_s {
UV_STREAM_FIELDS
};
+UV_EXTERN size_t uv_stream_get_write_queue_size(const uv_stream_t* stream);
+
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
@@ -640,6 +654,8 @@ 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_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);
/*
@@ -708,6 +724,7 @@ UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle,
UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
+UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags);
struct uv_poll_s {
@@ -719,7 +736,8 @@ struct uv_poll_s {
enum uv_poll_event {
UV_READABLE = 1,
UV_WRITABLE = 2,
- UV_DISCONNECT = 4
+ UV_DISCONNECT = 4,
+ UV_PRIORITIZED = 8
};
UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
@@ -958,6 +976,7 @@ UV_EXTERN int uv_spawn(uv_loop_t* loop,
const uv_process_options_t* options);
UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
UV_EXTERN int uv_kill(int pid, int signum);
+UV_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*);
/*
@@ -1034,6 +1053,7 @@ UV_EXTERN int uv_get_process_title(char* buffer, size_t size);
UV_EXTERN int uv_set_process_title(const char* title);
UV_EXTERN int uv_resident_set_memory(size_t* rss);
UV_EXTERN int uv_uptime(double* uptime);
+UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd);
typedef struct {
long tv_sec;
@@ -1065,6 +1085,8 @@ UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd);
UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
+UV_EXTERN uv_pid_t uv_os_getpid(void);
+UV_EXTERN uv_pid_t uv_os_getppid(void);
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
@@ -1111,7 +1133,8 @@ typedef enum {
UV_FS_READLINK,
UV_FS_CHOWN,
UV_FS_FCHOWN,
- UV_FS_REALPATH
+ UV_FS_REALPATH,
+ UV_FS_COPYFILE
} uv_fs_type;
/* uv_fs_t is a subclass of uv_req_t. */
@@ -1127,6 +1150,12 @@ struct uv_fs_s {
UV_FS_PRIVATE_FIELDS
};
+UV_EXTERN uv_fs_type uv_fs_get_type(const uv_fs_t*);
+UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*);
+UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*);
+UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*);
+UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*);
+
UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req);
UV_EXTERN int uv_fs_close(uv_loop_t* loop,
uv_fs_t* req,
@@ -1156,6 +1185,18 @@ UV_EXTERN int uv_fs_write(uv_loop_t* loop,
unsigned int nbufs,
int64_t offset,
uv_fs_cb cb);
+/*
+ * This flag can be used with uv_fs_copyfile() to return an error if the
+ * destination already exists.
+ */
+#define UV_FS_COPYFILE_EXCL 0x0001
+
+UV_EXTERN int uv_fs_copyfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb);
UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
@@ -1389,6 +1430,21 @@ UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size
UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
+#if defined(IF_NAMESIZE)
+# define UV_IF_NAMESIZE (IF_NAMESIZE + 1)
+#elif defined(IFNAMSIZ)
+# define UV_IF_NAMESIZE (IFNAMSIZ + 1)
+#else
+# define UV_IF_NAMESIZE (16 + 1)
+#endif
+
+UV_EXTERN int uv_if_indextoname(unsigned int ifindex,
+ char* buffer,
+ size_t* size);
+UV_EXTERN int uv_if_indextoiid(unsigned int ifindex,
+ char* buffer,
+ size_t* size);
+
UV_EXTERN int uv_exepath(char* buffer, size_t* size);
UV_EXTERN int uv_cwd(char* buffer, size_t* size);
@@ -1408,6 +1464,7 @@ UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
UV_EXTERN int uv_mutex_init(uv_mutex_t* handle);
+UV_EXTERN int uv_mutex_init_recursive(uv_mutex_t* handle);
UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);
UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle);
UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle);
@@ -1480,6 +1537,8 @@ struct uv_loop_s {
UV_LOOP_PRIVATE_FIELDS
};
+UV_EXTERN void* uv_loop_get_data(const uv_loop_t*);
+UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
/* Don't export the private CPP symbols. */
#undef UV_HANDLE_TYPE_PRIVATE
diff --git a/src/threadpool.c b/src/threadpool.c
index 108934112c..413d1c204c 100644
--- a/src/threadpool.c
+++ b/src/threadpool.c
@@ -38,7 +38,6 @@ static uv_thread_t* threads;
static uv_thread_t default_threads[4];
static QUEUE exit_message;
static QUEUE wq;
-static volatile int initialized;
static void uv__cancelled(struct uv__work* w) {
@@ -53,7 +52,8 @@ static void worker(void* arg) {
struct uv__work* w;
QUEUE* q;
- (void) arg;
+ uv_sem_post((uv_sem_t*) arg);
+ arg = NULL;
for (;;) {
uv_mutex_lock(&mutex);
@@ -105,7 +105,7 @@ static void post(QUEUE* q) {
UV_DESTRUCTOR(static void cleanup(void)) {
unsigned int i;
- if (initialized == 0)
+ if (nthreads == 0)
return;
post(&exit_message);
@@ -122,7 +122,6 @@ UV_DESTRUCTOR(static void cleanup(void)) {
threads = NULL;
nthreads = 0;
- initialized = 0;
}
#endif
@@ -130,6 +129,7 @@ UV_DESTRUCTOR(static void cleanup(void)) {
static void init_threads(void) {
unsigned int i;
const char* val;
+ uv_sem_t sem;
nthreads = ARRAY_SIZE(default_threads);
val = getenv("UV_THREADPOOL_SIZE");
@@ -157,11 +157,17 @@ static void init_threads(void) {
QUEUE_INIT(&wq);
+ if (uv_sem_init(&sem, 0))
+ abort();
+
for (i = 0; i < nthreads; i++)
- if (uv_thread_create(threads + i, worker, NULL))
+ if (uv_thread_create(threads + i, worker, &sem))
abort();
- initialized = 1;
+ for (i = 0; i < nthreads; i++)
+ uv_sem_wait(&sem);
+
+ uv_sem_destroy(&sem);
}
diff --git a/src/unix/aix-common.c b/src/unix/aix-common.c
new file mode 100644
index 0000000000..c2217fb6b4
--- /dev/null
+++ b/src/unix/aix-common.c
@@ -0,0 +1,292 @@
+/* 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 <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 <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>
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ uint64_t G = 1000000000;
+ timebasestruct_t t;
+ read_wall_time(&t, TIMEBASE_SZ);
+ time_base_to_time(&t, TIMEBASE_SZ);
+ return (uint64_t) t.tb_high * G + t.tb_low;
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ * There is no direct way of getting the exe path in AIX - either through /procfs
+ * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
+ * and use it in conjunction with PATH environment variable to craft one.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+ int res;
+ char args[PATH_MAX];
+ char abspath[PATH_MAX];
+ size_t abspath_size;
+ struct procsinfo pi;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ pi.pi_pid = getpid();
+ res = getargs(&pi, sizeof(pi), args, sizeof(args));
+ if (res < 0)
+ return -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 -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 -EINVAL;
+
+ clonedpath = uv__strdup(path);
+ if (clonedpath == NULL)
+ return -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 -EINVAL;
+ }
+}
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+ uv_interface_address_t* address;
+ int sockfd, inet6, size = 1;
+ struct ifconf ifc;
+ struct ifreq *ifr, *p, flg;
+ struct sockaddr_dl* sa_addr;
+
+ *count = 0;
+
+ if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
+ return -errno;
+ }
+
+ if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+ ifc.ifc_req = (struct ifreq*)uv__malloc(size);
+ ifc.ifc_len = size;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
+
+ /* Count all up and running ipv4/ipv6 addresses */
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ (*count)++;
+ }
+
+ /* Alloc the return interface structs */
+ *addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
+ if (!(*addresses)) {
+ uv__close(sockfd);
+ return -ENOMEM;
+ }
+ address = *addresses;
+
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ inet6 = (p->ifr_addr.sa_family == AF_INET6);
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -ENOSYS;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ /* All conditions above must match count loop */
+
+ address->name = uv__strdup(p->ifr_name);
+
+ if (inet6)
+ address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
+ else
+ address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
+
+ sa_addr = (struct sockaddr_dl*) &p->ifr_addr;
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+
+ if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
+ uv__close(sockfd);
+ return -ENOSYS;
+ }
+
+ if (inet6)
+ address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr);
+ else
+ address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
+
+ address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+
+ address++;
+ }
+
+#undef ADDR_SIZE
+
+ uv__close(sockfd);
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/src/unix/aix.c b/src/unix/aix.c
index 388c9cca97..fd413090fe 100644
--- a/src/unix/aix.c
+++ b/src/unix/aix.c
@@ -1,4 +1,5 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
@@ -64,11 +65,18 @@
#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;
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) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
int uv__platform_loop_init(uv_loop_t* loop) {
loop->fs_fd = -1;
@@ -316,104 +324,6 @@ update_timeout:
}
-uint64_t uv__hrtime(uv_clocktype_t type) {
- uint64_t G = 1000000000;
- timebasestruct_t t;
- read_wall_time(&t, TIMEBASE_SZ);
- time_base_to_time(&t, TIMEBASE_SZ);
- return (uint64_t) t.tb_high * G + t.tb_low;
-}
-
-
-/*
- * We could use a static buffer for the path manipulations that we need outside
- * of the function, but this function could be called by multiple consumers and
- * we don't want to potentially create a race condition in the use of snprintf.
- * There is no direct way of getting the exe path in AIX - either through /procfs
- * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
- * and use it in conjunction with PATH environment variable to craft one.
- */
-int uv_exepath(char* buffer, size_t* size) {
- int res;
- char args[PATH_MAX];
- char abspath[PATH_MAX];
- size_t abspath_size;
- struct procsinfo pi;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return -EINVAL;
-
- pi.pi_pid = getpid();
- res = getargs(&pi, sizeof(pi), args, sizeof(args));
- if (res < 0)
- return -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 -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 -EINVAL;
-
- clonedpath = uv__strdup(path);
- if (clonedpath == NULL)
- return -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 -EINVAL;
- }
-}
-
-
uint64_t uv_get_free_memory(void) {
perfstat_memory_total_t mem_total;
int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
@@ -855,6 +765,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
handle->path = uv__strdup(filename);
handle->cb = cb;
+ handle->dir_filename = NULL;
uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
@@ -952,6 +863,9 @@ int uv_set_process_title(const char* title) {
if (new_title == NULL)
return -ENOMEM;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
/* If this is the first time this is set,
* don't free and set argv[1] to NULL.
*/
@@ -964,6 +878,8 @@ int uv_set_process_title(const char* title) {
if (process_argc > 1)
process_argv[1] = NULL;
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -976,8 +892,13 @@ int uv_get_process_title(char* buffer, size_t size) {
else if (size <= len)
return -ENOBUFS;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
memcpy(buffer, process_argv[0], len + 1);
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -1017,6 +938,7 @@ int uv_uptime(double* uptime) {
size_t entries = 0;
time_t boot_time;
+ boot_time = 0;
utmpname(UTMP_FILE);
setutent();
@@ -1093,130 +1015,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
}
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
- int i;
-
- for (i = 0; i < count; ++i) {
- uv__free(cpu_infos[i].model);
- }
-
- uv__free(cpu_infos);
-}
-
-
-int uv_interface_addresses(uv_interface_address_t** addresses,
- int* count) {
- uv_interface_address_t* address;
- int sockfd, size = 1;
- struct ifconf ifc;
- struct ifreq *ifr, *p, flg;
-
- *count = 0;
-
- if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
- return -errno;
- }
-
- if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
- uv__close(sockfd);
- return -errno;
- }
-
- ifc.ifc_req = (struct ifreq*)uv__malloc(size);
- ifc.ifc_len = size;
- if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
- uv__close(sockfd);
- return -errno;
- }
-
-#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
-
- /* Count all up and running ipv4/ipv6 addresses */
- ifr = ifc.ifc_req;
- while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
- p = ifr;
- ifr = (struct ifreq*)
- ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
-
- if (!(p->ifr_addr.sa_family == AF_INET6 ||
- p->ifr_addr.sa_family == AF_INET))
- continue;
-
- memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
- if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
- uv__close(sockfd);
- return -errno;
- }
-
- if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
- continue;
-
- (*count)++;
- }
-
- /* Alloc the return interface structs */
- *addresses = (uv_interface_address_t*)
- uv__malloc(*count * sizeof(uv_interface_address_t));
- if (!(*addresses)) {
- uv__close(sockfd);
- return -ENOMEM;
- }
- address = *addresses;
-
- ifr = ifc.ifc_req;
- while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
- p = ifr;
- ifr = (struct ifreq*)
- ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
-
- if (!(p->ifr_addr.sa_family == AF_INET6 ||
- p->ifr_addr.sa_family == AF_INET))
- continue;
-
- memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
- if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
- uv__close(sockfd);
- return -ENOSYS;
- }
-
- if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
- continue;
-
- /* All conditions above must match count loop */
-
- address->name = uv__strdup(p->ifr_name);
-
- if (p->ifr_addr.sa_family == AF_INET6) {
- address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
- } else {
- address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
- }
-
- /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
-
- address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
-
- address++;
- }
-
-#undef ADDR_SIZE
-
- uv__close(sockfd);
- return 0;
-}
-
-
-void uv_free_interface_addresses(uv_interface_address_t* addresses,
- int count) {
- int i;
-
- for (i = 0; i < count; ++i) {
- uv__free(addresses[i].name);
- }
-
- uv__free(addresses);
-}
-
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct pollfd* events;
uintptr_t i;
diff --git a/src/unix/android-ifaddrs.c b/src/unix/android-ifaddrs.c
index 30f681b7d0..bf30b14179 100644
--- a/src/unix/android-ifaddrs.c
+++ b/src/unix/android-ifaddrs.c
@@ -43,9 +43,10 @@ typedef struct NetlinkList
unsigned int m_size;
} NetlinkList;
-static int netlink_socket(void)
+static int netlink_socket(pid_t *p_pid)
{
struct sockaddr_nl l_addr;
+ socklen_t l_len;
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if(l_socket < 0)
@@ -61,6 +62,14 @@ static int netlink_socket(void)
return -1;
}
+ l_len = sizeof(l_addr);
+ if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
+ {
+ close(l_socket);
+ return -1;
+ }
+ *p_pid = l_addr.nl_pid;
+
return l_socket;
}
@@ -128,7 +137,7 @@ static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
}
}
-static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
+static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
{
size_t l_size = 4096;
void *l_buffer = NULL;
@@ -153,11 +162,10 @@ static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_don
}
if(l_read >= 0)
{
- pid_t l_pid = getpid();
struct nlmsghdr *l_hdr;
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
{
- if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
@@ -207,7 +215,7 @@ static void freeResultList(NetlinkList *p_list)
}
}
-static NetlinkList *getResultList(int p_socket, int p_request)
+static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
{
int l_size;
int l_done;
@@ -227,7 +235,7 @@ static NetlinkList *getResultList(int p_socket, int p_request)
{
NetlinkList *l_item;
- struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
+ struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
/* Error */
if(!l_hdr)
{
@@ -449,7 +457,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
char *l_name;
char *l_addr;
- for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
if(l_info->ifa_family == AF_PACKET)
@@ -471,7 +479,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
break;
case IFA_LABEL:
- l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+ l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
break;
default:
break;
@@ -496,7 +504,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
}
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
- for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
@@ -559,7 +567,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
{
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
- char l_mask[16] = {0};
+ unsigned char l_mask[16] = {0};
unsigned i;
for(i=0; i<(l_prefix/8); ++i)
{
@@ -578,18 +586,17 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
return 0;
}
-static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
+static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
{
int l_numLinks = 0;
- pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
- if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
@@ -612,16 +619,15 @@ static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifadd
return l_numLinks;
}
-static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
+static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
{
- pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
- if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
@@ -648,6 +654,7 @@ int getifaddrs(struct ifaddrs **ifap)
int l_socket;
int l_result;
int l_numLinks;
+ pid_t l_pid;
NetlinkList *l_linkResults;
NetlinkList *l_addrResults;
@@ -657,20 +664,20 @@ int getifaddrs(struct ifaddrs **ifap)
}
*ifap = NULL;
- l_socket = netlink_socket();
+ l_socket = netlink_socket(&l_pid);
if(l_socket < 0)
{
return -1;
}
- l_linkResults = getResultList(l_socket, RTM_GETLINK);
+ l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
if(!l_linkResults)
{
close(l_socket);
return -1;
}
- l_addrResults = getResultList(l_socket, RTM_GETADDR);
+ l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
if(!l_addrResults)
{
close(l_socket);
@@ -679,8 +686,8 @@ int getifaddrs(struct ifaddrs **ifap)
}
l_result = 0;
- l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
- if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
+ l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
+ if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
{
l_result = -1;
}
diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h
index 9dac2557f8..7cac1f9889 100644
--- a/src/unix/atomic-ops.h
+++ b/src/unix/atomic-ops.h
@@ -20,7 +20,6 @@
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
#include <atomic.h>
-#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n)
#endif
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
@@ -49,6 +48,8 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
return oldval;
else
return op4;
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ return atomic_cas_uint(ptr, oldval, newval);
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
@@ -83,6 +84,8 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
return oldval;
else
return op4;
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ return atomic_cas_ulong(ptr, oldval, newval);
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c
index 414789451a..ea3166c5e9 100644
--- a/src/unix/bsd-ifaddrs.c
+++ b/src/unix/bsd-ifaddrs.c
@@ -31,11 +31,20 @@
#include <net/if_dl.h>
#endif
-static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
return 1;
if (ent->ifa_addr == NULL)
return 1;
+#if !defined(__CYGWIN__) && !defined(__MSYS__)
+ /*
+ * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family`
+ * equals to `AF_LINK` or not. Otherwise, the result depends on the operation
+ * system with `AF_LINK` or `PF_INET`.
+ */
+ if (exclude_type == UV__EXCLUDE_IFPHYS)
+ return (ent->ifa_addr->sa_family != AF_LINK);
+#endif
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
/*
* On BSD getifaddrs returns information related to the raw underlying
@@ -43,7 +52,11 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) {
*/
if (ent->ifa_addr->sa_family == AF_LINK)
return 1;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#elif defined(__NetBSD__)
+ if (ent->ifa_addr->sa_family != PF_INET &&
+ ent->ifa_addr->sa_family != PF_INET6)
+ return 1;
+#elif defined(__OpenBSD__)
if (ent->ifa_addr->sa_family != PF_INET)
return 1;
#endif
@@ -63,7 +76,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
(*count)++;
}
@@ -78,7 +91,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
address->name = uv__strdup(ent->ifa_name);
@@ -102,7 +115,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
continue;
address = *addresses;
diff --git a/src/unix/core.c b/src/unix/core.c
index 30cdaef7ba..c7e431e529 100644
--- a/src/unix/core.c
+++ b/src/unix/core.c
@@ -28,7 +28,6 @@
#include <errno.h>
#include <assert.h>
#include <unistd.h>
-#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -59,13 +58,19 @@
#if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__)
+ defined(__FreeBSD_kernel__) || \
+ defined(__NetBSD__)
# include <sys/sysctl.h>
# include <sys/filio.h>
# include <sys/wait.h>
# define UV__O_CLOEXEC O_CLOEXEC
# if defined(__FreeBSD__) && __FreeBSD__ >= 10
# define uv__accept4 accept4
+# endif
+# if defined(__NetBSD__)
+# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d))
+# endif
+# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
# endif
@@ -82,6 +87,10 @@
#include <sys/ioctl.h>
#endif
+#if !defined(__MVS__)
+#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */
+#endif
+
/* Fallback for the maximum hostname length */
#ifndef MAXHOSTNAMELEN
# define MAXHOSTNAMELEN 256
@@ -459,7 +468,9 @@ int uv__accept(int sockfd) {
assert(sockfd >= 0);
while (1) {
-#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10)
+#if defined(__linux__) || \
+ (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
+ defined(__NetBSD__)
static int no_accept4;
if (no_accept4)
@@ -835,7 +846,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+ assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
assert(0 != events);
assert(w->fd >= 0);
assert(w->fd < INT_MAX);
@@ -863,7 +874,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+ assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
assert(0 != events);
if (w->fd == -1)
@@ -895,7 +906,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
- uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP);
+ uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
QUEUE_REMOVE(&w->pending_queue);
/* Remove stale events for this file descriptor */
@@ -910,7 +921,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
int uv__io_active(const uv__io_t* w, unsigned int events) {
- assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+ assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
assert(0 != events);
return 0 != (w->pevents & events);
}
@@ -985,7 +996,7 @@ int uv__open_cloexec(const char* path, int flags) {
int uv__dup2_cloexec(int oldfd, int newfd) {
int r;
-#if defined(__FreeBSD__) && __FreeBSD__ >= 10
+#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
r = dup3(oldfd, newfd, O_CLOEXEC);
if (r == -1)
return -errno;
@@ -1289,6 +1300,9 @@ int uv_os_setenv(const char* name, const char* value) {
int uv_os_unsetenv(const char* name) {
+ if (name == NULL)
+ return -EINVAL;
+
if (unsetenv(name) != 0)
return -errno;
@@ -1324,3 +1338,18 @@ int uv_os_gethostname(char* buffer, size_t* size) {
*size = len;
return 0;
}
+
+
+uv_os_fd_t uv_get_osfhandle(int fd) {
+ return fd;
+}
+
+
+uv_pid_t uv_os_getpid(void) {
+ return getpid();
+}
+
+
+uv_pid_t uv_os_getppid(void) {
+ return getppid();
+}
diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c
index e52ae99dbe..f2b3f247a0 100644
--- a/src/unix/freebsd.c
+++ b/src/unix/freebsd.c
@@ -25,7 +25,6 @@
#include <string.h>
#include <errno.h>
-#include <kvm.h>
#include <paths.h>
#include <sys/user.h>
#include <sys/types.h>
@@ -48,9 +47,16 @@
# define CP_INTR 4
#endif
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static char *process_title;
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
int uv__platform_loop_init(uv_loop_t* loop) {
return uv__kqueue_init(loop);
}
@@ -161,9 +167,20 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
int oid[4];
+ char* new_title;
+
+ new_title = uv__strdup(title);
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ if (process_title == NULL) {
+ uv_mutex_unlock(&process_title_mutex);
+ return -ENOMEM;
+ }
uv__free(process_title);
- process_title = uv__strdup(title);
+ process_title = new_title;
oid[0] = CTL_KERN;
oid[1] = KERN_PROC;
@@ -177,6 +194,8 @@ int uv_set_process_title(const char* title) {
process_title,
strlen(process_title) + 1);
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -187,51 +206,54 @@ int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return -EINVAL;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
if (process_title) {
len = strlen(process_title) + 1;
- if (size < len)
+ if (size < len) {
+ uv_mutex_unlock(&process_title_mutex);
return -ENOBUFS;
+ }
memcpy(buffer, process_title, len);
} else {
len = 0;
}
+ uv_mutex_unlock(&process_title_mutex);
+
buffer[len] = '\0';
return 0;
}
-
int uv_resident_set_memory(size_t* rss) {
- kvm_t *kd = NULL;
- struct kinfo_proc *kinfo = NULL;
- pid_t pid;
- int nprocs;
- size_t page_size = getpagesize();
+ struct kinfo_proc kinfo;
+ size_t page_size;
+ size_t kinfo_size;
+ int mib[4];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
- pid = getpid();
+ kinfo_size = sizeof(kinfo);
- kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
- if (kd == NULL) goto error;
+ if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0))
+ return -errno;
- kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
- if (kinfo == NULL) goto error;
+ page_size = getpagesize();
#ifdef __DragonFly__
- *rss = kinfo->kp_vm_rssize * page_size;
+ *rss = kinfo.kp_vm_rssize * page_size;
#else
- *rss = kinfo->ki_rssize * page_size;
+ *rss = kinfo.ki_rssize * page_size;
#endif
- kvm_close(kd);
-
return 0;
-
-error:
- if (kd) kvm_close(kd);
- return -EPERM;
}
@@ -254,6 +276,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
const char* maxcpus_key;
const char* cptimes_key;
+ const char* model_key;
char model[512];
long* cp_times;
int numcpus;
@@ -272,8 +295,20 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cptimes_key = "kern.cp_times";
#endif
+#if defined(__arm__) || defined(__aarch64__)
+ /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */
+ model_key = "hw.machine";
+ cpuspeed = 0;
+#else
+ model_key = "hw.model";
+
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0))
+ return -errno;
+#endif
+
size = sizeof(model);
- if (sysctlbyname("hw.model", &model, &size, NULL, 0))
+ if (sysctlbyname(model_key, &model, &size, NULL, 0))
return -errno;
size = sizeof(numcpus);
@@ -286,12 +321,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
*count = numcpus;
- size = sizeof(cpuspeed);
- if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) {
- uv__free(*cpu_infos);
- return -errno;
- }
-
/* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
* ncpu.
*/
diff --git a/src/unix/fs.c b/src/unix/fs.c
index f9513ea55a..e0969a4c2f 100644
--- a/src/unix/fs.c
+++ b/src/unix/fs.c
@@ -60,8 +60,14 @@
# include <sys/sendfile.h>
#endif
+#if defined(__APPLE__)
+# include <copyfile.h>
+#endif
+
#define INIT(subtype) \
do { \
+ if (req == NULL) \
+ return -EINVAL; \
req->type = UV_FS; \
if (cb != NULL) \
uv__req_init(loop, req, UV_FS); \
@@ -126,26 +132,33 @@
while (0)
-static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
-#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
- return fdatasync(req->file);
-#elif defined(__APPLE__)
+static ssize_t uv__fs_fsync(uv_fs_t* req) {
+#if defined(__APPLE__)
/* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
* to the drive platters. This is in contrast to Linux's fdatasync and fsync
* which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
- * for flushing buffered data to permanent storage.
+ * for flushing buffered data to permanent storage. If F_FULLFSYNC is not
+ * supported by the file system we should fall back to fsync(). This is the
+ * same approach taken by sqlite.
*/
- return fcntl(req->file, F_FULLFSYNC);
+ int r;
+
+ r = fcntl(req->file, F_FULLFSYNC);
+ if (r != 0 && errno == ENOTTY)
+ r = fsync(req->file);
+ return r;
#else
return fsync(req->file);
#endif
}
-static ssize_t uv__fs_fsync(uv_fs_t* req) {
-#if defined(__APPLE__)
- /* See the comment in uv__fs_fdatasync. */
- return fcntl(req->file, F_FULLFSYNC);
+static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
+#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
+ return fdatasync(req->file);
+#elif defined(__APPLE__)
+ /* See the comment in uv__fs_fsync. */
+ return uv__fs_fsync(req);
#else
return fsync(req->file);
#endif
@@ -432,7 +445,12 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
return -1;
}
+#if defined(__MVS__)
+ len = os390_readlink(req->path, buf, len);
+#else
len = readlink(req->path, buf, len);
+#endif
+
if (len == -1) {
uv__free(buf);
@@ -766,6 +784,118 @@ done:
return r;
}
+static ssize_t uv__fs_copyfile(uv_fs_t* req) {
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+ /* On macOS, use the native copyfile(3). */
+ copyfile_flags_t flags;
+
+ flags = COPYFILE_ALL;
+
+ if (req->flags & UV_FS_COPYFILE_EXCL)
+ flags |= COPYFILE_EXCL;
+
+ return copyfile(req->path, req->new_path, NULL, flags);
+#else
+ uv_fs_t fs_req;
+ uv_file srcfd;
+ uv_file dstfd;
+ struct stat statsbuf;
+ int dst_flags;
+ int result;
+ int err;
+ size_t bytes_to_send;
+ int64_t in_offset;
+
+ dstfd = -1;
+ err = 0;
+
+ /* Open the source file. */
+ srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL);
+ uv_fs_req_cleanup(&fs_req);
+
+ if (srcfd < 0)
+ return srcfd;
+
+ /* Get the source file's mode. */
+ if (fstat(srcfd, &statsbuf)) {
+ err = -errno;
+ goto out;
+ }
+
+ dst_flags = O_WRONLY | O_CREAT | O_TRUNC;
+
+ if (req->flags & UV_FS_COPYFILE_EXCL)
+ dst_flags |= O_EXCL;
+
+ /* Open the destination file. */
+ dstfd = uv_fs_open(NULL,
+ &fs_req,
+ req->new_path,
+ dst_flags,
+ statsbuf.st_mode,
+ NULL);
+ uv_fs_req_cleanup(&fs_req);
+
+ if (dstfd < 0) {
+ err = dstfd;
+ goto out;
+ }
+
+ if (fchmod(dstfd, statsbuf.st_mode) == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ bytes_to_send = statsbuf.st_size;
+ in_offset = 0;
+ while (bytes_to_send != 0) {
+ err = uv_fs_sendfile(NULL,
+ &fs_req,
+ dstfd,
+ srcfd,
+ in_offset,
+ bytes_to_send,
+ NULL);
+ uv_fs_req_cleanup(&fs_req);
+ if (err < 0)
+ break;
+ bytes_to_send -= fs_req.result;
+ in_offset += fs_req.result;
+ }
+
+out:
+ if (err < 0)
+ result = err;
+ else
+ result = 0;
+
+ /* Close the source file. */
+ err = uv__close_nocheckstdio(srcfd);
+
+ /* Don't overwrite any existing errors. */
+ if (err != 0 && result == 0)
+ result = err;
+
+ /* Close the destination file if it is open. */
+ if (dstfd >= 0) {
+ err = uv__close_nocheckstdio(dstfd);
+
+ /* Don't overwrite any existing errors. */
+ if (err != 0 && result == 0)
+ result = err;
+
+ /* Remove the destination file if something went wrong. */
+ if (result != 0) {
+ uv_fs_unlink(NULL, &fs_req, req->new_path, NULL);
+ /* Ignore the unlink return value, as an error already happened. */
+ uv_fs_req_cleanup(&fs_req);
+ }
+ }
+
+ return result;
+#endif
+}
+
static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_dev = src->st_dev;
dst->st_mode = src->st_mode;
@@ -946,6 +1076,7 @@ static void uv__fs_work(struct uv__work* w) {
X(CHMOD, chmod(req->path, req->mode));
X(CHOWN, chown(req->path, req->uid, req->gid));
X(CLOSE, close(req->file));
+ X(COPYFILE, uv__fs_copyfile(req));
X(FCHMOD, fchmod(req->file, req->mode));
X(FCHOWN, fchown(req->file, req->uid, req->gid));
X(FDATASYNC, uv__fs_fdatasync(req));
@@ -1186,10 +1317,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
unsigned int nbufs,
int64_t off,
uv_fs_cb cb) {
+ INIT(READ);
+
if (bufs == NULL || nbufs == 0)
return -EINVAL;
- INIT(READ);
req->file = file;
req->nbufs = nbufs;
@@ -1324,10 +1456,11 @@ int uv_fs_write(uv_loop_t* loop,
unsigned int nbufs,
int64_t off,
uv_fs_cb cb) {
+ INIT(WRITE);
+
if (bufs == NULL || nbufs == 0)
return -EINVAL;
- INIT(WRITE);
req->file = file;
req->nbufs = nbufs;
@@ -1349,6 +1482,9 @@ int uv_fs_write(uv_loop_t* loop,
void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req == NULL)
+ return;
+
/* 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 is the
@@ -1367,3 +1503,20 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
uv__free(req->ptr);
req->ptr = NULL;
}
+
+
+int uv_fs_copyfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(COPYFILE);
+
+ if (flags & ~UV_FS_COPYFILE_EXCL)
+ return -EINVAL;
+
+ PATH2;
+ req->flags = flags;
+ POST;
+}
diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c
index 643e233cfe..38837406a6 100644
--- a/src/unix/fsevents.c
+++ b/src/unix/fsevents.c
@@ -230,6 +230,7 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
uv_loop_t* loop;
uv__cf_loop_state_t* state;
uv__fsevents_event_t* event;
+ FSEventStreamEventFlags flags;
QUEUE head;
loop = info;
@@ -245,8 +246,10 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
/* Process and filter out events */
for (i = 0; i < numEvents; i++) {
+ flags = eventFlags[i];
+
/* Ignore system events */
- if (eventFlags[i] & kFSEventsSystem)
+ if (flags & kFSEventsSystem)
continue;
path = paths[i];
@@ -271,6 +274,9 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
/* Ignore events with path equal to directory itself */
if (len == 0)
continue;
+#else
+ if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir))
+ continue;
#endif /* MAC_OS_X_VERSION_10_7 */
/* Do not emit events from subdirectories (without option set) */
@@ -291,12 +297,24 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
memset(event, 0, sizeof(*event));
memcpy(event->path, path, len + 1);
+ event->events = UV_RENAME;
- if ((eventFlags[i] & kFSEventsModified) != 0 &&
- (eventFlags[i] & kFSEventsRenamed) == 0)
+#ifdef MAC_OS_X_VERSION_10_7
+ if (0 != (flags & kFSEventsModified) &&
+ 0 == (flags & kFSEventsRenamed)) {
+ event->events = UV_CHANGE;
+ }
+#else
+ if (0 != (flags & kFSEventsModified) &&
+ 0 != (flags & kFSEventStreamEventFlagItemIsDir) &&
+ 0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
event->events = UV_CHANGE;
- else
- event->events = UV_RENAME;
+ }
+ if (0 == (flags & kFSEventStreamEventFlagItemIsDir) &&
+ 0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
+ event->events = UV_CHANGE;
+ }
+#endif /* MAC_OS_X_VERSION_10_7 */
QUEUE_INSERT_TAIL(&head, &event->member);
}
diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c
index 2049aea2f3..0185971697 100644
--- a/src/unix/getaddrinfo.c
+++ b/src/unix/getaddrinfo.c
@@ -32,6 +32,7 @@
#include <stddef.h> /* NULL */
#include <stdlib.h>
#include <string.h>
+#include <net/if.h> /* if_indextoname() */
/* EAI_* constants. */
#include <netdb.h>
@@ -200,3 +201,32 @@ void uv_freeaddrinfo(struct addrinfo* ai) {
if (ai)
freeaddrinfo(ai);
}
+
+
+int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
+ char ifname_buf[UV_IF_NAMESIZE];
+ size_t len;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ if (if_indextoname(ifindex, ifname_buf) == NULL)
+ return -errno;
+
+ len = strnlen(ifname_buf, sizeof(ifname_buf));
+
+ if (*size <= len) {
+ *size = len + 1;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, ifname_buf, len);
+ buffer[len] = '\0';
+ *size = len;
+
+ return 0;
+}
+
+int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
+ return uv_if_indextoname(ifindex, buffer, size);
+}
diff --git a/src/unix/ibmi.c b/src/unix/ibmi.c
new file mode 100644
index 0000000000..c19e2fc379
--- /dev/null
+++ b/src/unix/ibmi.c
@@ -0,0 +1,112 @@
+/* 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 <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 <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 <ctype.h>
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <limits.h>
+#include <strings.h>
+#include <sys/vnode.h>
+
+uint64_t uv_get_free_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
+}
+
+
+void uv_loadavg(double avg[3]) {
+ avg[0] = avg[1] = avg[2] = 0;
+ return;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ return UV_ENOSYS;
+}
+
+
+int uv_uptime(double* uptime) {
+ return UV_ENOSYS;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int numcpus, idx = 0;
+ uv_cpu_info_t* cpu_info;
+
+ *cpu_infos = NULL;
+ *count = 0;
+
+ numcpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t));
+ if (!*cpu_infos) {
+ return -ENOMEM;
+ }
+
+ cpu_info = *cpu_infos;
+ for (idx = 0; idx < numcpus; idx++) {
+ cpu_info->speed = 0;
+ cpu_info->model = uv__strdup("unknown");
+ cpu_info->cpu_times.user = 0;
+ cpu_info->cpu_times.sys = 0;
+ cpu_info->cpu_times.idle = 0;
+ cpu_info->cpu_times.irq = 0;
+ cpu_info->cpu_times.nice = 0;
+ cpu_info++;
+ }
+ *count = numcpus;
+
+ return 0;
+}
diff --git a/src/unix/internal.h b/src/unix/internal.h
index 2e3afa6c85..3df5c4c3eb 100644
--- a/src/unix/internal.h
+++ b/src/unix/internal.h
@@ -110,6 +110,12 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
# define UV__POLLRDHUP 0x2000
#endif
+#ifdef POLLPRI
+# define UV__POLLPRI POLLPRI
+#else
+# define UV__POLLPRI 0
+#endif
+
#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
/*
* It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
@@ -145,6 +151,12 @@ enum {
UV_LOOP_BLOCK_SIGPROF = 1
};
+/* flags of excluding ifaddr */
+enum {
+ UV__EXCLUDE_IFPHYS,
+ UV__EXCLUDE_IFADDR
+};
+
typedef enum {
UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
@@ -163,7 +175,8 @@ struct uv__stream_queued_fds_s {
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__linux__) || \
- defined(__OpenBSD__)
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
#define uv__cloexec uv__cloexec_ioctl
#define uv__nonblock uv__nonblock_ioctl
#else
diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c
index 6bc60bbe46..5e89bdced4 100644
--- a/src/unix/kqueue.c
+++ b/src/unix/kqueue.c
@@ -34,6 +34,17 @@
#include <fcntl.h>
#include <time.h>
+/*
+ * Required on
+ * - Until at least FreeBSD 11.0
+ * - Older versions of Mac OS X
+ *
+ * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp
+ */
+#ifndef EV_OOBAND
+#define EV_OOBAND EV_FLAG1
+#endif
+
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
@@ -48,11 +59,12 @@ int uv__kqueue_init(uv_loop_t* loop) {
}
+#if defined(__APPLE__)
static int uv__has_forked_with_cfrunloop;
+#endif
int uv__io_fork(uv_loop_t* loop) {
int err;
- uv__close(loop->backend_fd);
loop->backend_fd = -1;
err = uv__kqueue_init(loop);
if (err)
@@ -166,6 +178,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
}
}
+ if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) {
+ EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0);
+
+ if (++nevents == ARRAY_SIZE(events)) {
+ if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
+ abort();
+ nevents = 0;
+ }
+ }
+
w->events = w->pevents;
}
@@ -275,6 +297,20 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
}
}
+ if (ev->filter == EV_OOBAND) {
+ if (w->pevents & UV__POLLPRI) {
+ revents |= UV__POLLPRI;
+ w->rcount = ev->data;
+ } else {
+ /* TODO batch up */
+ struct kevent events[1];
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != ENOENT)
+ abort();
+ }
+ }
+
if (ev->filter == EVFILT_WRITE) {
if (w->pevents & POLLOUT) {
revents |= POLLOUT;
diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c
index 2866e93854..4d480ce10a 100644
--- a/src/unix/linux-core.c
+++ b/src/unix/linux-core.c
@@ -388,7 +388,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
* free when we switch over to edge-triggered I/O.
*/
if (pe->events == POLLERR || pe->events == POLLHUP)
- pe->events |= w->pevents & (POLLIN | POLLOUT);
+ pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI);
if (pe->events != 0) {
/* Run signal watchers last. This also affects child process watchers
@@ -837,7 +837,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
uv__free(cpu_infos);
}
-static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
return 1;
if (ent->ifa_addr == NULL)
@@ -847,8 +847,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) {
* devices. We're not interested in this information yet.
*/
if (ent->ifa_addr->sa_family == PF_PACKET)
- return 1;
- return 0;
+ return exclude_type;
+ return !exclude_type;
}
int uv_interface_addresses(uv_interface_address_t** addresses,
@@ -869,7 +869,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
/* Count the number of interfaces */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
(*count)++;
@@ -887,7 +887,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
address->name = uv__strdup(ent->ifa_name);
@@ -911,7 +911,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent))
+ if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
continue;
address = *addresses;
diff --git a/src/unix/loop.c b/src/unix/loop.c
index bcd49242ce..5b5b0e095b 100644
--- a/src/unix/loop.c
+++ b/src/unix/loop.c
@@ -31,7 +31,6 @@ int uv_loop_init(uv_loop_t* loop) {
void* saved_data;
int err;
- uv__signal_global_once_init();
saved_data = loop->data;
memset(loop, 0, sizeof(*loop));
@@ -68,6 +67,7 @@ int uv_loop_init(uv_loop_t* loop) {
if (err)
return err;
+ uv__signal_global_once_init();
err = uv_signal_init(loop, &loop->child_watcher);
if (err)
goto fail_signal_init;
diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c
index 9b5546b7e6..7425072331 100644
--- a/src/unix/netbsd.c
+++ b/src/unix/netbsd.c
@@ -40,9 +40,16 @@
#include <unistd.h>
#include <time.h>
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static char *process_title;
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
int uv__platform_loop_init(uv_loop_t* loop) {
return uv__kqueue_init(loop);
}
@@ -66,22 +73,32 @@ void uv_loadavg(double avg[3]) {
int uv_exepath(char* buffer, size_t* size) {
+ /* Intermediate buffer, retrieving partial path name does not work
+ * As of NetBSD-8(beta), vnode->path translator does not handle files
+ * with longer names than 31 characters.
+ */
+ char int_buf[PATH_MAX];
+ size_t int_size;
int mib[4];
- size_t cb;
- pid_t mypid;
if (buffer == NULL || size == NULL || *size == 0)
return -EINVAL;
- mypid = getpid();
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
- mib[2] = mypid;
- mib[3] = KERN_PROC_ARGV;
+ mib[2] = -1;
+ mib[3] = KERN_PROC_PATHNAME;
+ int_size = ARRAY_SIZE(int_buf);
- cb = *size;
- if (sysctl(mib, 4, buffer, &cb, NULL, 0))
+ if (sysctl(mib, 4, int_buf, &int_size, NULL, 0))
return -errno;
+
+ /* Copy string from the intermediate buffer to outer one with appropriate
+ * length.
+ */
+ strlcpy(buffer, int_buf, *size);
+
+ /* Set new size. */
*size = strlen(buffer);
return 0;
@@ -124,11 +141,24 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
- if (process_title) uv__free(process_title);
+ char* new_title;
+
+ new_title = uv__strdup(title);
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
- process_title = uv__strdup(title);
+ if (process_title == NULL) {
+ uv_mutex_unlock(&process_title_mutex);
+ return -ENOMEM;
+ }
+
+ uv__free(process_title);
+ process_title = new_title;
setproctitle("%s", title);
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -139,17 +169,24 @@ int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return -EINVAL;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
if (process_title) {
len = strlen(process_title) + 1;
- if (size < len)
+ if (size < len) {
+ uv_mutex_unlock(&process_title_mutex);
return -ENOBUFS;
+ }
memcpy(buffer, process_title, len);
} else {
len = 0;
}
+ uv_mutex_unlock(&process_title_mutex);
+
buffer[len] = '\0';
return 0;
diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c
index 56f0af15c3..c0ffa564b4 100644
--- a/src/unix/openbsd.c
+++ b/src/unix/openbsd.c
@@ -36,9 +36,16 @@
#include <unistd.h>
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static char *process_title;
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
int uv__platform_loop_init(uv_loop_t* loop) {
return uv__kqueue_init(loop);
}
@@ -146,9 +153,24 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
+ char* new_title;
+
+ new_title = uv__strdup(title);
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ if (process_title == NULL) {
+ uv_mutex_unlock(&process_title_mutex);
+ return -ENOMEM;
+ }
+
uv__free(process_title);
- process_title = uv__strdup(title);
+ process_title = new_title;
setproctitle("%s", title);
+
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
@@ -159,17 +181,24 @@ int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return -EINVAL;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
if (process_title) {
len = strlen(process_title) + 1;
- if (size < len)
+ if (size < len) {
+ uv_mutex_unlock(&process_title_mutex);
return -ENOBUFS;
+ }
memcpy(buffer, process_title, len);
} else {
len = 0;
}
+ uv_mutex_unlock(&process_title_mutex);
+
buffer[len] = '\0';
return 0;
diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c
index 7edf2358d4..21558ea868 100644
--- a/src/unix/os390-syscalls.c
+++ b/src/unix/os390-syscalls.c
@@ -25,6 +25,8 @@
#include <stdlib.h>
#include <assert.h>
#include <search.h>
+#include <termios.h>
+#include <sys/msg.h>
#define CW_CONDVAR 32
@@ -103,10 +105,19 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
unsigned int newsize;
unsigned int i;
struct pollfd* newlst;
+ struct pollfd event;
if (len <= lst->size)
return;
+ if (lst->size == 0)
+ event.fd = -1;
+ else {
+ /* Extract the message queue at the end. */
+ event = lst->items[lst->size - 1];
+ lst->items[lst->size - 1].fd = -1;
+ }
+
newsize = next_power_of_two(len);
newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0]));
@@ -115,32 +126,101 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
for (i = lst->size; i < newsize; ++i)
newlst[i].fd = -1;
+ /* Restore the message queue at the end */
+ newlst[newsize - 1] = event;
+
lst->items = newlst;
lst->size = newsize;
}
+static void init_message_queue(uv__os390_epoll* lst) {
+ struct {
+ long int header;
+ char body;
+ } msg;
+
+ /* initialize message queue */
+ lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT);
+ if (lst->msg_queue == -1)
+ abort();
+
+ /*
+ On z/OS, the message queue will be affiliated with the process only
+ when a send is performed on it. Once this is done, the system
+ can be queried for all message queues belonging to our process id.
+ */
+ msg.header = 1;
+ if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0)
+ abort();
+
+ /* Clean up the dummy message sent above */
+ if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body))
+ abort();
+}
+
+
+static void before_fork(void) {
+ uv_mutex_lock(&global_epoll_lock);
+}
+
+
+static void after_fork(void) {
+ uv_mutex_unlock(&global_epoll_lock);
+}
+
+
+static void child_fork(void) {
+ QUEUE* q;
+ uv_once_t child_once = UV_ONCE_INIT;
+
+ /* reset once */
+ memcpy(&once, &child_once, sizeof(child_once));
+
+ /* reset epoll list */
+ while (!QUEUE_EMPTY(&global_epoll_queue)) {
+ uv__os390_epoll* lst;
+ q = QUEUE_HEAD(&global_epoll_queue);
+ QUEUE_REMOVE(q);
+ lst = QUEUE_DATA(q, uv__os390_epoll, member);
+ uv__free(lst->items);
+ lst->items = NULL;
+ lst->size = 0;
+ }
+
+ uv_mutex_unlock(&global_epoll_lock);
+ uv_mutex_destroy(&global_epoll_lock);
+}
+
+
static void epoll_init(void) {
QUEUE_INIT(&global_epoll_queue);
if (uv_mutex_init(&global_epoll_lock))
abort();
+
+ if (pthread_atfork(&before_fork, &after_fork, &child_fork))
+ abort();
}
uv__os390_epoll* epoll_create1(int flags) {
uv__os390_epoll* lst;
- uv_once(&once, epoll_init);
- uv_mutex_lock(&global_epoll_lock);
lst = uv__malloc(sizeof(*lst));
- if (lst == -1)
- return NULL;
- QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
- uv_mutex_unlock(&global_epoll_lock);
+ if (lst != NULL) {
+ /* initialize list */
+ lst->size = 0;
+ lst->items = NULL;
+ init_message_queue(lst);
+ maybe_resize(lst, 1);
+ lst->items[lst->size - 1].fd = lst->msg_queue;
+ lst->items[lst->size - 1].events = POLLIN;
+ uv_once(&once, epoll_init);
+ uv_mutex_lock(&global_epoll_lock);
+ QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
+ uv_mutex_unlock(&global_epoll_lock);
+ }
- /* initialize list */
- lst->size = 0;
- lst->items = NULL;
return lst;
}
@@ -149,22 +229,32 @@ int epoll_ctl(uv__os390_epoll* lst,
int op,
int fd,
struct epoll_event *event) {
- if(op == EPOLL_CTL_DEL) {
+ uv_mutex_lock(&global_epoll_lock);
+
+ if (op == EPOLL_CTL_DEL) {
if (fd >= lst->size || lst->items[fd].fd == -1) {
+ uv_mutex_unlock(&global_epoll_lock);
errno = ENOENT;
return -1;
}
lst->items[fd].fd = -1;
- } else if(op == EPOLL_CTL_ADD) {
- maybe_resize(lst, fd + 1);
+ } else if (op == EPOLL_CTL_ADD) {
+
+ /* Resizing to 'fd + 1' would expand the list to contain at least
+ * 'fd'. But we need to guarantee that the last index on the list
+ * is reserved for the message queue. So specify 'fd + 2' instead.
+ */
+ maybe_resize(lst, fd + 2);
if (lst->items[fd].fd != -1) {
+ uv_mutex_unlock(&global_epoll_lock);
errno = EEXIST;
return -1;
}
lst->items[fd].fd = fd;
lst->items[fd].events = event->events;
- } else if(op == EPOLL_CTL_MOD) {
+ } else if (op == EPOLL_CTL_MOD) {
if (fd >= lst->size || lst->items[fd].fd == -1) {
+ uv_mutex_unlock(&global_epoll_lock);
errno = ENOENT;
return -1;
}
@@ -172,44 +262,36 @@ int epoll_ctl(uv__os390_epoll* lst,
} else
abort();
+ uv_mutex_unlock(&global_epoll_lock);
return 0;
}
int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
int maxevents, int timeout) {
- size_t size;
+ nmsgsfds_t size;
struct pollfd* pfds;
int pollret;
int reventcount;
- uv_mutex_lock(&global_epoll_lock);
- uv_mutex_unlock(&global_epoll_lock);
- size = lst->size;
+ size = _SET_FDS_MSGS(size, 1, lst->size - 1);
pfds = lst->items;
pollret = poll(pfds, size, timeout);
- if(pollret == -1)
+ if (pollret <= 0)
return pollret;
+ pollret = _NFDS(pollret) + _NMSGS(pollret);
+
reventcount = 0;
- for (int i = 0; i < lst->size && i < maxevents; ++i) {
+ for (int i = 0;
+ i < lst->size && i < maxevents && reventcount < pollret; ++i) {
struct epoll_event ev;
- ev.events = 0;
- ev.fd = pfds[i].fd;
- if(!pfds[i].revents)
+ if (pfds[i].fd == -1 || pfds[i].revents == 0)
continue;
- if(pfds[i].revents & POLLRDNORM)
- ev.events = ev.events | POLLIN;
-
- if(pfds[i].revents & POLLWRNORM)
- ev.events = ev.events | POLLOUT;
-
- if(pfds[i].revents & POLLHUP)
- ev.events = ev.events | POLLHUP;
-
- pfds[i].revents = 0;
+ ev.fd = pfds[i].fd;
+ ev.events = pfds[i].revents;
events[reventcount++] = ev;
}
@@ -235,9 +317,14 @@ int epoll_file_close(int fd) {
}
void epoll_queue_close(uv__os390_epoll* lst) {
+ /* Remove epoll instance from global queue */
uv_mutex_lock(&global_epoll_lock);
QUEUE_REMOVE(&lst->member);
uv_mutex_unlock(&global_epoll_lock);
+
+ /* Free resources */
+ msgctl(lst->msg_queue, IPC_RMID, NULL);
+ lst->msg_queue = -1;
uv__free(lst->items);
lst->items = NULL;
}
@@ -332,3 +419,81 @@ char* mkdtemp(char* path) {
return path;
}
+
+
+ssize_t os390_readlink(const char* path, char* buf, size_t len) {
+ ssize_t rlen;
+ ssize_t vlen;
+ ssize_t plen;
+ char* delimiter;
+ char old_delim;
+ char* tmpbuf;
+ char realpathstr[PATH_MAX + 1];
+
+ tmpbuf = uv__malloc(len + 1);
+ if (tmpbuf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ rlen = readlink(path, tmpbuf, len);
+ if (rlen < 0) {
+ uv__free(tmpbuf);
+ return rlen;
+ }
+
+ if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {
+ /* Straightforward readlink. */
+ memcpy(buf, tmpbuf, rlen);
+ uv__free(tmpbuf);
+ return rlen;
+ }
+
+ /*
+ * There is a parmlib variable at the beginning
+ * which needs interpretation.
+ */
+ tmpbuf[rlen] = '\0';
+ delimiter = strchr(tmpbuf + 2, '/');
+ if (delimiter == NULL)
+ /* No slash at the end */
+ delimiter = strchr(tmpbuf + 2, '\0');
+
+ /* Read real path of the variable. */
+ old_delim = *delimiter;
+ *delimiter = '\0';
+ if (realpath(tmpbuf, realpathstr) == NULL) {
+ uv__free(tmpbuf);
+ return -1;
+ }
+
+ /* realpathstr is not guaranteed to end with null byte.*/
+ realpathstr[PATH_MAX] = '\0';
+
+ /* Reset the delimiter and fill up the buffer. */
+ *delimiter = old_delim;
+ plen = strlen(delimiter);
+ vlen = strlen(realpathstr);
+ rlen = plen + vlen;
+ if (rlen > len) {
+ uv__free(tmpbuf);
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ memcpy(buf, realpathstr, vlen);
+ memcpy(buf + vlen, delimiter, plen);
+
+ /* Done using temporary buffer. */
+ uv__free(tmpbuf);
+
+ return rlen;
+}
+
+
+size_t strnlen(const char* str, size_t maxlen) {
+ void* p = memchr(str, 0, maxlen);
+ if (p == NULL)
+ return maxlen;
+ else
+ return p - str;
+}
diff --git a/src/unix/os390-syscalls.h b/src/unix/os390-syscalls.h
index 61a7cee839..6e34a88cb9 100644
--- a/src/unix/os390-syscalls.h
+++ b/src/unix/os390-syscalls.h
@@ -50,6 +50,7 @@ typedef struct {
QUEUE member;
struct pollfd* items;
unsigned long size;
+ int msg_queue;
} uv__os390_epoll;
/* epoll api */
@@ -65,5 +66,7 @@ int scandir(const char* maindir, struct dirent*** namelist,
int (*compar)(const struct dirent **,
const struct dirent **));
char *mkdtemp(char* path);
+ssize_t os390_readlink(const char* path, char* buf, size_t len);
+size_t strnlen(const char* str, size_t maxlen);
#endif /* UV_OS390_SYSCALL_H_ */
diff --git a/src/unix/os390.c b/src/unix/os390.c
index 2ba5abf354..081438e8e7 100644
--- a/src/unix/os390.c
+++ b/src/unix/os390.c
@@ -25,6 +25,9 @@
#include <utmpx.h>
#include <unistd.h>
#include <sys/ps.h>
+#include <builtins.h>
+#include <termios.h>
+#include <sys/msg.h>
#if defined(__clang__)
#include "csrsic.h"
#else
@@ -32,6 +35,7 @@
#endif
#define CVT_PTR 0x10
+#define PSA_PTR 0x00
#define CSD_OFFSET 0x294
/*
@@ -69,6 +73,18 @@
/* CPC model length from the CSRSI Service. */
#define CPCMODEL_LENGTH 16
+/* Pointer to the home (current) ASCB. */
+#define PSAAOLD 0x224
+
+/* Pointer to rsm address space block extension. */
+#define ASCBRSME 0x16C
+
+/*
+ NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE.
+ It does not include 2G frames.
+*/
+#define RAXFMCT 0x2C
+
/* Thread Entry constants */
#define PGTH_CURRENT 1
#define PGTH_LEN 26
@@ -76,6 +92,9 @@
#pragma linkage(BPX4GTH, OS)
#pragma linkage(BPX1GTH, OS)
+/* TOD Clock resolution in nanoseconds */
+#define TOD_RES 4.096
+
typedef unsigned data_area_ptr_assign_type;
typedef union {
@@ -100,7 +119,7 @@ void uv_loadavg(double avg[3]) {
int uv__platform_loop_init(uv_loop_t* loop) {
uv__os390_epoll* ep;
- ep = epoll_create1(UV__EPOLL_CLOEXEC);
+ ep = epoll_create1(0);
loop->ep = ep;
if (ep == NULL)
return -errno;
@@ -118,9 +137,10 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
uint64_t uv__hrtime(uv_clocktype_t type) {
- struct timeval time;
- gettimeofday(&time, NULL);
- return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3;
+ unsigned long long timestamp;
+ __stckf(&timestamp);
+ /* Convert to nanoseconds */
+ return timestamp / TOD_RES;
}
@@ -337,13 +357,17 @@ uint64_t uv_get_total_memory(void) {
int uv_resident_set_memory(size_t* rss) {
- W_PSPROC buf;
+ char* psa;
+ char* ascb;
+ char* rax;
+ size_t nframes;
- memset(&buf, 0, sizeof(buf));
- if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1)
- return -EINVAL;
+ psa = PSA_PTR;
+ ascb = *(char* __ptr32 *)(psa + PSAAOLD);
+ rax = *(char* __ptr32 *)(ascb + ASCBRSME);
+ nframes = *(unsigned int*)(rax + RAXFMCT);
- *rss = buf.ps_size;
+ *rss = nframes * sysconf(_SC_PAGESIZE);
return 0;
}
@@ -364,7 +388,6 @@ int uv_uptime(double* uptime) {
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
- int result;
int idx;
siv1v2 info;
data_area_ptr cvt = {0};
@@ -663,11 +686,124 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
return 0;
}
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
+ const char* filename, unsigned int flags) {
+ uv__os390_epoll* ep;
+ _RFIS reg_struct;
+ char* path;
+ int rc;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ ep = handle->loop->ep;
+ assert(ep->msg_queue != -1);
+
+ reg_struct.__rfis_cmd = _RFIS_REG;
+ reg_struct.__rfis_qid = ep->msg_queue;
+ reg_struct.__rfis_type = 1;
+ memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
+
+ path = uv__strdup(filename);
+ if (path == NULL)
+ return -ENOMEM;
+
+ rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
+ if (rc != 0)
+ return -errno;
+
+ uv__handle_start(handle);
+ handle->path = path;
+ handle->cb = cb;
+ memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
+ sizeof(handle->rfis_rftok));
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ uv__os390_epoll* ep;
+ _RFIS reg_struct;
+ int rc;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ ep = handle->loop->ep;
+ assert(ep->msg_queue != -1);
+
+ reg_struct.__rfis_cmd = _RFIS_UNREG;
+ reg_struct.__rfis_qid = ep->msg_queue;
+ reg_struct.__rfis_type = 1;
+ memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
+ sizeof(handle->rfis_rftok));
+
+ /*
+ * This call will take "/" as the path argument in case we
+ * don't care to supply the correct path. The system will simply
+ * ignore it.
+ */
+ rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
+ if (rc != 0 && errno != EALREADY && errno != ENOENT)
+ abort();
+
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+static int os390_message_queue_handler(uv__os390_epoll* ep) {
+ uv_fs_event_t* handle;
+ int msglen;
+ int events;
+ _RFIM msg;
+
+ if (ep->msg_queue == -1)
+ return 0;
+
+ msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT);
+
+ if (msglen == -1 && errno == ENOMSG)
+ return 0;
+
+ if (msglen == -1)
+ abort();
+
+ events = 0;
+ if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
+ events = UV_CHANGE;
+ else if (msg.__rfim_event == _RFIM_RENAME)
+ events = UV_RENAME;
+ else
+ /* Some event that we are not interested in. */
+ return 0;
+
+ handle = *(uv_fs_event_t**)(msg.__rfim_utok);
+ handle->cb(handle, uv__basename_r(handle->path), events, 0);
+ return 1;
+}
+
+
void uv__io_poll(uv_loop_t* loop, int timeout) {
static const int max_safe_timeout = 1789569;
struct epoll_event events[1024];
struct epoll_event* pe;
struct epoll_event e;
+ uv__os390_epoll* ep;
int real_timeout;
QUEUE* q;
uv__io_t* w;
@@ -745,9 +881,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
assert(timeout != -1);
- timeout = real_timeout - timeout;
- if (timeout > 0)
+
+ if (timeout > 0) {
+ timeout = real_timeout - timeout;
continue;
+ }
return;
}
@@ -779,6 +917,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (fd == -1)
continue;
+ ep = loop->ep;
+ if (fd == ep->msg_queue) {
+ os390_message_queue_handler(ep);
+ continue;
+ }
+
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
@@ -843,7 +987,12 @@ void uv__set_process_title(const char* title) {
}
int uv__io_fork(uv_loop_t* loop) {
- uv__platform_loop_delete(loop);
+ /*
+ Nullify the msg queue but don't close it because
+ it is still being used by the parent.
+ */
+ loop->ep = NULL;
+ uv__platform_loop_delete(loop);
return uv__platform_loop_init(loop);
}
diff --git a/src/unix/pipe.c b/src/unix/pipe.c
index 4a812955b0..ac7cfb46a9 100644
--- a/src/unix/pipe.c
+++ b/src/unix/pipe.c
@@ -302,3 +302,56 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
else
return uv__handle_type(handle->accepted_fd);
}
+
+
+int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
+ unsigned desired_mode;
+ struct stat pipe_stat;
+ char* name_buffer;
+ size_t name_len;
+ int r;
+
+ if (handle == NULL || uv__stream_fd(handle) == -1)
+ return -EBADF;
+
+ if (mode != UV_READABLE &&
+ mode != UV_WRITABLE &&
+ mode != (UV_WRITABLE | UV_READABLE))
+ return -EINVAL;
+
+ if (fstat(uv__stream_fd(handle), &pipe_stat) == -1)
+ return -errno;
+
+ desired_mode = 0;
+ if (mode & UV_READABLE)
+ desired_mode |= S_IRUSR | S_IRGRP | S_IROTH;
+ if (mode & UV_WRITABLE)
+ desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+
+ /* Exit early if pipe already has desired mode. */
+ if ((pipe_stat.st_mode & desired_mode) == desired_mode)
+ return 0;
+
+ pipe_stat.st_mode |= desired_mode;
+
+ /* Unfortunately fchmod does not work on all platforms, we will use chmod. */
+ name_len = 0;
+ r = uv_pipe_getsockname(handle, NULL, &name_len);
+ if (r != UV_ENOBUFS)
+ return r;
+
+ name_buffer = uv__malloc(name_len);
+ if (name_buffer == NULL)
+ return UV_ENOMEM;
+
+ r = uv_pipe_getsockname(handle, name_buffer, &name_len);
+ if (r != 0) {
+ uv__free(name_buffer);
+ return r;
+ }
+
+ r = chmod(name_buffer, pipe_stat.st_mode);
+ uv__free(name_buffer);
+
+ return r != -1 ? 0 : -errno;
+}
diff --git a/src/unix/poll.c b/src/unix/poll.c
index 370994bd57..816c7dc2eb 100644
--- a/src/unix/poll.c
+++ b/src/unix/poll.c
@@ -33,8 +33,19 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
handle = container_of(w, uv_poll_t, io_watcher);
- if (events & POLLERR) {
- uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP);
+ /*
+ * As documented in the kernel source fs/kernfs/file.c #780
+ * poll will return POLLERR|POLLPRI in case of sysfs
+ * polling. This does not happen in case of out-of-band
+ * TCP messages.
+ *
+ * The above is the case on (at least) FreeBSD and Linux.
+ *
+ * So to properly determine a POLLPRI or a POLLERR we need
+ * to check for both.
+ */
+ if ((events & POLLERR) && !(events & UV__POLLPRI)) {
+ uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
uv__handle_stop(handle);
handle->poll_cb(handle, -EBADF, 0);
return;
@@ -43,6 +54,8 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
pevents = 0;
if (events & POLLIN)
pevents |= UV_READABLE;
+ if (events & UV__POLLPRI)
+ pevents |= UV_PRIORITIZED;
if (events & POLLOUT)
pevents |= UV_WRITABLE;
if (events & UV__POLLRDHUP)
@@ -86,8 +99,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
static void uv__poll_stop(uv_poll_t* handle) {
uv__io_stop(handle->loop,
&handle->io_watcher,
- POLLIN | POLLOUT | UV__POLLRDHUP);
+ POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
uv__handle_stop(handle);
+ uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd);
}
@@ -101,7 +115,8 @@ int uv_poll_stop(uv_poll_t* handle) {
int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
int events;
- assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
+ assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
+ UV_PRIORITIZED)) == 0);
assert(!uv__is_closing(handle));
uv__poll_stop(handle);
@@ -112,6 +127,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
events = 0;
if (pevents & UV_READABLE)
events |= POLLIN;
+ if (pevents & UV_PRIORITIZED)
+ events |= UV__POLLPRI;
if (pevents & UV_WRITABLE)
events |= POLLOUT;
if (pevents & UV_DISCONNECT)
diff --git a/src/unix/process.c b/src/unix/process.c
index f2fe30521c..9842710d0e 100644
--- a/src/unix/process.c
+++ b/src/unix/process.c
@@ -279,9 +279,12 @@ static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd) {
+ sigset_t set;
int close_fd;
int use_fd;
+ int err;
int fd;
+ int n;
if (options->flags & UV_PROCESS_DETACHED)
setsid();
@@ -376,6 +379,31 @@ static void uv__process_child_init(const uv_process_options_t* options,
environ = options->env;
}
+ /* Reset signal disposition. Use a hard-coded limit because NSIG
+ * is not fixed on Linux: it's either 32, 34 or 64, depending on
+ * whether RT signals are enabled. We are not allowed to touch
+ * RT signal handlers, glibc uses them internally.
+ */
+ for (n = 1; n < 32; n += 1) {
+ if (n == SIGKILL || n == SIGSTOP)
+ continue; /* Can't be changed. */
+
+ if (SIG_ERR != signal(n, SIG_DFL))
+ continue;
+
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ /* Reset signal mask. */
+ sigemptyset(&set);
+ err = pthread_sigmask(SIG_SETMASK, &set, NULL);
+
+ if (err != 0) {
+ uv__write_int(error_fd, -err);
+ _exit(127);
+ }
+
execvp(options->file, options->args);
uv__write_int(error_fd, -errno);
_exit(127);
@@ -391,6 +419,7 @@ int uv_spawn(uv_loop_t* loop,
return -ENOSYS;
#else
int signal_pipe[2] = { -1, -1 };
+ int pipes_storage[8][2];
int (*pipes)[2];
int stdio_count;
ssize_t r;
@@ -415,7 +444,10 @@ int uv_spawn(uv_loop_t* loop,
stdio_count = 3;
err = -ENOMEM;
- pipes = uv__malloc(stdio_count * sizeof(*pipes));
+ pipes = pipes_storage;
+ if (stdio_count > (int) ARRAY_SIZE(pipes_storage))
+ pipes = uv__malloc(stdio_count * sizeof(*pipes));
+
if (pipes == NULL)
goto error;
@@ -520,7 +552,9 @@ int uv_spawn(uv_loop_t* loop,
process->pid = pid;
process->exit_cb = options->exit_cb;
- uv__free(pipes);
+ if (pipes != pipes_storage)
+ uv__free(pipes);
+
return exec_errorno;
error:
@@ -534,7 +568,9 @@ error:
if (pipes[i][1] != -1)
uv__close_nocheckstdio(pipes[i][1]);
}
- uv__free(pipes);
+
+ if (pipes != pipes_storage)
+ uv__free(pipes);
}
return err;
diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c
index 9160f7eafb..1b3a798820 100644
--- a/src/unix/proctitle.c
+++ b/src/unix/proctitle.c
@@ -26,6 +26,8 @@
extern void uv__set_process_title(const char* title);
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static void* args_mem;
static struct {
@@ -34,6 +36,11 @@ static struct {
} process_title;
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
char** uv_setup_args(int argc, char** argv) {
char** new_argv;
size_t size;
@@ -81,12 +88,16 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
- if (process_title.len == 0)
- return 0;
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ if (process_title.len != 0) {
+ /* No need to terminate, byte after is always '\0'. */
+ strncpy(process_title.str, title, process_title.len);
+ uv__set_process_title(title);
+ }
- /* No need to terminate, byte after is always '\0'. */
- strncpy(process_title.str, title, process_title.len);
- uv__set_process_title(title);
+ uv_mutex_unlock(&process_title_mutex);
return 0;
}
@@ -95,12 +106,22 @@ int uv_set_process_title(const char* title) {
int uv_get_process_title(char* buffer, size_t size) {
if (buffer == NULL || size == 0)
return -EINVAL;
- else if (size <= process_title.len)
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ if (size <= process_title.len) {
+ uv_mutex_unlock(&process_title_mutex);
return -ENOBUFS;
+ }
+
+ if (process_title.len != 0)
+ memcpy(buffer, process_title.str, process_title.len + 1);
- memcpy(buffer, process_title.str, process_title.len + 1);
buffer[process_title.len] = '\0';
+ uv_mutex_unlock(&process_title_mutex);
+
return 0;
}
diff --git a/src/unix/pthread-barrier.c b/src/unix/pthread-barrier.c
deleted file mode 100644
index b6e604d46d..0000000000
--- a/src/unix/pthread-barrier.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
-Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com>
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-#include "uv-common.h"
-#include "pthread-barrier.h"
-
-#include <stdlib.h>
-#include <assert.h>
-
-/* TODO: support barrier_attr */
-int pthread_barrier_init(pthread_barrier_t* barrier,
- const void* barrier_attr,
- unsigned count) {
- int rc;
- _uv_barrier* b;
-
- if (barrier == NULL || count == 0)
- return EINVAL;
-
- if (barrier_attr != NULL)
- return ENOTSUP;
-
- b = uv__malloc(sizeof(*b));
- if (b == NULL)
- return ENOMEM;
-
- b->in = 0;
- b->out = 0;
- b->threshold = count;
-
- if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
- goto error2;
- if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
- goto error;
-
- barrier->b = b;
- return 0;
-
-error:
- pthread_mutex_destroy(&b->mutex);
-error2:
- uv__free(b);
- return rc;
-}
-
-int pthread_barrier_wait(pthread_barrier_t* barrier) {
- int rc;
- _uv_barrier* b;
-
- if (barrier == NULL || barrier->b == NULL)
- return EINVAL;
-
- b = barrier->b;
- /* Lock the mutex*/
- if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
- return rc;
-
- /* Increment the count. If this is the first thread to reach the threshold,
- wake up waiters, unlock the mutex, then return
- PTHREAD_BARRIER_SERIAL_THREAD. */
- if (++b->in == b->threshold) {
- b->in = 0;
- b->out = b->threshold - 1;
- rc = pthread_cond_signal(&b->cond);
- assert(rc == 0);
-
- pthread_mutex_unlock(&b->mutex);
- return PTHREAD_BARRIER_SERIAL_THREAD;
- }
- /* Otherwise, wait for other threads until in is set to 0,
- then return 0 to indicate this is not the first thread. */
- do {
- if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
- break;
- } while (b->in != 0);
-
- /* mark thread exit */
- b->out--;
- pthread_cond_signal(&b->cond);
- pthread_mutex_unlock(&b->mutex);
- return rc;
-}
-
-int pthread_barrier_destroy(pthread_barrier_t* barrier) {
- int rc;
- _uv_barrier* b;
-
- if (barrier == NULL || barrier->b == NULL)
- return EINVAL;
-
- b = barrier->b;
-
- if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
- return rc;
-
- if (b->in > 0 || b->out > 0)
- rc = EBUSY;
-
- pthread_mutex_unlock(&b->mutex);
-
- if (rc)
- return rc;
-
- pthread_cond_destroy(&b->cond);
- pthread_mutex_destroy(&b->mutex);
- uv__free(barrier->b);
- barrier->b = NULL;
- return 0;
-}
diff --git a/src/unix/signal.c b/src/unix/signal.c
index cb09ead50a..3759778011 100644
--- a/src/unix/signal.c
+++ b/src/unix/signal.c
@@ -28,6 +28,9 @@
#include <string.h>
#include <unistd.h>
+#ifndef SA_RESTART
+# define SA_RESTART 0
+#endif
typedef struct {
uv_signal_t* handle;
@@ -216,7 +219,9 @@ static int uv__signal_register_handler(int signum, int oneshot) {
if (sigfillset(&sa.sa_mask))
abort();
sa.sa_handler = uv__signal_handler;
- sa.sa_flags = oneshot ? SA_RESETHAND : 0;
+ sa.sa_flags = SA_RESTART;
+ if (oneshot)
+ sa.sa_flags |= SA_RESETHAND;
/* XXX save old action so we can restore it later on? */
if (sigaction(signum, &sa, NULL))
diff --git a/src/unix/stream.c b/src/unix/stream.c
index 7b23d16ecf..6fc0a01f5a 100644
--- a/src/unix/stream.c
+++ b/src/unix/stream.c
@@ -514,7 +514,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
int err;
stream = container_of(w, uv_stream_t, io_watcher);
- assert(events == POLLIN);
+ assert(events & POLLIN);
assert(stream->accepted_fd == -1);
assert(!(stream->flags & UV_CLOSING));
@@ -750,6 +750,7 @@ static void uv__write(uv_stream_t* stream) {
int iovmax;
int iovcnt;
ssize_t n;
+ int err;
start:
@@ -782,14 +783,21 @@ start:
*/
if (req->send_handle) {
+ int fd_to_send;
struct msghdr msg;
struct cmsghdr *cmsg;
- int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
union {
char data[64];
struct cmsghdr alias;
} scratch;
+ if (uv__is_closing(req->send_handle)) {
+ err = -EBADF;
+ goto error;
+ }
+
+ fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
+
memset(&scratch, 0, sizeof(scratch));
assert(fd_to_send >= 0);
@@ -851,15 +859,9 @@ start:
}
if (n < 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK) {
- /* Error */
- req->error = -errno;
- uv__write_req_finish(req);
- uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
- if (!uv__io_active(&stream->io_watcher, POLLIN))
- uv__handle_stop(stream);
- uv__stream_osx_interrupt_select(stream);
- return;
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENOBUFS) {
+ err = -errno;
+ goto error;
} else if (stream->flags & UV_STREAM_BLOCKING) {
/* If this is a blocking stream, try again. */
goto start;
@@ -923,6 +925,16 @@ start:
/* Notify select() thread about state change */
uv__stream_osx_interrupt_select(stream);
+
+ return;
+
+error:
+ req->error = err;
+ uv__write_req_finish(req);
+ uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
+ if (!uv__io_active(&stream->io_watcher, POLLIN))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
}
@@ -1249,8 +1261,9 @@ static void uv__read(uv_stream_t* stream) {
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
- assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) &&
- "uv_shutdown (unix) only supports uv_handle_t right now");
+ assert(stream->type == UV_TCP ||
+ stream->type == UV_TTY ||
+ stream->type == UV_NAMED_PIPE);
if (!(stream->flags & UV_STREAM_WRITABLE) ||
stream->flags & UV_STREAM_SHUT ||
diff --git a/src/unix/sunos.c b/src/unix/sunos.c
index 2dc02ae457..a72c26a01f 100644
--- a/src/unix/sunos.c
+++ b/src/unix/sunos.c
@@ -747,7 +747,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) {
return 1;
if (ent->ifa_addr == NULL)
return 1;
- if (ent->ifa_addr->sa_family == PF_PACKET)
+ if (ent->ifa_addr->sa_family != AF_INET &&
+ ent->ifa_addr->sa_family != AF_INET6)
return 1;
return 0;
}
@@ -756,7 +757,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
struct ifaddrs* addrs;
struct ifaddrs* ent;
- int i;
if (getifaddrs(&addrs))
return -errno;
diff --git a/src/unix/tcp.c b/src/unix/tcp.c
index c423dcb15f..c7c8d21c66 100644
--- a/src/unix/tcp.c
+++ b/src/unix/tcp.c
@@ -28,15 +28,12 @@
#include <errno.h>
-static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
+static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
+ struct sockaddr_storage saddr;
+ socklen_t slen;
int sockfd;
int err;
- if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
- handle->flags |= flags;
- return 0;
- }
-
err = uv__socket(domain, SOCK_STREAM, 0);
if (err < 0)
return err;
@@ -48,10 +45,74 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
return err;
}
+ if (flags & UV_HANDLE_BOUND) {
+ /* Bind this new socket to an arbitrary port */
+ slen = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen);
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+
+ err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen);
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+ }
+
return 0;
}
+static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
+ struct sockaddr_storage saddr;
+ socklen_t slen;
+
+ if (domain == AF_UNSPEC) {
+ handle->flags |= flags;
+ return 0;
+ }
+
+ if (uv__stream_fd(handle) != -1) {
+
+ if (flags & UV_HANDLE_BOUND) {
+
+ if (handle->flags & UV_HANDLE_BOUND) {
+ /* It is already bound to a port. */
+ handle->flags |= flags;
+ return 0;
+ }
+
+ /* Query to see if tcp socket is bound. */
+ slen = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
+ return -errno;
+
+ if ((saddr.ss_family == AF_INET6 &&
+ ((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
+ (saddr.ss_family == AF_INET &&
+ ((struct sockaddr_in*) &saddr)->sin_port != 0)) {
+ /* Handle is already bound to a port. */
+ handle->flags |= flags;
+ return 0;
+ }
+
+ /* Bind to arbitrary port */
+ if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
+ return -errno;
+ }
+
+ handle->flags |= flags;
+ return 0;
+ }
+
+ return new_socket(handle, domain, flags);
+}
+
+
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
int domain;
@@ -260,6 +321,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
static int single_accept = -1;
+ unsigned long flags;
int err;
if (tcp->delayed_error)
@@ -273,30 +335,17 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
if (single_accept)
tcp->flags |= UV_TCP_SINGLE_ACCEPT;
- err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
- if (err)
- return err;
-
-#ifdef __MVS__
+ flags = UV_STREAM_READABLE;
+#if defined(__MVS__)
/* on zOS the listen call does not bind automatically
if the socket is unbound. Hence the manual binding to
an arbitrary port is required to be done manually
*/
-
- if (!(tcp->flags & UV_HANDLE_BOUND)) {
- struct sockaddr_storage saddr;
- socklen_t slen = sizeof(saddr);
- memset(&saddr, 0, sizeof(saddr));
-
- if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen))
- return -errno;
-
- if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen))
- return -errno;
-
- tcp->flags |= UV_HANDLE_BOUND;
- }
-#endif
+ flags |= UV_HANDLE_BOUND;
+#endif
+ err = maybe_new_socket(tcp, AF_INET, flags);
+ if (err)
+ return err;
if (listen(tcp->io_watcher.fd, backlog))
return -errno;
diff --git a/src/unix/thread.c b/src/unix/thread.c
index a9b5e4c02a..abaca295d2 100644
--- a/src/unix/thread.c
+++ b/src/unix/thread.c
@@ -41,36 +41,159 @@
#define NANOSEC ((uint64_t) 1e9)
-int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
- int err;
- pthread_attr_t* attr;
-#if defined(__APPLE__)
- pthread_attr_t attr_storage;
- struct rlimit lim;
+#if defined(UV__PTHREAD_BARRIER_FALLBACK)
+/* TODO: support barrier_attr */
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const void* barrier_attr,
+ unsigned count) {
+ int rc;
+ _uv_barrier* b;
+
+ if (barrier == NULL || count == 0)
+ return EINVAL;
+
+ if (barrier_attr != NULL)
+ return ENOTSUP;
+
+ b = uv__malloc(sizeof(*b));
+ if (b == NULL)
+ return ENOMEM;
+
+ b->in = 0;
+ b->out = 0;
+ b->threshold = count;
+
+ if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
+ goto error2;
+ if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
+ goto error;
+
+ barrier->b = b;
+ return 0;
+
+error:
+ pthread_mutex_destroy(&b->mutex);
+error2:
+ uv__free(b);
+ return rc;
+}
+
+int pthread_barrier_wait(pthread_barrier_t* barrier) {
+ int rc;
+ _uv_barrier* b;
+
+ if (barrier == NULL || barrier->b == NULL)
+ return EINVAL;
+
+ b = barrier->b;
+ /* Lock the mutex*/
+ if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
+ return rc;
+
+ /* Increment the count. If this is the first thread to reach the threshold,
+ wake up waiters, unlock the mutex, then return
+ PTHREAD_BARRIER_SERIAL_THREAD. */
+ if (++b->in == b->threshold) {
+ b->in = 0;
+ b->out = b->threshold - 1;
+ rc = pthread_cond_signal(&b->cond);
+ assert(rc == 0);
+
+ pthread_mutex_unlock(&b->mutex);
+ return PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+ /* Otherwise, wait for other threads until in is set to 0,
+ then return 0 to indicate this is not the first thread. */
+ do {
+ if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
+ break;
+ } while (b->in != 0);
+
+ /* mark thread exit */
+ b->out--;
+ pthread_cond_signal(&b->cond);
+ pthread_mutex_unlock(&b->mutex);
+ return rc;
+}
+
+int pthread_barrier_destroy(pthread_barrier_t* barrier) {
+ int rc;
+ _uv_barrier* b;
+
+ if (barrier == NULL || barrier->b == NULL)
+ return EINVAL;
+
+ b = barrier->b;
+
+ if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
+ return rc;
+
+ if (b->in > 0 || b->out > 0)
+ rc = EBUSY;
+
+ pthread_mutex_unlock(&b->mutex);
+
+ if (rc)
+ return rc;
+
+ pthread_cond_destroy(&b->cond);
+ pthread_mutex_destroy(&b->mutex);
+ uv__free(barrier->b);
+ barrier->b = NULL;
+ return 0;
+}
#endif
- /* On OSX threads other than the main thread are created with a reduced stack
- * size by default, adjust it to RLIMIT_STACK.
- */
-#if defined(__APPLE__)
- if (getrlimit(RLIMIT_STACK, &lim))
- abort();
- attr = &attr_storage;
- if (pthread_attr_init(attr))
+/* On MacOS, threads other than the main thread are created with a reduced
+ * stack size by default. Adjust to RLIMIT_STACK aligned to the page size.
+ *
+ * On Linux, threads created by musl have a much smaller stack than threads
+ * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
+ */
+static size_t thread_stack_size(void) {
+#if defined(__APPLE__) || defined(__linux__)
+ struct rlimit lim;
+
+ if (getrlimit(RLIMIT_STACK, &lim))
abort();
if (lim.rlim_cur != RLIM_INFINITY) {
/* pthread_attr_setstacksize() expects page-aligned values. */
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
-
if (lim.rlim_cur >= PTHREAD_STACK_MIN)
- if (pthread_attr_setstacksize(attr, lim.rlim_cur))
- abort();
+ return lim.rlim_cur;
}
+#endif
+
+#if !defined(__linux__)
+ return 0;
+#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
+ return 4 << 20; /* glibc default. */
#else
- attr = NULL;
+ return 2 << 20; /* glibc default. */
#endif
+}
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+ int err;
+ size_t stack_size;
+ pthread_attr_t* attr;
+ pthread_attr_t attr_storage;
+
+ attr = NULL;
+ stack_size = thread_stack_size();
+
+ if (stack_size > 0) {
+ attr = &attr_storage;
+
+ if (pthread_attr_init(attr))
+ abort();
+
+ if (pthread_attr_setstacksize(attr, stack_size))
+ abort();
+ }
err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg);
@@ -118,6 +241,25 @@ int uv_mutex_init(uv_mutex_t* mutex) {
}
+int uv_mutex_init_recursive(uv_mutex_t* mutex) {
+ pthread_mutexattr_t attr;
+ int err;
+
+ if (pthread_mutexattr_init(&attr))
+ abort();
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+ abort();
+
+ err = pthread_mutex_init(mutex, &attr);
+
+ if (pthread_mutexattr_destroy(&attr))
+ abort();
+
+ return -err;
+}
+
+
void uv_mutex_destroy(uv_mutex_t* mutex) {
if (pthread_mutex_destroy(mutex))
abort();
@@ -281,18 +423,20 @@ int uv_sem_trywait(uv_sem_t* sem) {
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
uv_sem_t semid;
- struct sembuf buf;
int err;
+ union {
+ int val;
+ struct semid_ds* buf;
+ unsigned short* array;
+ } arg;
- buf.sem_num = 0;
- buf.sem_op = value;
- buf.sem_flg = 0;
semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR);
if (semid == -1)
return -errno;
- if (-1 == semop(semid, &buf, 1)) {
+ arg.val = value;
+ if (-1 == semctl(semid, 0, SETVAL, arg)) {
err = errno;
if (-1 == semctl(*sem, 0, IPC_RMID))
abort();
@@ -424,7 +568,7 @@ int uv_cond_init(uv_cond_t* cond) {
if (err)
return -err;
-#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21)
err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
if (err)
goto error2;
@@ -511,7 +655,8 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
timeout += uv__hrtime(UV_CLOCK_PRECISE);
ts.tv_sec = timeout / NANOSEC;
ts.tv_nsec = timeout % NANOSEC;
-#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+
/*
* The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
* but has this alternative function instead.
@@ -519,7 +664,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
#else
r = pthread_cond_timedwait(cond, mutex, &ts);
-#endif /* __ANDROID__ */
+#endif /* __ANDROID_API__ */
#endif
diff --git a/src/unix/tty.c b/src/unix/tty.c
index b2d37f4c2c..357f9748f6 100644
--- a/src/unix/tty.c
+++ b/src/unix/tty.c
@@ -48,6 +48,42 @@ static int uv__tty_is_slave(const int fd) {
char dummy[256];
result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
+#elif defined(__NetBSD__)
+ /*
+ * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave
+ * device name for both descriptors, the master one and slave one.
+ *
+ * Implement function to compare major device number with pts devices.
+ *
+ * The major numbers are machine-dependent, on NetBSD/amd64 they are
+ * respectively:
+ * - master tty: ptc - major 6
+ * - slave tty: pts - major 5
+ */
+
+ struct stat sb;
+ /* Lookup device's major for the pts driver and cache it. */
+ static devmajor_t pts = NODEVMAJOR;
+
+ if (pts == NODEVMAJOR) {
+ pts = getdevmajor("pts", S_IFCHR);
+ if (pts == NODEVMAJOR)
+ abort();
+ }
+
+ /* Lookup stat structure behind the file descriptor. */
+ if (fstat(fd, &sb) != 0)
+ abort();
+
+ /* Assert character device. */
+ if (!S_ISCHR(sb.st_mode))
+ abort();
+
+ /* Assert valid major. */
+ if (major(sb.st_rdev) == NODEVMAJOR)
+ abort();
+
+ result = (pts == major(sb.st_rdev));
#else
/* Fallback to ptsname
*/
diff --git a/src/unix/udp.c b/src/unix/udp.c
index c556325de0..a475bf5741 100644
--- a/src/unix/udp.c
+++ b/src/unix/udp.c
@@ -237,8 +237,10 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
size = sendmsg(handle->io_watcher.fd, &h, 0);
} while (size == -1 && errno == EINTR);
- if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
- break;
+ if (size == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
+ break;
+ }
req->status = (size == -1 ? -errno : size);
@@ -472,7 +474,7 @@ int uv__udp_try_send(uv_udp_t* handle,
} while (size == -1 && errno == EINTR);
if (size == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK)
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
return -EAGAIN;
else
return -errno;
diff --git a/src/uv-data-getter-setters.c b/src/uv-data-getter-setters.c
new file mode 100644
index 0000000000..533e4a2fe1
--- /dev/null
+++ b/src/uv-data-getter-setters.c
@@ -0,0 +1,96 @@
+#include "uv.h"
+
+const char* uv_handle_type_name(uv_handle_type type) {
+ switch (type) {
+#define XX(uc,lc) case UV_##uc: return #lc;
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+ case UV_FILE: return "file";
+ case UV_HANDLE_TYPE_MAX:
+ case UV_UNKNOWN_HANDLE: return NULL;
+ }
+ return NULL;
+}
+
+uv_handle_type uv_handle_get_type(const uv_handle_t* handle) {
+ return handle->type;
+}
+
+void* uv_handle_get_data(const uv_handle_t* handle) {
+ return handle->data;
+}
+
+uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) {
+ return handle->loop;
+}
+
+void uv_handle_set_data(uv_handle_t* handle, void* data) {
+ handle->data = data;
+}
+
+const char* uv_req_type_name(uv_req_type type) {
+ switch (type) {
+#define XX(uc,lc) case UV_##uc: return #lc;
+ UV_REQ_TYPE_MAP(XX)
+#undef XX
+ case UV_REQ_TYPE_MAX:
+ case UV_UNKNOWN_REQ: return NULL;
+ }
+ return NULL;
+}
+
+uv_req_type uv_req_get_type(const uv_req_t* req) {
+ return req->type;
+}
+
+void* uv_req_get_data(const uv_req_t* req) {
+ return req->data;
+}
+
+void uv_req_set_data(uv_req_t* req, void* data) {
+ req->data = data;
+}
+
+size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) {
+ return stream->write_queue_size;
+}
+
+size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) {
+ return handle->send_queue_size;
+}
+
+size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) {
+ return handle->send_queue_count;
+}
+
+uv_pid_t uv_process_get_pid(const uv_process_t* proc) {
+ return proc->pid;
+}
+
+uv_fs_type uv_fs_get_type(const uv_fs_t* req) {
+ return req->fs_type;
+}
+
+ssize_t uv_fs_get_result(const uv_fs_t* req) {
+ return req->result;
+}
+
+void* uv_fs_get_ptr(const uv_fs_t* req) {
+ return req->ptr;
+}
+
+const char* uv_fs_get_path(const uv_fs_t* req) {
+ return req->path;
+}
+
+uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) {
+ return &req->statbuf;
+}
+
+void* uv_loop_get_data(const uv_loop_t* loop) {
+ return loop->data;
+}
+
+void uv_loop_set_data(uv_loop_t* loop, void* data) {
+ loop->data = data;
+}
diff --git a/src/win/dl.c b/src/win/dl.c
index 39e400ab2d..97ac1c1ad1 100644
--- a/src/win/dl.c
+++ b/src/win/dl.c
@@ -22,7 +22,7 @@
#include "uv.h"
#include "internal.h"
-static int uv__dlerror(uv_lib_t* lib, int errorno);
+static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno);
int uv_dlopen(const char* filename, uv_lib_t* lib) {
@@ -37,12 +37,12 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) {
-1,
filename_w,
ARRAY_SIZE(filename_w))) {
- return uv__dlerror(lib, GetLastError());
+ return uv__dlerror(lib, filename, GetLastError());
}
lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (lib->handle == NULL) {
- return uv__dlerror(lib, GetLastError());
+ return uv__dlerror(lib, filename, GetLastError());
}
return 0;
@@ -65,7 +65,7 @@ void uv_dlclose(uv_lib_t* lib) {
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
*ptr = (void*) GetProcAddress(lib->handle, name);
- return uv__dlerror(lib, *ptr ? 0 : GetLastError());
+ return uv__dlerror(lib, "", *ptr ? 0 : GetLastError());
}
@@ -88,31 +88,46 @@ static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
-static int uv__dlerror(uv_lib_t* lib, int errorno) {
+static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) {
+ DWORD_PTR arg;
DWORD res;
+ char* msg;
if (lib->errmsg) {
- LocalFree((void*)lib->errmsg);
+ LocalFree(lib->errmsg);
lib->errmsg = NULL;
}
- if (errorno) {
+ if (errorno == 0)
+ return 0;
+
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPSTR) &lib->errmsg, 0, NULL);
+
+ if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
- (LPSTR) &lib->errmsg, 0, NULL);
- if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
- res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
- 0, (LPSTR) &lib->errmsg, 0, NULL);
- }
-
- if (!res) {
- uv__format_fallback_error(lib, errorno);
- }
+ 0, (LPSTR) &lib->errmsg, 0, NULL);
+ }
+
+ if (res && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) {
+ msg = lib->errmsg;
+ lib->errmsg = NULL;
+ arg = (DWORD_PTR) filename;
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_FROM_STRING,
+ msg,
+ 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg);
+ LocalFree(msg);
}
- return errorno ? -1 : 0;
+ if (!res)
+ uv__format_fallback_error(lib, errorno);
+
+ return -1;
}
diff --git a/src/win/error.c b/src/win/error.c
index 642d1112e1..9b03bfef6b 100644
--- a/src/win/error.c
+++ b/src/win/error.c
@@ -58,7 +58,7 @@ void uv_fatal_error(const int errorno, const char* syscall) {
LocalFree(buf);
}
- *((char*)NULL) = 0xff; /* Force debug break */
+ DebugBreak();
abort();
}
diff --git a/src/win/fs.c b/src/win/fs.c
index 2d72cdc70f..097b00e08d 100644
--- a/src/win/fs.c
+++ b/src/win/fs.c
@@ -43,11 +43,26 @@
#define UV_FS_CLEANEDUP 0x0010
-#define QUEUE_FS_TP_JOB(loop, req) \
- do { \
- uv__req_register(loop, req); \
- uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
- } while (0)
+#define INIT(subtype) \
+ do { \
+ if (req == NULL) \
+ return UV_EINVAL; \
+ uv_fs_req_init(loop, req, subtype, cb); \
+ } \
+ while (0)
+
+#define POST \
+ do { \
+ if (cb != NULL) { \
+ uv__req_register(loop, req); \
+ uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
+ return 0; \
+ } else { \
+ uv__fs_work(&req->work_req); \
+ return req->result; \
+ } \
+ } \
+ while (0)
#define SET_REQ_RESULT(req, result_value) \
do { \
@@ -113,6 +128,7 @@ const WCHAR LONG_PATH_PREFIX_LEN = 4;
const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
const WCHAR UNC_PATH_PREFIX_LEN = 8;
+static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
void uv_fs_init(void) {
_fmode = _O_BINARY;
@@ -220,6 +236,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
uv_fs_type fs_type, const uv_fs_cb cb) {
+ uv__once_init();
UV_REQ_INIT(req, UV_FS);
req->loop = loop;
req->flags = 0;
@@ -398,21 +415,21 @@ void fs__open(uv_fs_t* req) {
umask(current_umask);
/* convert flags and mode to CreateFile parameters */
- switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
- case _O_RDONLY:
+ switch (flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) {
+ case UV_FS_O_RDONLY:
access = FILE_GENERIC_READ;
break;
- case _O_WRONLY:
+ case UV_FS_O_WRONLY:
access = FILE_GENERIC_WRITE;
break;
- case _O_RDWR:
+ case UV_FS_O_RDWR:
access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
break;
default:
goto einval;
}
- if (flags & _O_APPEND) {
+ if (flags & UV_FS_O_APPEND) {
access &= ~FILE_WRITE_DATA;
access |= FILE_APPEND_DATA;
}
@@ -422,26 +439,33 @@ void fs__open(uv_fs_t* req) {
* does. We indiscriminately use all the sharing modes, to match
* UNIX semantics. In particular, this ensures that the file can
* be deleted even whilst it's open, fixing issue #1449.
+ * We still support exclusive sharing mode, since it is necessary
+ * for opening raw block devices, otherwise Windows will prevent
+ * any attempt to write past the master boot record.
*/
- share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ if (flags & UV_FS_O_EXLOCK) {
+ share = 0;
+ } else {
+ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ }
- switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
+ switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) {
case 0:
- case _O_EXCL:
+ case UV_FS_O_EXCL:
disposition = OPEN_EXISTING;
break;
- case _O_CREAT:
+ case UV_FS_O_CREAT:
disposition = OPEN_ALWAYS;
break;
- case _O_CREAT | _O_EXCL:
- case _O_CREAT | _O_TRUNC | _O_EXCL:
+ case UV_FS_O_CREAT | UV_FS_O_EXCL:
+ case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL:
disposition = CREATE_NEW;
break;
- case _O_TRUNC:
- case _O_TRUNC | _O_EXCL:
+ case UV_FS_O_TRUNC:
+ case UV_FS_O_TRUNC | UV_FS_O_EXCL:
disposition = TRUNCATE_EXISTING;
break;
- case _O_CREAT | _O_TRUNC:
+ case UV_FS_O_CREAT | UV_FS_O_TRUNC:
disposition = CREATE_ALWAYS;
break;
default:
@@ -449,34 +473,49 @@ void fs__open(uv_fs_t* req) {
}
attributes |= FILE_ATTRIBUTE_NORMAL;
- if (flags & _O_CREAT) {
+ if (flags & UV_FS_O_CREAT) {
if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
attributes |= FILE_ATTRIBUTE_READONLY;
}
}
- if (flags & _O_TEMPORARY ) {
+ if (flags & UV_FS_O_TEMPORARY ) {
attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
access |= DELETE;
}
- if (flags & _O_SHORT_LIVED) {
+ if (flags & UV_FS_O_SHORT_LIVED) {
attributes |= FILE_ATTRIBUTE_TEMPORARY;
}
- switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
+ switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) {
case 0:
break;
- case _O_SEQUENTIAL:
+ case UV_FS_O_SEQUENTIAL:
attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
break;
- case _O_RANDOM:
+ case UV_FS_O_RANDOM:
attributes |= FILE_FLAG_RANDOM_ACCESS;
break;
default:
goto einval;
}
+ if (flags & UV_FS_O_DIRECT) {
+ attributes |= FILE_FLAG_NO_BUFFERING;
+ }
+
+ switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) {
+ case 0:
+ break;
+ case UV_FS_O_DSYNC:
+ case UV_FS_O_SYNC:
+ attributes |= FILE_FLAG_WRITE_THROUGH;
+ break;
+ default:
+ goto einval;
+ }
+
/* Setting this flag makes it possible to open a directory. */
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
@@ -489,9 +528,9 @@ void fs__open(uv_fs_t* req) {
NULL);
if (file == INVALID_HANDLE_VALUE) {
DWORD error = GetLastError();
- if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) &&
- !(flags & _O_EXCL)) {
- /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */
+ if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) &&
+ !(flags & UV_FS_O_EXCL)) {
+ /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was */
/* specified, it means the path referred to a directory. */
SET_REQ_UV_ERROR(req, UV_EISDIR, error);
} else {
@@ -556,9 +595,14 @@ void fs__read(uv_fs_t* req) {
DWORD error;
int result;
unsigned int index;
+ LARGE_INTEGER original_position;
+ LARGE_INTEGER zero_offset;
+ int restore_position;
VERIFY_FD(fd, req);
+ zero_offset.QuadPart = 0;
+ restore_position = 0;
handle = uv__get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
@@ -569,6 +613,10 @@ void fs__read(uv_fs_t* req) {
if (offset != -1) {
memset(&overlapped, 0, sizeof overlapped);
overlapped_ptr = &overlapped;
+ if (SetFilePointerEx(handle, zero_offset, &original_position,
+ FILE_CURRENT)) {
+ restore_position = 1;
+ }
} else {
overlapped_ptr = NULL;
}
@@ -593,6 +641,9 @@ void fs__read(uv_fs_t* req) {
++index;
} while (result && index < req->fs.info.nbufs);
+ if (restore_position)
+ SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN);
+
if (result || bytes > 0) {
SET_REQ_RESULT(req, bytes);
} else {
@@ -615,9 +666,14 @@ void fs__write(uv_fs_t* req) {
DWORD bytes;
int result;
unsigned int index;
+ LARGE_INTEGER original_position;
+ LARGE_INTEGER zero_offset;
+ int restore_position;
VERIFY_FD(fd, req);
+ zero_offset.QuadPart = 0;
+ restore_position = 0;
handle = uv__get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
@@ -627,6 +683,10 @@ void fs__write(uv_fs_t* req) {
if (offset != -1) {
memset(&overlapped, 0, sizeof overlapped);
overlapped_ptr = &overlapped;
+ if (SetFilePointerEx(handle, zero_offset, &original_position,
+ FILE_CURRENT)) {
+ restore_position = 1;
+ }
} else {
overlapped_ptr = NULL;
}
@@ -651,6 +711,9 @@ void fs__write(uv_fs_t* req) {
++index;
} while (result && index < req->fs.info.nbufs);
+ if (restore_position)
+ SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN);
+
if (result || bytes > 0) {
SET_REQ_RESULT(req, bytes);
} else {
@@ -1029,7 +1092,8 @@ cleanup:
}
-INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
+INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
+ int do_lstat) {
FILE_ALL_INFORMATION file_info;
FILE_FS_VOLUME_INFORMATION volume_info;
NTSTATUS nt_status;
@@ -1084,19 +1148,25 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
*/
statbuf->st_mode = 0;
- if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ /*
+ * On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism
+ * by which filesystem drivers can intercept and alter file system requests.
+ *
+ * The only reparse points we care about are symlinks and mount points, both
+ * of which are treated as POSIX symlinks. Further, we only care when
+ * invoked via lstat, which seeks information about the link instead of its
+ * target. Otherwise, reparse points must be treated as regular files.
+ */
+ if (do_lstat &&
+ (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
/*
- * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have
- * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets
- * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode
- * calculated below will indicate a normal directory or file, as if
- * FILE_ATTRIBUTE_REPARSE_POINT was not present.
+ * If reading the link fails, the reparse point is not a symlink and needs
+ * to be treated as a regular file. The higher level lstat function will
+ * detect this failure and retry without do_lstat if appropriate.
*/
- if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) {
- statbuf->st_mode |= S_IFLNK;
- } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) {
+ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
return -1;
- }
+ statbuf->st_mode |= S_IFLNK;
}
if (statbuf->st_mode == 0) {
@@ -1139,8 +1209,12 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
*
* Therefore we'll just report a sensible value that's quite commonly okay
* on modern hardware.
+ *
+ * 4096 is the minimum required to be compatible with newer Advanced Format
+ * drives (which have 4096 bytes per physical sector), and to be backwards
+ * compatible with older drives (which have 512 bytes per physical sector).
*/
- statbuf->st_blksize = 2048;
+ statbuf->st_blksize = 4096;
/* Todo: set st_flags to something meaningful. Also provide a wrapper for
* chattr(2).
@@ -1191,9 +1265,11 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
return;
}
- if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ if (fs__stat_handle(handle, &req->statbuf, do_lstat) != 0) {
DWORD error = GetLastError();
- if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) {
+ if (do_lstat &&
+ (error == ERROR_SYMLINK_NOT_SUPPORTED ||
+ error == ERROR_NOT_A_REPARSE_POINT)) {
/* We opened a reparse point but it was not a symlink. Try again. */
fs__stat_impl(req, 0);
@@ -1237,7 +1313,7 @@ static void fs__fstat(uv_fs_t* req) {
return;
}
- if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ if (fs__stat_handle(handle, &req->statbuf, 0) != 0) {
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
}
@@ -1309,6 +1385,22 @@ static void fs__ftruncate(uv_fs_t* req) {
}
+static void fs__copyfile(uv_fs_t* req) {
+ int flags;
+ int overwrite;
+
+ flags = req->fs.info.file_flags;
+ overwrite = flags & UV_FS_COPYFILE_EXCL;
+
+ if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ SET_REQ_RESULT(req, 0);
+}
+
+
static void fs__sendfile(uv_fs_t* req) {
int fd_in = req->file.fd, fd_out = req->fs.info.fd_out;
size_t length = req->fs.info.bufsml[0].len;
@@ -1675,25 +1767,46 @@ error:
static void fs__symlink(uv_fs_t* req) {
- WCHAR* pathw = req->file.pathw;
- WCHAR* new_pathw = req->fs.info.new_pathw;
- int flags = req->fs.info.file_flags;
- int result;
+ WCHAR* pathw;
+ WCHAR* new_pathw;
+ int flags;
+ int err;
+ pathw = req->file.pathw;
+ new_pathw = req->fs.info.new_pathw;
- if (flags & UV_FS_SYMLINK_JUNCTION) {
+ if (req->fs.info.file_flags & UV_FS_SYMLINK_JUNCTION) {
fs__create_junction(req, pathw, new_pathw);
- } else if (pCreateSymbolicLinkW) {
- result = pCreateSymbolicLinkW(new_pathw,
- pathw,
- flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
- if (result == -1) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- } else {
- SET_REQ_RESULT(req, result);
- }
- } else {
+ return;
+ }
+ if (!pCreateSymbolicLinkW) {
SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR)
+ flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag;
+ else
+ flags = uv__file_symlink_usermode_flag;
+
+ if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) {
+ SET_REQ_RESULT(req, 0);
+ return;
+ }
+
+ /* Something went wrong. We will test if it is because of user-mode
+ * symlinks.
+ */
+ err = GetLastError();
+ if (err == ERROR_INVALID_PARAMETER &&
+ flags & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) {
+ /* This system does not support user-mode symlinks. We will clear the
+ * unsupported flag and retry.
+ */
+ uv__file_symlink_usermode_flag = 0;
+ fs__symlink(req);
+ } else {
+ SET_REQ_WIN32_ERROR(req, err);
}
}
@@ -1831,6 +1944,7 @@ static void uv__fs_work(struct uv__work* w) {
XX(CLOSE, close)
XX(READ, read)
XX(WRITE, write)
+ XX(COPYFILE, copyfile)
XX(SENDFILE, sendfile)
XX(STAT, stat)
XX(LSTAT, lstat)
@@ -1877,6 +1991,9 @@ static void uv__fs_done(struct uv__work* w, int status) {
void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req == NULL)
+ return;
+
if (req->flags & UV_FS_CLEANEDUP)
return;
@@ -1907,8 +2024,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
int mode, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
-
+ INIT(UV_FS_OPEN);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
@@ -1916,28 +2032,14 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
req->fs.info.file_flags = flags;
req->fs.info.mode = mode;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__open(req);
- return req->result;
- }
+ POST;
}
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
+ INIT(UV_FS_CLOSE);
req->file.fd = fd;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__close(req);
- return req->result;
- }
+ POST;
}
@@ -1948,11 +2050,11 @@ int uv_fs_read(uv_loop_t* loop,
unsigned int nbufs,
int64_t offset,
uv_fs_cb cb) {
+ INIT(UV_FS_READ);
+
if (bufs == NULL || nbufs == 0)
return UV_EINVAL;
- uv_fs_req_init(loop, req, UV_FS_READ, cb);
-
req->file.fd = fd;
req->fs.info.nbufs = nbufs;
@@ -1966,14 +2068,7 @@ int uv_fs_read(uv_loop_t* loop,
memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
req->fs.info.offset = offset;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__read(req);
- return req->result;
- }
+ POST;
}
@@ -1984,11 +2079,11 @@ int uv_fs_write(uv_loop_t* loop,
unsigned int nbufs,
int64_t offset,
uv_fs_cb cb) {
+ INIT(UV_FS_WRITE);
+
if (bufs == NULL || nbufs == 0)
return UV_EINVAL;
- uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
-
req->file.fd = fd;
req->fs.info.nbufs = nbufs;
@@ -2002,14 +2097,7 @@ int uv_fs_write(uv_loop_t* loop,
memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
req->fs.info.offset = offset;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__write(req);
- return req->result;
- }
+ POST;
}
@@ -2017,20 +2105,13 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
-
+ INIT(UV_FS_UNLINK);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__unlink(req);
- return req->result;
- }
+ POST;
}
@@ -2038,22 +2119,14 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
-
+ INIT(UV_FS_MKDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.info.mode = mode;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__mkdir(req);
- return req->result;
- }
+ POST;
}
@@ -2061,39 +2134,25 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb);
-
+ INIT(UV_FS_MKDTEMP);
err = fs__capture_path(req, tpl, NULL, TRUE);
if (err)
return uv_translate_sys_error(err);
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__mkdtemp(req);
- return req->result;
- }
+ POST;
}
int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
-
+ INIT(UV_FS_RMDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__rmdir(req);
- return req->result;
- }
+ POST;
}
@@ -2101,22 +2160,14 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb);
-
+ INIT(UV_FS_SCANDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.info.file_flags = flags;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__scandir(req);
- return req->result;
- }
+ POST;
}
@@ -2124,20 +2175,13 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_LINK, cb);
-
+ INIT(UV_FS_LINK);
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__link(req);
- return req->result;
- }
+ POST;
}
@@ -2145,22 +2189,14 @@ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, int flags, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
-
+ INIT(UV_FS_SYMLINK);
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.info.file_flags = flags;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__symlink(req);
- return req->result;
- }
+ POST;
}
@@ -2168,20 +2204,13 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
-
+ INIT(UV_FS_READLINK);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__readlink(req);
- return req->result;
- }
+ POST;
}
@@ -2189,24 +2218,18 @@ int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb) {
int err;
- if (!req || !path) {
+ INIT(UV_FS_REALPATH);
+
+ if (!path) {
return UV_EINVAL;
}
- uv_fs_req_init(loop, req, UV_FS_REALPATH, cb);
-
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__realpath(req);
- return req->result;
- }
+ POST;
}
@@ -2214,88 +2237,53 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
uv_gid_t gid, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
-
+ INIT(UV_FS_CHOWN);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__chown(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
uv_gid_t gid, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb);
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fchown(req);
- return req->result;
- }
+ INIT(UV_FS_FCHOWN);
+ POST;
}
int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_STAT, cb);
-
+ INIT(UV_FS_STAT);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__stat(req);
- return req->result;
- }
+ POST;
}
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
-
+ INIT(UV_FS_LSTAT);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__lstat(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
+ INIT(UV_FS_FSTAT);
req->file.fd = fd;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fstat(req);
- return req->result;
- }
+ POST;
}
@@ -2303,85 +2291,70 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
-
+ INIT(UV_FS_RENAME);
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__rename(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
+ INIT(UV_FS_FSYNC);
req->file.fd = fd;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fsync(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
+ INIT(UV_FS_FDATASYNC);
req->file.fd = fd;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fdatasync(req);
- return req->result;
- }
+ POST;
}
int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
int64_t offset, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
-
+ INIT(UV_FS_FTRUNCATE);
req->file.fd = fd;
req->fs.info.offset = offset;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__ftruncate(req);
- return req->result;
- }
+ POST;
}
+int uv_fs_copyfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ INIT(UV_FS_COPYFILE);
+
+ if (flags & ~UV_FS_COPYFILE_EXCL)
+ return UV_EINVAL;
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+
+ if (err)
+ return uv_translate_sys_error(err);
+
+ req->fs.info.file_flags = flags;
+ POST;
+}
+
int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
-
+ INIT(UV_FS_SENDFILE);
req->file.fd = fd_in;
req->fs.info.fd_out = fd_out;
req->fs.info.offset = in_offset;
req->fs.info.bufsml[0].len = length;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__sendfile(req);
- return req->result;
- }
+ POST;
}
@@ -2392,21 +2365,13 @@ int uv_fs_access(uv_loop_t* loop,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_ACCESS, cb);
-
+ INIT(UV_FS_ACCESS);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err)
return uv_translate_sys_error(err);
req->fs.info.mode = flags;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- }
-
- fs__access(req);
- return req->result;
+ POST;
}
@@ -2414,39 +2379,23 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
-
+ INIT(UV_FS_CHMOD);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.info.mode = mode;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__chmod(req);
- return req->result;
- }
+ POST;
}
int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
-
+ INIT(UV_FS_FCHMOD);
req->file.fd = fd;
req->fs.info.mode = mode;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__fchmod(req);
- return req->result;
- }
+ POST;
}
@@ -2454,8 +2403,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
double mtime, uv_fs_cb cb) {
int err;
- uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
-
+ INIT(UV_FS_UTIME);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
@@ -2463,30 +2411,15 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
req->fs.time.atime = atime;
req->fs.time.mtime = mtime;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__utime(req);
- return req->result;
- }
+ POST;
}
int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
double mtime, uv_fs_cb cb) {
- uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
-
+ INIT(UV_FS_FUTIME);
req->file.fd = fd;
req->fs.time.atime = atime;
req->fs.time.mtime = mtime;
-
- if (cb) {
- QUEUE_FS_TP_JOB(loop, req);
- return 0;
- } else {
- fs__futime(req);
- return req->result;
- }
+ POST;
}
diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c
index baab838898..282d919cf7 100644
--- a/src/win/getaddrinfo.c
+++ b/src/win/getaddrinfo.c
@@ -28,6 +28,8 @@
/* EAI_* constants. */
#include <winsock2.h>
+/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
+#include <iphlpapi.h>
int uv__getaddrinfo_translate_error(int sys_err) {
switch (sys_err) {
@@ -73,6 +75,9 @@ int uv__getaddrinfo_translate_error(int sys_err) {
/* Do we need different versions of this for different architectures? */
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
+#ifndef NDIS_IF_MAX_STRING_SIZE
+#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
+#endif
static void uv__getaddrinfo_work(struct uv__work* w) {
uv_getaddrinfo_t* req;
@@ -380,3 +385,69 @@ error:
}
return uv_translate_sys_error(err);
}
+
+int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
+ NET_LUID luid;
+ wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
+ DWORD bufsize;
+ int r;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ r = ConvertInterfaceIndexToLuid(ifindex, &luid);
+
+ if (r != 0)
+ return uv_translate_sys_error(r);
+
+ r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
+
+ if (r != 0)
+ return uv_translate_sys_error(r);
+
+ /* Check how much space we need */
+ bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
+
+ if (bufsize == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (bufsize > *size) {
+ *size = bufsize;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ wname,
+ -1,
+ buffer,
+ *size,
+ NULL,
+ NULL);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ *size = bufsize - 1;
+ return 0;
+}
+
+int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
+ int r;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ r = snprintf(buffer, *size, "%d", ifindex);
+
+ if (r < 0)
+ return uv_translate_sys_error(r);
+
+ if (r >= (int) *size) {
+ *size = r + 1;
+ return UV_ENOBUFS;
+ }
+
+ *size = r;
+ return 0;
+}
diff --git a/src/win/handle.c b/src/win/handle.c
index 72b49d9790..39150702dd 100644
--- a/src/win/handle.c
+++ b/src/win/handle.c
@@ -152,3 +152,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
int uv_is_closing(const uv_handle_t* handle) {
return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
}
+
+
+uv_os_fd_t uv_get_osfhandle(int fd) {
+ return uv__get_osfhandle(fd);
+}
diff --git a/src/win/internal.h b/src/win/internal.h
index 444327d647..217fcdb5d7 100644
--- a/src/win/internal.h
+++ b/src/win/internal.h
@@ -326,7 +326,6 @@ 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);
-int uv_parent_pid(void);
int uv_current_pid(void);
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
int uv__getpwuid_r(uv_passwd_t* pwd);
diff --git a/src/win/pipe.c b/src/win/pipe.c
index edf3002121..1a7c4dc15e 100644
--- a/src/win/pipe.c
+++ b/src/win/pipe.c
@@ -31,6 +31,9 @@
#include "stream-inl.h"
#include "req-inl.h"
+#include <aclapi.h>
+#include <accctrl.h>
+
typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
struct uv__ipc_queue_item_s {
@@ -202,7 +205,7 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
uv_unique_pipe_name(ptr, name, nameSize);
pipeHandle = CreateNamedPipeA(name,
- access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
+ access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
NULL);
@@ -534,7 +537,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
*/
handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
- FILE_FLAG_FIRST_PIPE_INSTANCE,
+ FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
@@ -803,7 +806,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
req->pipeHandle = CreateNamedPipeW(handle->name,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
@@ -968,27 +971,31 @@ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
uv_mutex_unlock(m);
}
restart_readfile:
- result = ReadFile(handle->handle,
- &uv_zero_,
- 0,
- &bytes,
- NULL);
- if (!result) {
- err = GetLastError();
- if (err == ERROR_OPERATION_ABORTED &&
- handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
- if (handle->flags & UV_HANDLE_READING) {
- /* just a brief break to do something else */
- handle->pipe.conn.readfile_thread = NULL;
- /* resume after it is finished */
- uv_mutex_lock(m);
- handle->pipe.conn.readfile_thread = hThread;
- uv_mutex_unlock(m);
- goto restart_readfile;
- } else {
- result = 1; /* successfully stopped reading */
+ if (handle->flags & UV_HANDLE_READING) {
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ &bytes,
+ NULL);
+ if (!result) {
+ err = GetLastError();
+ if (err == ERROR_OPERATION_ABORTED &&
+ handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ if (handle->flags & UV_HANDLE_READING) {
+ /* just a brief break to do something else */
+ handle->pipe.conn.readfile_thread = NULL;
+ /* resume after it is finished */
+ uv_mutex_lock(m);
+ handle->pipe.conn.readfile_thread = hThread;
+ uv_mutex_unlock(m);
+ goto restart_readfile;
+ } else {
+ result = 1; /* successfully stopped reading */
+ }
}
}
+ } else {
+ result = 1; /* successfully aborted read before it even started */
}
if (hThread) {
assert(hThread == handle->pipe.conn.readfile_thread);
@@ -1515,7 +1522,10 @@ static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
int error, uv_buf_t buf) {
- if (error == ERROR_BROKEN_PIPE) {
+ if (error == ERROR_OPERATION_ABORTED) {
+ /* do nothing (equivalent to EINTR) */
+ }
+ else if (error == ERROR_BROKEN_PIPE) {
uv_pipe_read_eof(loop, handle, buf);
} else {
uv_pipe_read_error(loop, handle, error, buf);
@@ -1906,6 +1916,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
if (os_handle == INVALID_HANDLE_VALUE)
return UV_EBADF;
+ uv__once_init();
/* In order to avoid closing a stdio file descriptor 0-2, duplicate the
* underlying OS handle and forget about the original fd.
* We could also opt to use the original OS handle and just never close it,
@@ -1961,7 +1972,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_pid = uv_parent_pid();
+ pipe->pipe.conn.ipc_pid = uv_os_getppid();
assert(pipe->pipe.conn.ipc_pid != -1);
}
return 0;
@@ -1979,6 +1990,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
unsigned int name_len;
int err;
+ uv__once_init();
name_info = NULL;
if (handle->handle == INVALID_HANDLE_VALUE) {
@@ -2123,3 +2135,80 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
else
return UV_TCP;
}
+
+int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
+ SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY;
+ PACL old_dacl, new_dacl;
+ PSECURITY_DESCRIPTOR sd;
+ EXPLICIT_ACCESS ea;
+ PSID everyone;
+ int error;
+
+ if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ if (mode != UV_READABLE &&
+ mode != UV_WRITABLE &&
+ mode != (UV_WRITABLE | UV_READABLE))
+ return UV_EINVAL;
+
+ if (!AllocateAndInitializeSid(&sid_world,
+ 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &everyone)) {
+ error = GetLastError();
+ goto done;
+ }
+
+ if (GetSecurityInfo(handle->handle,
+ SE_KERNEL_OBJECT,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ &old_dacl,
+ NULL,
+ &sd)) {
+ error = GetLastError();
+ goto clean_sid;
+ }
+
+ memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
+ if (mode & UV_READABLE)
+ ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
+ if (mode & UV_WRITABLE)
+ ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+ ea.grfAccessPermissions |= SYNCHRONIZE;
+ ea.grfAccessMode = SET_ACCESS;
+ ea.grfInheritance = NO_INHERITANCE;
+ ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+ ea.Trustee.ptstrName = (LPTSTR)everyone;
+
+ if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) {
+ error = GetLastError();
+ goto clean_sd;
+ }
+
+ if (SetSecurityInfo(handle->handle,
+ SE_KERNEL_OBJECT,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ new_dacl,
+ NULL)) {
+ error = GetLastError();
+ goto clean_dacl;
+ }
+
+ error = 0;
+
+clean_dacl:
+ LocalFree((HLOCAL) new_dacl);
+clean_sd:
+ LocalFree((HLOCAL) sd);
+clean_sid:
+ FreeSid(everyone);
+done:
+ return uv_translate_sys_error(error);
+}
diff --git a/src/win/process.c b/src/win/process.c
index d141601607..cc06d9e22a 100644
--- a/src/win/process.c
+++ b/src/win/process.c
@@ -405,8 +405,15 @@ static WCHAR* search_path(const WCHAR *file,
/* Next slice starts just after where the previous one ended */
dir_start = dir_end;
+ /* If path is quoted, find quote end */
+ if (*dir_start == L'"' || *dir_start == L'\'') {
+ dir_end = wcschr(dir_start + 1, *dir_start);
+ if (dir_end == NULL) {
+ dir_end = wcschr(dir_start, L'\0');
+ }
+ }
/* Slice until the next ; or \0 is found */
- dir_end = wcschr(dir_start, L';');
+ dir_end = wcschr(dir_end, L';');
if (dir_end == NULL) {
dir_end = wcschr(dir_start, L'\0');
}
@@ -1051,15 +1058,18 @@ int uv_spawn(uv_loop_t* loop,
startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
+ process_flags = CREATE_UNICODE_ENVIRONMENT;
+
if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
/* Use SW_HIDE to avoid any potential process window. */
startup.wShowWindow = SW_HIDE;
+
+ /* Hide console windows. */
+ process_flags |= CREATE_NO_WINDOW;
} else {
startup.wShowWindow = SW_SHOWDEFAULT;
}
- process_flags = CREATE_UNICODE_ENVIRONMENT;
-
if (options->flags & UV_PROCESS_DETACHED) {
/* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
* means that libuv might not let you create a fully daemonized process
@@ -1163,6 +1173,10 @@ int uv_spawn(uv_loop_t* loop,
static int uv__kill(HANDLE process_handle, int signum) {
+ if (signum < 0 || signum >= NSIG) {
+ return UV_EINVAL;
+ }
+
switch (signum) {
case SIGTERM:
case SIGKILL:
@@ -1227,8 +1241,15 @@ int uv_process_kill(uv_process_t* process, int signum) {
int uv_kill(int pid, int signum) {
int err;
- HANDLE process_handle = OpenProcess(PROCESS_TERMINATE |
- PROCESS_QUERY_INFORMATION, FALSE, pid);
+ HANDLE process_handle;
+
+ if (pid == 0) {
+ process_handle = GetCurrentProcess();
+ } else {
+ process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
+ FALSE,
+ pid);
+ }
if (process_handle == NULL) {
err = GetLastError();
diff --git a/src/win/signal.c b/src/win/signal.c
index 7b42dd9928..a174da1f76 100644
--- a/src/win/signal.c
+++ b/src/win/signal.c
@@ -64,7 +64,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
}
-RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
+RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare)
/*
diff --git a/src/win/stream-inl.h b/src/win/stream-inl.h
index bf12148afe..dba0374704 100644
--- a/src/win/stream-inl.h
+++ b/src/win/stream-inl.h
@@ -36,6 +36,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop,
uv__handle_init(loop, (uv_handle_t*) handle, type);
handle->write_queue_size = 0;
handle->activecnt = 0;
+ handle->stream.conn.shutdown_req = NULL;
}
@@ -47,8 +48,6 @@ INLINE static void uv_connection_init(uv_stream_t* handle) {
handle->read_req.event_handle = NULL;
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
handle->read_req.data = handle;
-
- handle->stream.conn.shutdown_req = NULL;
}
diff --git a/src/win/tcp.c b/src/win/tcp.c
index 972539f4df..fd6efbaf89 100644
--- a/src/win/tcp.c
+++ b/src/win/tcp.c
@@ -747,10 +747,15 @@ static int uv_tcp_try_connect(uv_connect_t* req,
uv_connect_cb cb) {
uv_loop_t* loop = handle->loop;
const struct sockaddr* bind_addr;
+ struct sockaddr_storage converted;
BOOL success;
DWORD bytes;
int err;
+ err = uv__convert_to_localhost_if_unspecified(addr, &converted);
+ if (err)
+ return err;
+
if (handle->delayed_error) {
return handle->delayed_error;
}
@@ -782,12 +787,12 @@ static int uv_tcp_try_connect(uv_connect_t* req,
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
success = handle->tcp.conn.func_connectex(handle->socket,
- addr,
- addrlen,
- NULL,
- 0,
- &bytes,
- &req->u.io.overlapped);
+ (const struct sockaddr*) &converted,
+ addrlen,
+ NULL,
+ 0,
+ &bytes,
+ &req->u.io.overlapped);
if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
/* Process the req without IOCP. */
@@ -1446,6 +1451,8 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
WSAPROTOCOL_INFOW protocol_info;
int opt_len;
int err;
+ struct sockaddr_storage saddr;
+ int saddr_len;
/* Detect the address family of the socket. */
opt_len = (int) sizeof protocol_info;
@@ -1466,6 +1473,19 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
return uv_translate_sys_error(err);
}
+ /* Support already active socket. */
+ saddr_len = sizeof(saddr);
+ if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) {
+ /* Socket is already bound. */
+ handle->flags |= UV_HANDLE_BOUND;
+ saddr_len = sizeof(saddr);
+ if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) {
+ /* Socket is already connected. */
+ uv_connection_init((uv_stream_t*) handle);
+ handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+ }
+
return 0;
}
diff --git a/src/win/thread.c b/src/win/thread.c
index 91684e9387..9eaad77cd0 100644
--- a/src/win/thread.c
+++ b/src/win/thread.c
@@ -182,6 +182,7 @@ int uv_thread_join(uv_thread_t *tid) {
else {
CloseHandle(*tid);
*tid = 0;
+ MemoryBarrier(); /* For feature parity with pthread_join(). */
return 0;
}
}
@@ -198,6 +199,11 @@ int uv_mutex_init(uv_mutex_t* mutex) {
}
+int uv_mutex_init_recursive(uv_mutex_t* mutex) {
+ return uv_mutex_init(mutex);
+}
+
+
void uv_mutex_destroy(uv_mutex_t* mutex) {
DeleteCriticalSection(mutex);
}
diff --git a/src/win/timer.c b/src/win/timer.c
index 27ca7716af..7e006fedfa 100644
--- a/src/win/timer.c
+++ b/src/win/timer.c
@@ -56,7 +56,7 @@ static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
}
-RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
+RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare)
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
diff --git a/src/win/tty.c b/src/win/tty.c
index a6f583956f..05a11e8830 100644
--- a/src/win/tty.c
+++ b/src/win/tty.c
@@ -112,14 +112,30 @@ static int uv_tty_virtual_offset = -1;
static int uv_tty_virtual_height = -1;
static int uv_tty_virtual_width = -1;
+/* The console window size
+ * We keep this separate from uv_tty_virtual_*. We use those values to only
+ * handle signalling SIGWINCH
+ */
+
+static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
+static int uv__tty_console_height = -1;
+static int uv__tty_console_width = -1;
+
+static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
+static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
+ DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild,
+ DWORD dwEventThread,
+ DWORD dwmsEventTime);
+
/* We use a semaphore rather than a mutex or critical section because in some
cases (uv__cancel_read_console) we need take the lock in the main thread and
release it in another thread. Using a semaphore ensures that in such
scenario the main thread will still block when trying to acquire the lock. */
static uv_sem_t uv_tty_output_lock;
-static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
-
static WORD uv_tty_default_text_attributes =
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
@@ -141,6 +157,18 @@ static void uv__determine_vterm_state(HANDLE handle);
void uv_console_init(void) {
if (uv_sem_init(&uv_tty_output_lock, 1))
abort();
+ uv__tty_console_handle = CreateFileW(L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ 0,
+ OPEN_EXISTING,
+ 0,
+ 0);
+ if (uv__tty_console_handle != NULL) {
+ QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
+ NULL,
+ WT_EXECUTELONGFUNCTION);
+ }
}
@@ -148,6 +176,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
HANDLE handle;
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
+ uv__once_init();
handle = (HANDLE) uv__get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE)
return UV_EBADF;
@@ -183,11 +212,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
if (uv__vterm_state == UV_UNCHECKED)
uv__determine_vterm_state(handle);
- /* Store the global tty output handle. This handle is used by TTY read */
- /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */
- /* is received. */
- uv_tty_output_handle = handle;
-
/* Remember the original console text attributes. */
uv_tty_capture_initial_style(&screen_buffer_info);
@@ -704,25 +728,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
}
records_left--;
- /* If the window was resized, recompute the virtual window size. This */
- /* will trigger a SIGWINCH signal if the window size changed in an */
- /* way that matters to libuv. */
- if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
- CONSOLE_SCREEN_BUFFER_INFO info;
-
- uv_sem_wait(&uv_tty_output_lock);
-
- if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
- GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
- uv_tty_update_virtual_window(&info);
- }
-
- uv_sem_post(&uv_tty_output_lock);
-
- continue;
- }
-
- /* Ignore other events that are not key or resize events. */
+ /* Ignore other events that are not key events. */
if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
continue;
}
@@ -1102,9 +1108,6 @@ static int uv__cancel_read_console(uv_tty_t* handle) {
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
- int old_virtual_width = uv_tty_virtual_width;
- int old_virtual_height = uv_tty_virtual_height;
-
uv_tty_virtual_width = info->dwSize.X;
uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
@@ -1124,14 +1127,6 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
if (uv_tty_virtual_offset < 0) {
uv_tty_virtual_offset = 0;
}
-
- /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */
- /* if this was the first time the virtual window size was computed. */
- if (old_virtual_width != -1 && old_virtual_height != -1 &&
- (uv_tty_virtual_width != old_virtual_width ||
- uv_tty_virtual_height != old_virtual_height)) {
- uv__signal_dispatch(SIGWINCH);
- }
}
@@ -2279,3 +2274,55 @@ static void uv__determine_vterm_state(HANDLE handle) {
uv__vterm_state = UV_SUPPORTED;
}
+
+static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
+ CONSOLE_SCREEN_BUFFER_INFO sb_info;
+ MSG msg;
+
+ if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
+ return 0;
+
+ uv__tty_console_width = sb_info.dwSize.X;
+ uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
+
+ if (pSetWinEventHook == NULL)
+ return 0;
+
+ if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
+ EVENT_CONSOLE_LAYOUT,
+ NULL,
+ uv__tty_console_resize_event,
+ 0,
+ 0,
+ WINEVENT_OUTOFCONTEXT))
+ return 0;
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ return 0;
+}
+
+static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
+ DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild,
+ DWORD dwEventThread,
+ DWORD dwmsEventTime) {
+ CONSOLE_SCREEN_BUFFER_INFO sb_info;
+ int width, height;
+
+ if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
+ return;
+
+ width = sb_info.dwSize.X;
+ height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
+
+ if (width != uv__tty_console_width || height != uv__tty_console_height) {
+ uv__tty_console_width = width;
+ uv__tty_console_height = height;
+ uv__signal_dispatch(SIGWINCH);
+ }
+}
diff --git a/src/win/udp.c b/src/win/udp.c
index 2fd15cfa9a..cd1d0e07b2 100644
--- a/src/win/udp.c
+++ b/src/win/udp.c
@@ -897,13 +897,12 @@ int uv__udp_send(uv_udp_send_t* req,
int err;
if (!(handle->flags & UV_HANDLE_BOUND)) {
- if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_))
bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
- } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ else if (addrlen == sizeof(uv_addr_ip6_any_))
bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
- } else {
- abort();
- }
+ else
+ return UV_EINVAL;
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
if (err)
return uv_translate_sys_error(err);
@@ -922,5 +921,45 @@ int uv__udp_try_send(uv_udp_t* handle,
unsigned int nbufs,
const struct sockaddr* addr,
unsigned int addrlen) {
- return UV_ENOSYS;
+ DWORD bytes;
+ const struct sockaddr* bind_addr;
+ struct sockaddr_storage converted;
+ int err;
+
+ assert(nbufs > 0);
+
+ err = uv__convert_to_localhost_if_unspecified(addr, &converted);
+ if (err)
+ return err;
+
+ /* Already sending a message.*/
+ if (handle->send_queue_count != 0)
+ return UV_EAGAIN;
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_))
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ else if (addrlen == sizeof(uv_addr_ip6_any_))
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ else
+ return UV_EINVAL;
+ err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return uv_translate_sys_error(err);
+ }
+
+ err = WSASendTo(handle->socket,
+ (WSABUF*)bufs,
+ nbufs,
+ &bytes,
+ 0,
+ (const struct sockaddr*) &converted,
+ addrlen,
+ NULL,
+ NULL);
+
+ if (err)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ return bytes;
}
diff --git a/src/win/util.c b/src/win/util.c
index d2e7f772ce..3100bc23ad 100644
--- a/src/win/util.c
+++ b/src/win/util.c
@@ -331,7 +331,12 @@ uint64_t uv_get_total_memory(void) {
}
-int uv_parent_pid(void) {
+uv_pid_t uv_os_getpid(void) {
+ return GetCurrentProcessId();
+}
+
+
+uv_pid_t uv_os_getppid(void) {
int parent_pid = -1;
HANDLE handle;
PROCESSENTRY32 pe;
@@ -1388,7 +1393,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
return uv_translate_sys_error(GetLastError());
- bufsize = sizeof(path);
+ bufsize = ARRAY_SIZE(path);
if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
r = GetLastError();
CloseHandle(token);
@@ -1403,7 +1408,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
CloseHandle(token);
/* Get the username using GetUserNameW() */
- bufsize = sizeof(username);
+ bufsize = ARRAY_SIZE(username);
if (!GetUserNameW(username, &bufsize)) {
r = GetLastError();
diff --git a/src/win/winapi.c b/src/win/winapi.c
index aa5d719fbe..4ccdf0a5f9 100644
--- a/src/win/winapi.c
+++ b/src/win/winapi.c
@@ -52,11 +52,15 @@ sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
/* Powrprof.dll function pointer */
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
+/* User32.dll function pointer */
+sSetWinEventHook pSetWinEventHook;
+
void uv_winapi_init(void) {
HMODULE ntdll_module;
HMODULE kernel32_module;
HMODULE powrprof_module;
+ HMODULE user32_module;
ntdll_module = GetModuleHandleA("ntdll.dll");
if (ntdll_module == NULL) {
@@ -156,4 +160,10 @@ void uv_winapi_init(void) {
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
}
+ user32_module = LoadLibraryA("user32.dll");
+ if (user32_module != NULL) {
+ pSetWinEventHook = (sSetWinEventHook)
+ GetProcAddress(user32_module, "SetWinEventHook");
+ }
+
}
diff --git a/src/win/winapi.h b/src/win/winapi.h
index 9401676fbd..cc54b79b08 100644
--- a/src/win/winapi.h
+++ b/src/win/winapi.h
@@ -4104,6 +4104,10 @@
# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
#endif
+#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x00000002
+#endif
+
/* from winternl.h */
typedef struct _UNICODE_STRING {
USHORT Length;
@@ -4721,6 +4725,25 @@ typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
HANDLE Recipient,
_PHPOWERNOTIFY RegistrationHandle);
+/* from Winuser.h */
+typedef VOID (CALLBACK* WINEVENTPROC)
+ (HWINEVENTHOOK hWinEventHook,
+ DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild,
+ DWORD idEventThread,
+ DWORD dwmsEventTime);
+
+typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
+ (UINT eventMin,
+ UINT eventMax,
+ HMODULE hmodWinEventProc,
+ WINEVENTPROC lpfnWinEventProc,
+ DWORD idProcess,
+ DWORD idThread,
+ UINT dwflags);
+
/* Ntdll function pointers */
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
@@ -4749,4 +4772,7 @@ extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
/* Powrprof.dll function pointer */
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
+/* User32.dll function pointer */
+extern sSetWinEventHook pSetWinEventHook;
+
#endif /* UV_WIN_WINAPI_H_ */
diff --git a/src/win/winsock.c b/src/win/winsock.c
index e86d76b131..7cfa90f8af 100644
--- a/src/win/winsock.c
+++ b/src/win/winsock.c
@@ -559,3 +559,31 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
return SOCKET_ERROR;
}
}
+
+int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
+ struct sockaddr_storage* storage) {
+ struct sockaddr_in* dest4;
+ struct sockaddr_in6* dest6;
+
+ if (addr == NULL)
+ return UV_EINVAL;
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ dest4 = (struct sockaddr_in*) storage;
+ memcpy(dest4, addr, sizeof(*dest4));
+ if (dest4->sin_addr.s_addr == 0)
+ dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ return 0;
+ case AF_INET6:
+ dest6 = (struct sockaddr_in6*) storage;
+ memcpy(dest6, addr, sizeof(*dest6));
+ if (memcmp(&dest6->sin6_addr,
+ &uv_addr_ip6_any_.sin6_addr,
+ sizeof(uv_addr_ip6_any_.sin6_addr)) == 0)
+ dest6->sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
+ return 0;
+ default:
+ return UV_EINVAL;
+ }
+}
diff --git a/src/win/winsock.h b/src/win/winsock.h
index 7c007ab493..7ecb755bfb 100644
--- a/src/win/winsock.h
+++ b/src/win/winsock.h
@@ -187,4 +187,7 @@ typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
#endif
+int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
+ struct sockaddr_storage* storage);
+
#endif /* UV_WIN_WINSOCK_H_ */