CPPFLAGS += -D_LARGEFILE_SOURCE
CPPFLAGS += -D_FILE_OFFSET_BITS=64
+OBJS += src/unix/async.o
+OBJS += src/unix/cares.o
+OBJS += src/unix/check.o
OBJS += src/unix/core.o
OBJS += src/unix/dl.o
-OBJS += src/unix/fs.o
-OBJS += src/unix/cares.o
-OBJS += src/unix/udp.o
OBJS += src/unix/error.o
-OBJS += src/unix/thread.o
+OBJS += src/unix/fs.o
+OBJS += src/unix/idle.o
+OBJS += src/unix/loop.o
+OBJS += src/unix/pipe.o
+OBJS += src/unix/prepare.o
OBJS += src/unix/process.o
+OBJS += src/unix/stream.o
OBJS += src/unix/tcp.o
-OBJS += src/unix/pipe.o
+OBJS += src/unix/thread.o
+OBJS += src/unix/timer.o
OBJS += src/unix/tty.o
-OBJS += src/unix/stream.o
+OBJS += src/unix/udp.o
ifeq (SunOS,$(uname_S))
EV_CONFIG=config_sunos.h
ifeq (Darwin,$(uname_S))
EV_CONFIG=config_darwin.h
EIO_CONFIG=config_darwin.h
-CPPFLAGS += -Isrc/ares/config_darwin
+CPPFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 -Isrc/ares/config_darwin
LINKFLAGS+=-framework CoreServices
OBJS += src/unix/darwin.o
OBJS += src/unix/kqueue.o
CSTDFLAG += -D_GNU_SOURCE
CPPFLAGS += -Isrc/ares/config_linux
LINKFLAGS+=-ldl -lrt
-OBJS += src/unix/linux/core.o src/unix/linux/inotify.o
+OBJS += src/unix/linux/core.o src/unix/linux/inotify.o src/unix/linux/syscalls.o
endif
ifeq (FreeBSD,$(uname_S))
EV_CONFIG=config_openbsd.h
EIO_CONFIG=config_openbsd.h
CPPFLAGS += -Isrc/ares/config_openbsd
-LINKFLAGS+=
+LINKFLAGS+=-lkvm
OBJS += src/unix/openbsd.o
OBJS += src/unix/kqueue.o
endif
uv_root = os.path.normpath(script_dir)
sys.path.insert(0, os.path.join(uv_root, 'build', 'gyp', 'pylib'))
-import gyp
+try:
+ import gyp
+except ImportError:
+ print('You need to install gyp in build/gyp first. See the README.')
+ sys.exit(42)
# Directory within which we want all generated files (including Makefiles)
# to be written.
#ifndef UV_TREE_H_
#define UV_TREE_H_
-#if __GNUC__
-# define __unused __attribute__((unused))
-#else
-# define __unused
+#ifndef UV__UNUSED
+# if __GNUC__
+# define UV__UNUSED __attribute__((unused))
+# else
+# define UV__UNUSED
+# endif
#endif
/*
#define RB_PROTOTYPE(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
- RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
#define RB_GENERATE(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp,)
#define RB_GENERATE_STATIC(name, type, field, cmp) \
- RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
+ RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
attr void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
+#include <pwd.h>
#include <termios.h>
#include <pthread.h>
typedef pthread_mutex_t uv_mutex_t;
typedef pthread_rwlock_t uv_rwlock_t;
+/* Platform-specific definitions for uv_spawn support. */
+typedef gid_t uv_gid_t;
+typedef uid_t uv_uid_t;
+
/* Platform-specific definitions for uv_dlopen support. */
typedef void* uv_lib_t;
#define UV_DYNAMIC /* empty */
+#define UV_HANDLE_TYPE_PRIVATE /* empty */
+#define UV_REQ_TYPE_PRIVATE /* empty */
+
#if __linux__
# define UV_LOOP_PRIVATE_PLATFORM_FIELDS \
/* RB_HEAD(uv__inotify_watchers, uv_fs_event_s) */ \
* sure that we're always calling ares_process. See the warning above the \
* definition of ares_timeout(). \
*/ \
- ev_timer timer; \
+ uv_timer_t timer; \
/* Poll result queue */ \
eio_channel uv_eio_channel; \
struct ev_loop* ev; \
uv_async_t uv_eio_want_poll_notifier; \
uv_async_t uv_eio_done_poll_notifier; \
uv_idle_t uv_eio_poller; \
+ uv_handle_t* endgame_handles; \
UV_LOOP_PRIVATE_PLATFORM_FIELDS
#define UV_REQ_BUFSML_SIZE (4)
#define UV_HANDLE_PRIVATE_FIELDS \
int fd; \
int flags; \
- ev_idle next_watcher;
+ uv_handle_t* endgame_next; /* that's what uv-win calls it */ \
#define UV_STREAM_PRIVATE_FIELDS \
ev_timer timer_watcher; \
uv_timer_cb timer_cb;
-#define UV_ARES_TASK_PRIVATE_FIELDS \
- int sock; \
- ev_io read_watcher; \
- ev_io write_watcher;
-
#define UV_GETADDRINFO_PRIVATE_FIELDS \
uv_getaddrinfo_cb cb; \
struct addrinfo* hints; \
LPDWORD bytes,
LPDWORD flags,
LPWSAOVERLAPPED overlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE
- completion_routine);
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
typedef int (WSAAPI* LPFN_WSARECVFROM)
(SOCKET socket,
HANDLE padding;
} uv_once_t;
+/* Platform-specific definitions for uv_spawn support. */
+typedef unsigned char uv_uid_t;
+typedef unsigned char uv_gid_t;
+
/* Platform-specific definitions for uv_dlopen support. */
typedef HMODULE uv_lib_t;
#define UV_DYNAMIC FAR WINAPI
/* Counter to keep track of active udp streams */ \
unsigned int active_udp_streams;
+#define UV_HANDLE_TYPE_PRIVATE \
+ UV_ARES_EVENT,
+
#define UV_REQ_TYPE_PRIVATE \
/* TODO: remove the req suffix */ \
+ UV_ACCEPT, \
UV_ARES_EVENT_REQ, \
UV_ARES_CLEANUP_REQ, \
+ UV_FS_EVENT_REQ, \
UV_GETADDRINFO_REQ, \
UV_PROCESS_EXIT, \
UV_PROCESS_CLOSE, \
+ UV_READ, \
UV_UDP_RECV, \
- UV_FS_EVENT_REQ
+ UV_WAKEUP,
#define UV_REQ_PRIVATE_FIELDS \
union { \
uv_handle_t* endgame_next; \
unsigned int flags;
-#define UV_ARES_TASK_PRIVATE_FIELDS \
- struct uv_req_s ares_req; \
- SOCKET sock; \
- HANDLE h_wait; \
- WSAEVENT h_event; \
- HANDLE h_close_event;
-
#define UV_GETADDRINFO_PRIVATE_FIELDS \
struct uv_req_s getadddrinfo_req; \
uv_getaddrinfo_cb getaddrinfo_cb; \
HANDLE close_handle;
#define UV_FS_PRIVATE_FIELDS \
- wchar_t* pathw; \
int flags; \
DWORD sys_errno_; \
- struct _stati64 stat; \
- void* arg0; \
+ union { \
+ wchar_t* pathw; \
+ int file; \
+ }; \
union { \
struct { \
- void* arg1; \
- void* arg2; \
- void* arg3; \
+ int mode; \
+ wchar_t* new_pathw; \
+ int file_flags; \
+ int file_out; \
+ void* buf; \
+ size_t length; \
+ int64_t offset; \
}; \
+ struct _stati64 stat; \
struct { \
- ssize_t arg4; \
- ssize_t arg5; \
+ double atime; \
+ double mtime; \
}; \
};
#include "ares.h"
-#ifndef _SSIZE_T_
-typedef intptr_t ssize_t;
+#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
+ typedef intptr_t ssize_t;
+# define _SSIZE_T_
+# define _SSIZE_T_DEFINED
#endif
#if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__)
XX( 51, ELOOP, "too many symbolic links encountered") \
XX( 52, EXDEV, "cross-device link not permitted") \
XX( 53, ENOTEMPTY, "directory not empty") \
- XX( 54, ENOSPC, "no space left on device")
+ XX( 54, ENOSPC, "no space left on device") \
+ XX( 55, EIO, "i/o error") \
+ XX( 56, EROFS, "read-only file system" )
#define UV_ERRNO_GEN(val, name, s) UV_##name = val,
} uv_err_code;
#undef UV_ERRNO_GEN
+#define UV_HANDLE_TYPE_MAP(XX) \
+ XX(ARES_TASK, ares_task) \
+ XX(ASYNC, async) \
+ XX(CHECK, check) \
+ XX(FS_EVENT, fs_event) \
+ XX(IDLE, idle) \
+ XX(NAMED_PIPE, pipe) \
+ XX(PREPARE, prepare) \
+ XX(PROCESS, process) \
+ XX(TCP, tcp) \
+ XX(TIMER, timer) \
+ XX(TTY, tty) \
+ XX(UDP, udp) \
+
+#define UV_REQ_TYPE_MAP(XX) \
+ XX(CONNECT, connect) \
+ XX(WRITE, write) \
+ XX(SHUTDOWN, shutdown) \
+ XX(UDP_SEND, udp_send) \
+ XX(FS, fs) \
+ XX(WORK, work) \
+ XX(GETADDRINFO, getaddrinfo) \
+
typedef enum {
UV_UNKNOWN_HANDLE = 0,
- UV_TCP,
- UV_UDP,
- UV_NAMED_PIPE,
- UV_TTY,
+#define XX(uc, lc) UV_##uc,
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
UV_FILE,
- UV_TIMER,
- UV_PREPARE,
- UV_CHECK,
- UV_IDLE,
- UV_ASYNC,
- UV_ARES_TASK,
- UV_ARES_EVENT,
- UV_PROCESS,
- UV_FS_EVENT
+ UV_HANDLE_TYPE_PRIVATE
+ UV_HANDLE_TYPE_MAX
} uv_handle_type;
typedef enum {
UV_UNKNOWN_REQ = 0,
- UV_CONNECT,
- UV_ACCEPT,
- UV_READ,
- UV_WRITE,
- UV_SHUTDOWN,
- UV_WAKEUP,
- UV_UDP_SEND,
- UV_FS,
- UV_WORK,
- UV_GETADDRINFO,
+#define XX(uc, lc) UV_##uc,
+ UV_REQ_TYPE_MAP(XX)
+#undef XX
UV_REQ_TYPE_PRIVATE
+ UV_REQ_TYPE_MAX
} uv_req_type;
};
/*
+ * Returns size of various handle types, useful for FFI
+ * bindings to allocate correct memory without copying struct
+ * definitions
+ */
+UV_EXTERN size_t uv_handle_size(uv_handle_type type);
+
+/*
+ * Returns size of request types, useful for dynamic lookup with FFI
+ */
+UV_EXTERN size_t uv_req_size(uv_req_type type);
+
+/*
* Returns 1 if the prepare/check/idle/timer handle has been started, 0
* otherwise. For other handle types this always returns 1.
*/
-UV_EXTERN int uv_is_active(uv_handle_t* handle);
+UV_EXTERN int uv_is_active(const uv_handle_t* handle);
/*
* Request handle to be closed. close_cb will be called asynchronously after
/*
* Used to determine whether a stream is readable or writable.
*/
-UV_EXTERN int uv_is_readable(uv_stream_t* handle);
-UV_EXTERN int uv_is_writable(uv_stream_t* handle);
+UV_EXTERN int uv_is_readable(const uv_stream_t* handle);
+UV_EXTERN int uv_is_writable(const uv_stream_t* handle);
+
+
+/*
+ * Used to determine whether a stream is closing or closed.
+ *
+ * N.B. is only valid between the initialization of the handle
+ * and the arrival of the close callback, and cannot be used
+ * to validate the handle.
+ */
+UV_EXTERN int uv_is_closing(const uv_handle_t* handle);
/*
struct uv_getaddrinfo_s {
UV_REQ_FIELDS
/* read-only */
- uv_loop_t* loop; \
+ uv_loop_t* loop;
UV_GETADDRINFO_PRIVATE_FIELDS
};
* in. Stands for current working directory.
*/
char* cwd;
-
/*
- * TODO describe how this works.
+ * Various flags that control how uv_spawn() behaves. See the definition of
+ * `enum uv_process_flags` below.
*/
- int windows_verbatim_arguments;
-
+ unsigned int flags;
+ /*
+ * Libuv can change the child process' user/group id. This happens only when
+ * the appropriate bits are set in the flags fields. This is not supported on
+ * windows; uv_spawn() will fail and set the error to UV_ENOTSUP.
+ */
+ uv_uid_t uid;
+ uv_gid_t gid;
/*
* The user should supply pointers to initialized uv_pipe_t structs for
* stdio. This is used to to send or receive input from the subprocess.
} uv_process_options_t;
/*
+ * These are the flags that can be used for the uv_process_options.flags field.
+ */
+enum uv_process_flags {
+ /*
+ * Set the child process' user id. The user id is supplied in the `uid` field
+ * of the options struct. This does not work on windows; setting this flag
+ * will cause uv_spawn() to fail.
+ */
+ UV_PROCESS_SETUID = (1 << 0),
+ /*
+ * Set the child process' group id. The user id is supplied in the `gid`
+ * field of the options struct. This does not work on windows; setting this
+ * flag will cause uv_spawn() to fail.
+ */
+ UV_PROCESS_SETGID = (1 << 1),
+ /*
+ * Do not wrap any arguments in quotes, or perform any other escaping, when
+ * converting the argument list into a command line string. This option is
+ * only meaningful on Windows systems. On unix it is silently ignored.
+ */
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2)
+};
+
+/*
* uv_process_t is a subclass of uv_handle_t
*/
struct uv_process_s {
UV_EXTERN int uv_spawn(uv_loop_t*, uv_process_t*,
uv_process_options_t options);
+
/*
* Kills the process with the specified signal. The user must still
* call uv_close on the process.
int flags, int mode, uv_fs_cb cb);
UV_EXTERN int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file,
- void* buf, size_t length, off_t offset, uv_fs_cb cb);
+ void* buf, size_t length, int64_t offset, uv_fs_cb cb);
UV_EXTERN int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb);
UV_EXTERN int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file,
- void* buf, size_t length, off_t offset, uv_fs_cb cb);
+ void* buf, size_t length, int64_t offset, uv_fs_cb cb);
UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path,
int mode, uv_fs_cb cb);
uv_fs_cb cb);
UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file,
- off_t offset, uv_fs_cb cb);
+ int64_t offset, uv_fs_cb cb);
UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd,
- uv_file in_fd, off_t in_offset, size_t length, uv_fs_cb cb);
+ uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb);
UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path,
int mode, uv_fs_cb cb);
/* Don't export the private CPP symbols. */
+#undef UV_HANDLE_TYPE_PRIVATE
#undef UV_REQ_TYPE_PRIVATE
#undef UV_REQ_PRIVATE_FIELDS
#undef UV_STREAM_PRIVATE_FIELDS
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+
+static void uv__async(EV_P_ ev_async* w, int revents) {
+ uv_async_t* async = container_of(w, uv_async_t, async_watcher);
+
+ if (async->async_cb) {
+ async->async_cb(async, 0);
+ }
+}
+
+
+int uv_async_init(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb) {
+ uv__handle_init(loop, (uv_handle_t*)async, UV_ASYNC);
+ loop->counters.async_init++;
+
+ ev_async_init(&async->async_watcher, uv__async);
+ async->async_cb = async_cb;
+
+ /* Note: This does not have symmetry with the other libev wrappers. */
+ ev_async_start(loop->ev, &async->async_watcher);
+ ev_unref(loop->ev);
+
+ return 0;
+}
+
+
+int uv_async_send(uv_async_t* async) {
+ ev_async_send(async->loop->ev, &async->async_watcher);
+ return 0;
+}
+
+
+void uv__async_close(uv_async_t* handle) {
+ ev_async_stop(handle->loop->ev, &handle->async_watcher);
+ ev_ref(handle->loop->ev);
+}
* This is called once per second by loop->timer. It is used to
* constantly callback into c-ares for possibly processing timeouts.
*/
-static void uv__ares_timeout(struct ev_loop* ev, struct ev_timer* watcher,
- int revents) {
- uv_loop_t* loop = ev_userdata(ev);
+static void uv__ares_timeout(uv_timer_t* handle, int status) {
+ assert(!uv_ares_handles_empty(handle->loop));
+ ares_process_fd(handle->loop->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+}
+
+
+static void uv__ares_timer_start(uv_loop_t* loop) {
+ if (uv_is_active((uv_handle_t*)&loop->timer)) return;
+ uv_timer_start(&loop->timer, uv__ares_timeout, 1000, 1000);
+ uv_ref(loop);
+}
- assert(ev == loop->ev);
- assert((uv_loop_t*)watcher->data == loop);
- assert(watcher == &loop->timer);
- assert(revents == EV_TIMER);
- assert(!uv_ares_handles_empty(loop));
- ares_process_fd(loop->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+static void uv__ares_timer_stop(uv_loop_t* loop) {
+ if (!uv_is_active((uv_handle_t*)&loop->timer)) return;
+ uv_timer_stop(&loop->timer);
+ uv_unref(loop);
}
assert(ev == loop->ev);
/* Reset the idle timer */
- ev_timer_again(ev, &loop->timer);
+ uv_timer_again(&loop->timer);
/* Process DNS responses */
ares_process_fd(loop->channel,
/* New socket */
/* If this is the first socket then start the timer. */
- if (!ev_is_active(&loop->timer)) {
+ if (!uv_is_active((uv_handle_t*)&loop->timer)) {
assert(uv_ares_handles_empty(loop));
- ev_timer_again(loop->ev, &loop->timer);
+ uv__ares_timer_start(loop);
}
h = uv__ares_task_create(loop, sock);
free(h);
if (uv_ares_handles_empty(loop)) {
- ev_timer_stop(loop->ev, &loop->timer);
+ uv__ares_timer_stop(loop);
}
}
}
* Initialize the timeout timer. The timer won't be started until the
* first socket is opened.
*/
- ev_timer_init(&loop->timer, uv__ares_timeout, 1., 1.);
+ uv_timer_init(loop, &loop->timer);
+ uv_unref(loop);
loop->timer.data = loop;
return rc;
void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) {
/* only allow destroy if did init */
if (loop->channel) {
- ev_timer_stop(loop->ev, &loop->timer);
+ uv__ares_timer_stop(loop);
ares_destroy(channel);
loop->channel = NULL;
}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+
+static void uv__check(EV_P_ ev_check* w, int revents) {
+ uv_check_t* check = container_of(w, uv_check_t, check_watcher);
+
+ if (check->check_cb) {
+ check->check_cb(check, 0);
+ }
+}
+
+
+int uv_check_init(uv_loop_t* loop, uv_check_t* check) {
+ uv__handle_init(loop, (uv_handle_t*)check, UV_CHECK);
+ loop->counters.check_init++;
+
+ ev_check_init(&check->check_watcher, uv__check);
+ check->check_cb = NULL;
+
+ return 0;
+}
+
+
+int uv_check_start(uv_check_t* check, uv_check_cb cb) {
+ int was_active = ev_is_active(&check->check_watcher);
+
+ check->check_cb = cb;
+
+ ev_check_start(check->loop->ev, &check->check_watcher);
+
+ if (!was_active) {
+ ev_unref(check->loop->ev);
+ }
+
+ return 0;
+}
+
+
+int uv_check_stop(uv_check_t* check) {
+ int was_active = ev_is_active(&check->check_watcher);
+
+ ev_check_stop(check->loop->ev, &check->check_watcher);
+
+ if (was_active) {
+ ev_ref(check->loop->ev);
+ }
+
+ return 0;
+}
+
+
+int uv__check_active(const uv_check_t* handle) {
+ return ev_is_active(&handle->check_watcher);
+}
+
+
+void uv__check_close(uv_check_t* handle) {
+ uv_check_stop(handle);
+}
static uv_loop_t default_loop_struct;
static uv_loop_t* default_loop_ptr;
-void uv__next(EV_P_ ev_idle* watcher, int revents);
static void uv__finish_close(uv_handle_t* handle);
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
- uv_async_t* async;
- uv_stream_t* stream;
- uv_process_t* process;
-
handle->close_cb = close_cb;
switch (handle->type) {
- case UV_NAMED_PIPE:
- uv_pipe_cleanup((uv_pipe_t*)handle);
- /* Fall through. */
-
- case UV_TTY:
- case UV_TCP:
- stream = (uv_stream_t*)handle;
-
- uv_read_stop(stream);
- ev_io_stop(stream->loop->ev, &stream->write_watcher);
-
- close(stream->fd);
- stream->fd = -1;
-
- if (stream->accepted_fd >= 0) {
- close(stream->accepted_fd);
- stream->accepted_fd = -1;
- }
+ case UV_NAMED_PIPE:
+ uv__pipe_close((uv_pipe_t*)handle);
+ break;
- assert(!ev_is_active(&stream->read_watcher));
- assert(!ev_is_active(&stream->write_watcher));
- break;
+ case UV_TTY:
+ case UV_TCP:
+ uv__stream_close((uv_stream_t*)handle);
+ break;
- case UV_UDP:
- uv__udp_start_close((uv_udp_t*)handle);
- break;
+ case UV_UDP:
+ uv__udp_close((uv_udp_t*)handle);
+ break;
- case UV_PREPARE:
- uv_prepare_stop((uv_prepare_t*) handle);
- break;
+ case UV_PREPARE:
+ uv__prepare_close((uv_prepare_t*)handle);
+ break;
- case UV_CHECK:
- uv_check_stop((uv_check_t*) handle);
- break;
+ case UV_CHECK:
+ uv__check_close((uv_check_t*)handle);
+ break;
- case UV_IDLE:
- uv_idle_stop((uv_idle_t*) handle);
- break;
+ case UV_IDLE:
+ uv__idle_close((uv_idle_t*)handle);
+ break;
- case UV_ASYNC:
- async = (uv_async_t*)handle;
- ev_async_stop(async->loop->ev, &async->async_watcher);
- ev_ref(async->loop->ev);
- break;
+ case UV_ASYNC:
+ uv__async_close((uv_async_t*)handle);
+ break;
- case UV_TIMER:
- uv_timer_stop((uv_timer_t*)handle);
- break;
+ case UV_TIMER:
+ uv__timer_close((uv_timer_t*)handle);
+ break;
- case UV_PROCESS:
- process = (uv_process_t*)handle;
- ev_child_stop(process->loop->ev, &process->child_watcher);
- break;
+ case UV_PROCESS:
+ uv__process_close((uv_process_t*)handle);
+ break;
- case UV_FS_EVENT:
- uv__fs_event_destroy((uv_fs_event_t*)handle);
- break;
+ case UV_FS_EVENT:
+ uv__fs_event_close((uv_fs_event_t*)handle);
+ break;
- default:
- assert(0);
+ default:
+ assert(0);
}
handle->flags |= UV_CLOSING;
+ handle->endgame_next = handle->loop->endgame_handles;
+ handle->loop->endgame_handles = handle;
+ uv_unref(handle->loop);
+}
+
- /* This is used to call the on_close callback in the next loop. */
- ev_idle_start(handle->loop->ev, &handle->next_watcher);
- ev_feed_event(handle->loop->ev, &handle->next_watcher, EV_IDLE);
- assert(ev_is_pending(&handle->next_watcher));
+int uv_is_closing(const uv_handle_t* handle) {
+ return handle->flags & (UV_CLOSING | UV_CLOSED);
}
-static int uv__loop_init(uv_loop_t* loop,
- struct ev_loop *(ev_loop_new)(unsigned int flags)) {
- memset(loop, 0, sizeof(*loop));
- RB_INIT(&loop->uv_ares_handles_);
-#if HAVE_KQUEUE
- loop->ev = ev_loop_new(EVBACKEND_KQUEUE);
-#else
- loop->ev = ev_loop_new(EVFLAG_AUTO);
-#endif
- ev_set_userdata(loop->ev, loop);
- eio_channel_init(&loop->uv_eio_channel, loop);
- uv__loop_platform_init(loop);
- return 0;
+uv_loop_t* uv_default_loop(void) {
+ if (default_loop_ptr)
+ return default_loop_ptr;
+
+ if (uv__loop_init(&default_loop_struct, /* default_loop? */ 1))
+ return NULL;
+
+ return (default_loop_ptr = &default_loop_struct);
}
if ((loop = malloc(sizeof(*loop))) == NULL)
return NULL;
- if (uv__loop_init(loop, ev_loop_new)) {
+ if (uv__loop_init(loop, /* default_loop? */ 0)) {
free(loop);
return NULL;
}
void uv_loop_delete(uv_loop_t* loop) {
- uv_ares_destroy(loop, loop->channel);
- ev_loop_destroy(loop->ev);
- uv__loop_platform_delete(loop);
+ uv__loop_delete(loop);
#ifndef NDEBUG
memset(loop, -1, sizeof *loop);
#endif
}
-uv_loop_t* uv_default_loop(void) {
- if (default_loop_ptr)
- return default_loop_ptr;
-
- if (uv__loop_init(&default_loop_struct, ev_default_loop))
- return NULL;
+void uv__run(uv_loop_t* loop) {
+ ev_run(loop->ev, EVRUN_ONCE);
- default_loop_ptr = &default_loop_struct;
- return default_loop_ptr;
+ while (loop->endgame_handles)
+ uv__finish_close(loop->endgame_handles);
}
int uv_run(uv_loop_t* loop) {
- ev_run(loop->ev, 0);
+ do
+ uv__run(loop);
+ while (uv_loop_refcount(loop) > 0);
+
return 0;
}
int uv_run_once(uv_loop_t* loop) {
- ev_run(loop->ev, EVRUN_ONCE);
+ uv__run(loop);
return 0;
}
handle->loop = loop;
handle->type = type;
handle->flags = 0;
-
- ev_init(&handle->next_watcher, uv__next);
-
- /* Ref the loop until this handle is closed. See uv__finish_close. */
- ev_ref(loop->ev);
+ handle->endgame_next = NULL;
+ uv_ref(loop); /* unref'd in uv_close() */
}
break;
}
- ev_idle_stop(loop->ev, &handle->next_watcher);
+
+ loop->endgame_handles = handle->endgame_next;
if (handle->close_cb) {
handle->close_cb(handle);
}
-
- ev_unref(loop->ev);
-}
-
-
-void uv__next(EV_P_ ev_idle* w, int revents) {
- uv_handle_t* handle = container_of(w, uv_handle_t, next_watcher);
-
- assert(revents == EV_IDLE);
-
- /* For now this function is only to handle the closing event, but we might
- * put more stuff here later.
- */
- assert(handle->flags & UV_CLOSING);
- uv__finish_close(handle);
}
}
-void uv__req_init(uv_loop_t* loop, uv_req_t* req) {
- loop->counters.req_init++;
- req->type = UV_UNKNOWN_REQ;
-}
-
-
-static void uv__prepare(EV_P_ ev_prepare* w, int revents) {
- uv_prepare_t* prepare = container_of(w, uv_prepare_t, prepare_watcher);
-
- if (prepare->prepare_cb) {
- prepare->prepare_cb(prepare, 0);
- }
-}
-
-
-int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare) {
- uv__handle_init(loop, (uv_handle_t*)prepare, UV_PREPARE);
- loop->counters.prepare_init++;
-
- ev_prepare_init(&prepare->prepare_watcher, uv__prepare);
- prepare->prepare_cb = NULL;
-
- return 0;
-}
-
-
-int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb) {
- int was_active = ev_is_active(&prepare->prepare_watcher);
-
- prepare->prepare_cb = cb;
-
- ev_prepare_start(prepare->loop->ev, &prepare->prepare_watcher);
-
- if (!was_active) {
- ev_unref(prepare->loop->ev);
- }
-
- return 0;
-}
-
-
-int uv_prepare_stop(uv_prepare_t* prepare) {
- int was_active = ev_is_active(&prepare->prepare_watcher);
-
- ev_prepare_stop(prepare->loop->ev, &prepare->prepare_watcher);
-
- if (was_active) {
- ev_ref(prepare->loop->ev);
- }
- return 0;
-}
-
-
-
-static void uv__check(EV_P_ ev_check* w, int revents) {
- uv_check_t* check = container_of(w, uv_check_t, check_watcher);
-
- if (check->check_cb) {
- check->check_cb(check, 0);
- }
-}
-
-
-int uv_check_init(uv_loop_t* loop, uv_check_t* check) {
- uv__handle_init(loop, (uv_handle_t*)check, UV_CHECK);
- loop->counters.check_init++;
-
- ev_check_init(&check->check_watcher, uv__check);
- check->check_cb = NULL;
-
- return 0;
-}
-
-
-int uv_check_start(uv_check_t* check, uv_check_cb cb) {
- int was_active = ev_is_active(&check->check_watcher);
-
- check->check_cb = cb;
-
- ev_check_start(check->loop->ev, &check->check_watcher);
-
- if (!was_active) {
- ev_unref(check->loop->ev);
- }
-
- return 0;
-}
-
-
-int uv_check_stop(uv_check_t* check) {
- int was_active = ev_is_active(&check->check_watcher);
-
- ev_check_stop(check->loop->ev, &check->check_watcher);
-
- if (was_active) {
- ev_ref(check->loop->ev);
- }
-
- return 0;
-}
-
-
-static void uv__idle(EV_P_ ev_idle* w, int revents) {
- uv_idle_t* idle = container_of(w, uv_idle_t, idle_watcher);
-
- if (idle->idle_cb) {
- idle->idle_cb(idle, 0);
- }
-}
-
-
-
-int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) {
- uv__handle_init(loop, (uv_handle_t*)idle, UV_IDLE);
- loop->counters.idle_init++;
-
- ev_idle_init(&idle->idle_watcher, uv__idle);
- idle->idle_cb = NULL;
-
- return 0;
-}
-
-
-int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb) {
- int was_active = ev_is_active(&idle->idle_watcher);
-
- idle->idle_cb = cb;
- ev_idle_start(idle->loop->ev, &idle->idle_watcher);
-
- if (!was_active) {
- ev_unref(idle->loop->ev);
- }
-
- return 0;
-}
-
-
-int uv_idle_stop(uv_idle_t* idle) {
- int was_active = ev_is_active(&idle->idle_watcher);
-
- ev_idle_stop(idle->loop->ev, &idle->idle_watcher);
-
- if (was_active) {
- ev_ref(idle->loop->ev);
- }
-
- return 0;
-}
-
-
-int uv_is_active(uv_handle_t* handle) {
+int uv_is_active(const uv_handle_t* handle) {
switch (handle->type) {
- case UV_TIMER:
- return ev_is_active(&((uv_timer_t*)handle)->timer_watcher);
-
- case UV_PREPARE:
- return ev_is_active(&((uv_prepare_t*)handle)->prepare_watcher);
-
- case UV_CHECK:
- return ev_is_active(&((uv_check_t*)handle)->check_watcher);
-
- case UV_IDLE:
- return ev_is_active(&((uv_idle_t*)handle)->idle_watcher);
-
- default:
- return 1;
- }
-}
-
-
-static void uv__async(EV_P_ ev_async* w, int revents) {
- uv_async_t* async = container_of(w, uv_async_t, async_watcher);
-
- if (async->async_cb) {
- async->async_cb(async, 0);
+ case UV_CHECK:
+ return uv__check_active((const uv_check_t*)handle);
+ case UV_IDLE:
+ return uv__idle_active((const uv_idle_t*)handle);
+ case UV_PREPARE:
+ return uv__prepare_active((const uv_prepare_t*)handle);
+ case UV_TIMER:
+ return uv__timer_active((const uv_timer_t*)handle);
+ default:
+ return 1;
}
}
-int uv_async_init(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb) {
- uv__handle_init(loop, (uv_handle_t*)async, UV_ASYNC);
- loop->counters.async_init++;
-
- ev_async_init(&async->async_watcher, uv__async);
- async->async_cb = async_cb;
-
- /* Note: This does not have symmetry with the other libev wrappers. */
- ev_async_start(loop->ev, &async->async_watcher);
- ev_unref(loop->ev);
-
- return 0;
-}
-
-
-int uv_async_send(uv_async_t* async) {
- ev_async_send(async->loop->ev, &async->async_watcher);
- return 0;
-}
-
-
-static int uv__timer_active(const uv_timer_t* timer) {
- return timer->flags & UV_TIMER_ACTIVE;
-}
-
-
-static int uv__timer_repeating(const uv_timer_t* timer) {
- return timer->flags & UV_TIMER_REPEAT;
-}
-
-
-static void uv__timer_cb(EV_P_ ev_timer* w, int revents) {
- uv_timer_t* timer = container_of(w, uv_timer_t, timer_watcher);
-
- assert(uv__timer_active(timer));
-
- if (!uv__timer_repeating(timer)) {
- timer->flags &= ~UV_TIMER_ACTIVE;
- ev_ref(EV_A);
- }
-
- if (timer->timer_cb) {
- timer->timer_cb(timer, 0);
- }
-}
-
-
-int uv_timer_init(uv_loop_t* loop, uv_timer_t* timer) {
- uv__handle_init(loop, (uv_handle_t*)timer, UV_TIMER);
- loop->counters.timer_init++;
-
- ev_init(&timer->timer_watcher, uv__timer_cb);
-
- return 0;
-}
-
-
-int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout,
- int64_t repeat) {
- if (uv__timer_active(timer)) {
- return -1;
- }
-
- timer->timer_cb = cb;
- timer->flags |= UV_TIMER_ACTIVE;
-
- if (repeat)
- timer->flags |= UV_TIMER_REPEAT;
- else
- timer->flags &= ~UV_TIMER_REPEAT;
-
- ev_timer_set(&timer->timer_watcher, timeout / 1000.0, repeat / 1000.0);
- ev_timer_start(timer->loop->ev, &timer->timer_watcher);
- ev_unref(timer->loop->ev);
-
- return 0;
-}
-
-
-int uv_timer_stop(uv_timer_t* timer) {
- if (uv__timer_active(timer)) {
- ev_ref(timer->loop->ev);
- }
-
- timer->flags &= ~(UV_TIMER_ACTIVE | UV_TIMER_REPEAT);
- ev_timer_stop(timer->loop->ev, &timer->timer_watcher);
-
- return 0;
-}
-
-
-int uv_timer_again(uv_timer_t* timer) {
- if (!uv__timer_active(timer)) {
- uv__set_sys_error(timer->loop, EINVAL);
- return -1;
- }
-
- assert(uv__timer_repeating(timer));
- ev_timer_again(timer->loop->ev, &timer->timer_watcher);
- return 0;
-}
-
-
-void uv_timer_set_repeat(uv_timer_t* timer, int64_t repeat) {
- assert(timer->type == UV_TIMER);
- timer->timer_watcher.repeat = repeat / 1000.0;
-
- if (repeat)
- timer->flags |= UV_TIMER_REPEAT;
- else
- timer->flags &= ~UV_TIMER_REPEAT;
-}
-
-
-int64_t uv_timer_get_repeat(uv_timer_t* timer) {
- assert(timer->type == UV_TIMER);
- return (int64_t)(1000 * timer->timer_watcher.repeat);
-}
-
-
static int uv_getaddrinfo_done(eio_req* req) {
uv_getaddrinfo_t* handle = req->data;
struct addrinfo *res = handle->res;
return -1;
}
- uv__req_init(loop, (uv_req_t*)handle);
- handle->type = UV_GETADDRINFO;
+ uv__req_init(loop, handle, UV_GETADDRINFO);
handle->loop = loop;
handle->cb = cb;
assert(sockfd >= 0);
while (1) {
-#if HAVE_SYS_ACCEPT4
- peerfd = sys_accept4(sockfd, saddr, &slen, SOCK_NONBLOCK | SOCK_CLOEXEC);
-
+#if __linux__
+ peerfd = uv__accept4(sockfd, saddr, &slen, UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC);
if (peerfd != -1)
break;
}
-void uv__fs_event_destroy(uv_fs_event_t* handle) {
+void uv__fs_event_close(uv_fs_event_t* handle) {
assert(0 && "implement me");
}
int uv_exepath(char* buffer, size_t* size) {
uint32_t usize;
int result;
+ char* path;
char* fullpath;
if (!buffer || !size) {
result = _NSGetExecutablePath(buffer, &usize);
if (result) return result;
- fullpath = realpath(buffer, NULL);
+ path = (char*)malloc(2 * PATH_MAX);
+ fullpath = realpath(buffer, path);
if (fullpath == NULL) {
+ free(path);
return -1;
}
case EBADF: return UV_EBADF;
case EPIPE: return UV_EPIPE;
case EAGAIN: return UV_EAGAIN;
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK: return UV_EAGAIN;
+#endif
case ECONNRESET: return UV_ECONNRESET;
case EFAULT: return UV_EFAULT;
case EMFILE: return UV_EMFILE;
case EBUSY: return UV_EBUSY;
case ENOTEMPTY: return UV_ENOTEMPTY;
case ENOSPC: return UV_ENOSPC;
+ case EROFS: return UV_EROFS;
+ case ENOMEM: return UV_ENOMEM;
default: return UV_UNKNOWN;
}
UNREACHABLE();
/* Make sure the thread pool is initialized. */
uv_eio_init(loop);
- uv__req_init(loop, (uv_req_t*)req);
- req->type = UV_FS;
+ uv__req_init(loop, req, UV_FS);
req->loop = loop;
req->fs_type = fs_type;
req->cb = cb;
int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
- size_t length, off_t offset, uv_fs_cb cb) {
+ size_t length, int64_t offset, uv_fs_cb cb) {
uv_fs_req_init(loop, req, UV_FS_READ, NULL, cb);
if (cb) {
int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
- size_t length, off_t offset, uv_fs_cb cb) {
+ size_t length, int64_t offset, uv_fs_cb cb) {
uv_fs_req_init(loop, req, UV_FS_WRITE, NULL, cb);
if (cb) {
}
-int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, off_t offset,
+int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, int64_t offset,
uv_fs_cb cb) {
char* path = NULL;
WRAP_EIO(UV_FS_FTRUNCATE, eio_ftruncate, ftruncate, ARGS2(file, offset))
int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd,
- off_t in_offset, size_t length, uv_fs_cb cb) {
+ int64_t in_offset, size_t length, uv_fs_cb cb) {
char* path = NULL;
WRAP_EIO(UV_FS_SENDFILE, eio_sendfile, eio_sendfile_sync,
ARGS4(out_fd, in_fd, in_offset, length))
#if HAVE_FUTIMES
-static int _futime(const uv_file file, double atime, double mtime) {
+static int _futime(const uv_file fd, double atime, double mtime) {
+#if __linux__
+ /* utimesat() has nanosecond resolution but we stick to microseconds
+ * for the sake of consistency with other platforms.
+ */
+ struct timespec ts[2];
+ ts[0].tv_sec = atime;
+ ts[0].tv_nsec = (unsigned long)(atime * 1000000) % 1000000 * 1000;
+ ts[1].tv_sec = mtime;
+ ts[1].tv_nsec = (unsigned long)(mtime * 1000000) % 1000000 * 1000;
+ return uv__utimesat(fd, NULL, ts, 0);
+#else
struct timeval tv[2];
-
- /* FIXME possible loss of precision in floating-point arithmetic? */
tv[0].tv_sec = atime;
tv[0].tv_usec = (unsigned long)(atime * 1000000) % 1000000;
-
tv[1].tv_sec = mtime;
tv[1].tv_usec = (unsigned long)(mtime * 1000000) % 1000000;
-
-#ifdef __sun
- return futimesat(file, NULL, tv);
-#else
- return futimes(file, tv);
-#endif
+ return futimes(fd, tv);
+#endif /* __linux__ */
}
-#endif
+#endif /* HAVE_FUTIMES */
int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
uv_eio_init(loop);
- uv__req_init(loop, (uv_req_t*)req);
+ uv__req_init(loop, req, UV_WORK);
uv_ref(loop);
req->loop = loop;
req->data = data;
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+
+static void uv__idle(EV_P_ ev_idle* w, int revents) {
+ uv_idle_t* idle = container_of(w, uv_idle_t, idle_watcher);
+
+ if (idle->idle_cb) {
+ idle->idle_cb(idle, 0);
+ }
+}
+
+
+int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) {
+ uv__handle_init(loop, (uv_handle_t*)idle, UV_IDLE);
+ loop->counters.idle_init++;
+
+ ev_idle_init(&idle->idle_watcher, uv__idle);
+ idle->idle_cb = NULL;
+
+ return 0;
+}
+
+
+int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb) {
+ int was_active = ev_is_active(&idle->idle_watcher);
+
+ idle->idle_cb = cb;
+ ev_idle_start(idle->loop->ev, &idle->idle_watcher);
+
+ if (!was_active) {
+ ev_unref(idle->loop->ev);
+ }
+
+ return 0;
+}
+
+
+int uv_idle_stop(uv_idle_t* idle) {
+ int was_active = ev_is_active(&idle->idle_watcher);
+
+ ev_idle_stop(idle->loop->ev, &idle->idle_watcher);
+
+ if (was_active) {
+ ev_ref(idle->loop->ev);
+ }
+
+ return 0;
+}
+
+
+int uv__idle_active(const uv_idle_t* handle) {
+ return ev_is_active(&handle->idle_watcher);
+}
+
+
+void uv__idle_close(uv_idle_t* handle) {
+ uv_idle_stop(handle);
+}
#undef HAVE_KQUEUE
#undef HAVE_PORTS_FS
-#if defined(__linux__)
-
-# undef HAVE_SYS_UTIMESAT
-# undef HAVE_SYS_PIPE2
-# undef HAVE_SYS_ACCEPT4
-
-# undef _GNU_SOURCE
-# define _GNU_SOURCE
-
-# include <linux/version.h>
-# include <sys/syscall.h>
-# include <features.h>
-# include <unistd.h>
-
-# if __NR_utimensat
-# define HAVE_SYS_UTIMESAT 1
-# endif
-# if __NR_pipe2
-# define HAVE_SYS_PIPE2 1
-# endif
-# if __NR_accept4
-# define HAVE_SYS_ACCEPT4 1
-# endif
-
-# ifndef O_CLOEXEC
-# define O_CLOEXEC 02000000
-# endif
-
-# ifndef SOCK_CLOEXEC
-# define SOCK_CLOEXEC O_CLOEXEC
-# endif
-
-# ifndef SOCK_NONBLOCK
-# define SOCK_NONBLOCK O_NONBLOCK
-# endif
-
-# if HAVE_SYS_UTIMESAT
-inline static int sys_utimesat(int dirfd,
- const char* path,
- const struct timespec times[2],
- int flags)
-{
- return syscall(__NR_utimensat, dirfd, path, times, flags);
-}
-inline static int sys_futimes(int fd, const struct timeval times[2])
-{
- struct timespec ts[2];
- ts[0].tv_sec = times[0].tv_sec, ts[0].tv_nsec = times[0].tv_usec * 1000;
- ts[1].tv_sec = times[1].tv_sec, ts[1].tv_nsec = times[1].tv_usec * 1000;
- return sys_utimesat(fd, NULL, ts, 0);
-}
-# undef HAVE_FUTIMES
-# define HAVE_FUTIMES 1
-# define futimes(fd, times) sys_futimes(fd, times)
-# endif /* HAVE_SYS_FUTIMESAT */
-
-# if HAVE_SYS_PIPE2
-inline static int sys_pipe2(int pipefd[2], int flags)
-{
- return syscall(__NR_pipe2, pipefd, flags);
-}
-# endif /* HAVE_SYS_PIPE2 */
-
-# if HAVE_SYS_ACCEPT4
-inline static int sys_accept4(int fd,
- struct sockaddr* addr,
- socklen_t* addrlen,
- int flags)
-{
- return syscall(__NR_accept4, fd, addr, addrlen, flags);
-}
-# endif /* HAVE_SYS_ACCEPT4 */
-
+#if __linux__
+# include "linux/syscalls.h"
+# define HAVE_FUTIMES 1 /* emulated with utimesat() */
#endif /* __linux__ */
#if defined(__sun)
# ifdef PORT_SOURCE_FILE
# define HAVE_PORTS_FS 1
# endif
+# define HAVE_FUTIMES 1
+# define futimes(fd, tv) futimesat(fd, (void*)0, tv)
#endif /* __sun */
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun)
UV_TIMER_REPEAT = 0x100
};
+inline static void uv__req_init(uv_loop_t* loop,
+ uv_req_t* req,
+ uv_req_type type) {
+ loop->counters.req_init++;
+ req->type = type;
+}
+#define uv__req_init(loop, req, type) \
+ uv__req_init((loop), (uv_req_t*)(req), (type))
+
/* core */
void uv__handle_init(uv_loop_t* loop, uv_handle_t* handle, uv_handle_type type);
int uv__nonblock(int fd, int set) __attribute__((unused));
int uv__socket(int domain, int type, int protocol);
int uv__dup(int fd);
+/* loop */
+int uv__loop_init(uv_loop_t* loop, int default_loop);
+void uv__loop_delete(uv_loop_t* loop);
+
/* error */
uv_err_code uv_translate_sys_error(int sys_errno);
void uv_fatal_error(const int errorno, const char* syscall);
-/* requests */
-void uv__req_init(uv_loop_t* loop, uv_req_t*);
-
/* stream */
void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream,
uv_handle_type type);
/* pipe */
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
void uv__pipe_accept(EV_P_ ev_io* watcher, int revents);
-int uv_pipe_cleanup(uv_pipe_t* handle);
-/* udp */
-void uv__udp_start_close(uv_udp_t* handle);
+/* various */
+int uv__check_active(const uv_check_t* handle);
+int uv__idle_active(const uv_idle_t* handle);
+int uv__prepare_active(const uv_prepare_t* handle);
+int uv__timer_active(const uv_timer_t* handle);
+
+void uv__async_close(uv_async_t* handle);
+void uv__check_close(uv_check_t* handle);
+void uv__fs_event_close(uv_fs_event_t* handle);
+void uv__idle_close(uv_idle_t* handle);
+void uv__pipe_close(uv_pipe_t* handle);
+void uv__prepare_close(uv_prepare_t* handle);
+void uv__process_close(uv_process_t* handle);
+void uv__stream_close(uv_stream_t* handle);
+void uv__timer_close(uv_timer_t* handle);
+void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle);
-/* fs */
-void uv__fs_event_destroy(uv_fs_event_t* handle);
-
#define UV__F_IPC (1 << 0)
#define UV__F_NONBLOCK (1 << 1)
int uv__make_socketpair(int fds[2], int flags);
int uv__make_pipe(int fds[2], int flags);
-#if __linux__
-void uv__inotify_loop_init(uv_loop_t* loop);
-void uv__inotify_loop_delete(uv_loop_t* loop);
-# define uv__loop_platform_init(loop) uv__inotify_loop_init(loop)
-# define uv__loop_platform_delete(loop) uv__inotify_loop_delete(loop)
-#else
-# define uv__loop_platform_init(loop)
-# define uv__loop_platform_delete(loop)
-#endif
-
#endif /* UV_UNIX_INTERNAL_H_ */
/* We don't support any flags yet. */
assert(!flags);
- if (cb == NULL) {
- uv__set_sys_error(loop, EINVAL);
- return -1;
- }
-
/* TODO open asynchronously - but how do we report back errors? */
if ((fd = open(filename, O_RDONLY)) == -1) {
uv__set_sys_error(loop, errno);
}
-void uv__fs_event_destroy(uv_fs_event_t* handle) {
+void uv__fs_event_close(uv_fs_event_t* handle) {
uv__fs_event_stop(handle);
free(handle->filename);
close(handle->fd);
#include "uv.h"
#include "tree.h"
#include "../internal.h"
+#include "syscalls.h"
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
-#include <fcntl.h>
-
-#undef HAVE_INOTIFY_INIT
-#undef HAVE_INOTIFY_INIT1
-#undef HAVE_INOTIFY_ADD_WATCH
-#undef HAVE_INOTIFY_RM_WATCH
-
-#if __NR_inotify_init
-# define HAVE_INOTIFY_INIT 1
-#endif
-#if __NR_inotify_init1
-# define HAVE_INOTIFY_INIT1 1
-#endif
-#if __NR_inotify_add_watch
-# define HAVE_INOTIFY_ADD_WATCH 1
-#endif
-#if __NR_inotify_rm_watch
-# define HAVE_INOTIFY_RM_WATCH 1
-#endif
-
-#if HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1
-# undef IN_ACCESS
-# undef IN_MODIFY
-# undef IN_ATTRIB
-# undef IN_CLOSE_WRITE
-# undef IN_CLOSE_NOWRITE
-# undef IN_OPEN
-# undef IN_MOVED_FROM
-# undef IN_MOVED_TO
-# undef IN_CREATE
-# undef IN_DELETE
-# undef IN_DELETE_SELF
-# undef IN_MOVE_SELF
-# define IN_ACCESS 0x001
-# define IN_MODIFY 0x002
-# define IN_ATTRIB 0x004
-# define IN_CLOSE_WRITE 0x008
-# define IN_CLOSE_NOWRITE 0x010
-# define IN_OPEN 0x020
-# define IN_MOVED_FROM 0x040
-# define IN_MOVED_TO 0x080
-# define IN_CREATE 0x100
-# define IN_DELETE 0x200
-# define IN_DELETE_SELF 0x400
-# define IN_MOVE_SELF 0x800
-struct inotify_event {
- int32_t wd;
- uint32_t mask;
- uint32_t cookie;
- uint32_t len;
- /* char name[0]; */
-};
-#endif /* HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1 */
-
-#undef IN_CLOEXEC
-#undef IN_NONBLOCK
-
-#if HAVE_INOTIFY_INIT1
-# define IN_CLOEXEC O_CLOEXEC
-# define IN_NONBLOCK O_NONBLOCK
-#endif /* HAVE_INOTIFY_INIT1 */
-
-#if HAVE_INOTIFY_INIT
-inline static int inotify_init(void) {
- return syscall(__NR_inotify_init);
-}
-#endif /* HAVE_INOTIFY_INIT */
-
-#if HAVE_INOTIFY_INIT1
-inline static int inotify_init1(int flags) {
- return syscall(__NR_inotify_init1, flags);
-}
-#endif /* HAVE_INOTIFY_INIT1 */
-
-#if HAVE_INOTIFY_ADD_WATCH
-inline static int inotify_add_watch(int fd, const char* path, uint32_t mask) {
- return syscall(__NR_inotify_add_watch, fd, path, mask);
-}
-#endif /* HAVE_INOTIFY_ADD_WATCH */
-
-#if HAVE_INOTIFY_RM_WATCH
-inline static int inotify_rm_watch(int fd, uint32_t wd) {
- return syscall(__NR_inotify_rm_watch, fd, wd);
-}
-#endif /* HAVE_INOTIFY_RM_WATCH */
/* Don't look aghast, this is exactly how glibc's basename() works. */
RB_GENERATE_STATIC(uv__inotify_watchers, uv_fs_event_s, node, compare_watchers)
-void uv__inotify_loop_init(uv_loop_t* loop) {
- RB_INIT(&loop->inotify_watchers);
- loop->inotify_fd = -1;
-}
-
-
-void uv__inotify_loop_delete(uv_loop_t* loop) {
- if (loop->inotify_fd == -1) return;
- ev_io_stop(loop->ev, &loop->inotify_read_watcher);
- close(loop->inotify_fd);
- loop->inotify_fd = -1;
-}
-
-
-#if HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1
-
static void uv__inotify_read(EV_P_ ev_io* w, int revents);
static int new_inotify_fd(void) {
int fd;
-#if HAVE_INOTIFY_INIT1
- fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
if (fd != -1)
return fd;
if (errno != ENOSYS)
return -1;
-#endif
- if ((fd = inotify_init()) == -1)
+ if ((fd = uv__inotify_init()) == -1)
return -1;
if (uv__cloexec(fd, 1) || uv__nonblock(fd, 1)) {
static void uv__inotify_read(EV_P_ ev_io* w, int revents) {
- const struct inotify_event* e;
+ const struct uv__inotify_event* e;
uv_fs_event_t* handle;
uv_loop_t* uv_loop;
const char* filename;
/* Now we have one or more inotify_event structs. */
for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
- e = (const struct inotify_event*)p;
+ e = (const struct uv__inotify_event*)p;
events = 0;
- if (e->mask & (IN_ATTRIB|IN_MODIFY))
+ if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY))
events |= UV_CHANGE;
- if (e->mask & ~(IN_ATTRIB|IN_MODIFY))
+ if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY))
events |= UV_RENAME;
handle = find_watcher(uv_loop, e->wd);
if (init_inotify(loop)) return -1;
- events = IN_ATTRIB
- | IN_CREATE
- | IN_MODIFY
- | IN_DELETE
- | IN_DELETE_SELF
- | IN_MOVED_FROM
- | IN_MOVED_TO;
+ events = UV__IN_ATTRIB
+ | UV__IN_CREATE
+ | UV__IN_MODIFY
+ | UV__IN_DELETE
+ | UV__IN_DELETE_SELF
+ | UV__IN_MOVE_SELF
+ | UV__IN_MOVED_FROM
+ | UV__IN_MOVED_TO;
- wd = inotify_add_watch(loop->inotify_fd, filename, events);
+ wd = uv__inotify_add_watch(loop->inotify_fd, filename, events);
if (wd == -1) return uv__set_sys_error(loop, errno);
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
}
-void uv__fs_event_destroy(uv_fs_event_t* handle) {
- inotify_rm_watch(handle->loop->inotify_fd, handle->fd);
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv__inotify_rm_watch(handle->loop->inotify_fd, handle->fd);
remove_watcher(handle);
handle->fd = -1;
free(handle->filename);
handle->filename = NULL;
}
-
-#else /* !HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1 */
-
-int uv_fs_event_init(uv_loop_t* loop,
- uv_fs_event_t* handle,
- const char* filename,
- uv_fs_event_cb cb,
- int flags) {
- loop->counters.fs_event_init++;
- uv__set_sys_error(loop, ENOSYS);
- return -1;
-}
-
-
-void uv__fs_event_destroy(uv_fs_event_t* handle) {
- UNREACHABLE();
-}
-
-#endif /* HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1 */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "syscalls.h"
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#if __i386__
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+#endif
+
+#if __arm__
+# if __thumb__ || __ARM_EABI__
+# define UV_SYSCALL_BASE 0
+# else
+# define UV_SYSCALL_BASE 0x900000
+# endif
+#endif /* __arm__ */
+
+#ifndef __NR_accept4
+# if __x86_64__
+# define __NR_accept4 288
+# elif __i386__
+ /* Nothing. Handled through socketcall(). */
+# elif __arm__
+# define __NR_accept4 (UV_SYSCALL_BASE + 366)
+# endif
+#endif /* __NR_accept4 */
+
+#ifndef __NR_inotify_init
+# if __x86_64__
+# define __NR_inotify_init 253
+# elif __i386__
+# define __NR_inotify_init 291
+# elif __arm__
+# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
+# endif
+#endif /* __NR_inotify_init */
+
+#ifndef __NR_inotify_init1
+# if __x86_64__
+# define __NR_inotify_init1 294
+# elif __i386__
+# define __NR_inotify_init1 332
+# elif __arm__
+# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
+# endif
+#endif /* __NR_inotify_init1 */
+
+#ifndef __NR_inotify_add_watch
+# if __x86_64__
+# define __NR_inotify_add_watch 254
+# elif __i386__
+# define __NR_inotify_add_watch 292
+# elif __arm__
+# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
+# endif
+#endif /* __NR_inotify_add_watch */
+
+#ifndef __NR_inotify_rm_watch
+# if __x86_64__
+# define __NR_inotify_rm_watch 255
+# elif __i386__
+# define __NR_inotify_rm_watch 293
+# elif __arm__
+# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
+# endif
+#endif /* __NR_inotify_rm_watch */
+
+#ifndef __NR_pipe2
+# if __x86_64__
+# define __NR_pipe2 293
+# elif __i386__
+# define __NR_pipe2 331
+# elif __arm__
+# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
+# endif
+#endif /* __NR_pipe2 */
+
+#ifndef __NR_recvmmsg
+# if __x86_64__
+# define __NR_recvmmsg 299
+# elif __i386__
+# define __NR_recvmmsg 337
+# elif __arm__
+# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
+# endif
+#endif /* __NR_recvmsg */
+
+#ifndef __NR_sendmmsg
+# if __x86_64__
+# define __NR_sendmmsg 307
+# elif __i386__
+# define __NR_sendmmsg 345
+# elif __arm__
+# define __NR_recvmmsg (UV_SYSCALL_BASE + 374)
+# endif
+#endif /* __NR_sendmmsg */
+
+#ifndef __NR_utimensat
+# if __x86_64__
+# define __NR_utimensat 280
+# elif __i386__
+# define __NR_utimensat 320
+# elif __arm__
+# define __NR_utimensat (UV_SYSCALL_BASE + 348)
+# endif
+#endif /* __NR_utimensat */
+
+
+int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
+#if __i386__
+ unsigned long args[] = {
+ (unsigned long) fd,
+ (unsigned long) addr,
+ (unsigned long) addrlen,
+ (unsigned long) flags
+ };
+ return syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args);
+#elif __NR_accept4
+ return syscall(__NR_accept4, fd, addr, addrlen, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_init(void) {
+#if __NR_inotify_init
+ return syscall(__NR_inotify_init);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_init1(int flags) {
+#if __NR_inotify_init1
+ return syscall(__NR_inotify_init1, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_add_watch(int fd, const char* path, __u32 mask) {
+#if __NR_inotify_add_watch
+ return syscall(__NR_inotify_add_watch, fd, path, mask);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_rm_watch(int fd, __s32 wd) {
+#if __NR_inotify_rm_watch
+ return syscall(__NR_inotify_rm_watch, fd, wd);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__pipe2(int pipefd[2], int flags) {
+#if __NR_pipe2
+ return syscall(__NR_pipe2, pipefd, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__sendmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags) {
+#if __NR_sendmmsg
+ return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__recvmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags,
+ struct timespec* timeout) {
+#if __NR_recvmmsg
+ return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__utimesat(int dirfd,
+ const char* path,
+ const struct timespec times[2],
+ int flags)
+{
+#if __NR_utimensat
+ return syscall(__NR_utimensat, dirfd, path, times, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_LINUX_SYSCALL_H_
+#define UV_LINUX_SYSCALL_H_
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/types.h>
+
+#define UV__O_NONBLOCK 0x800
+#define UV__O_CLOEXEC 0x80000
+
+#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
+#define UV__SOCK_NONBLOCK UV__O_NONBLOCK
+
+#define UV__IN_CLOEXEC UV__O_CLOEXEC
+#define UV__IN_NONBLOCK UV__O_NONBLOCK
+
+#define UV__IN_ACCESS 0x001
+#define UV__IN_MODIFY 0x002
+#define UV__IN_ATTRIB 0x004
+#define UV__IN_CLOSE_WRITE 0x008
+#define UV__IN_CLOSE_NOWRITE 0x010
+#define UV__IN_OPEN 0x020
+#define UV__IN_MOVED_FROM 0x040
+#define UV__IN_MOVED_TO 0x080
+#define UV__IN_CREATE 0x100
+#define UV__IN_DELETE 0x200
+#define UV__IN_DELETE_SELF 0x400
+#define UV__IN_MOVE_SELF 0x800
+
+struct uv__inotify_event {
+ __s32 wd;
+ __u32 mask;
+ __u32 cookie;
+ __u32 len;
+ /* char name[0]; */
+};
+
+struct uv__mmsghdr {
+ struct msghdr msg_hdr;
+ unsigned int msg_len;
+};
+
+int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
+int uv__inotify_init(void);
+int uv__inotify_init1(int flags);
+int uv__inotify_add_watch(int fd, const char* path, __u32 mask);
+int uv__inotify_rm_watch(int fd, __s32 wd);
+int uv__pipe2(int pipefd[2], int flags);
+int uv__recvmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags,
+ struct timespec* timeout);
+int uv__sendmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags);
+int uv__utimesat(int dirfd,
+ const char* path,
+ const struct timespec times[2],
+ int flags);
+
+#endif /* UV_LINUX_SYSCALL_H_ */
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "tree.h"
+#include "internal.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+int uv__loop_init(uv_loop_t* loop, int default_loop) {
+#if HAVE_KQUEUE
+ int flags = EVBACKEND_KQUEUE;
+#else
+ int flags = EVFLAG_AUTO;
+#endif
+ RB_INIT(&loop->uv_ares_handles_);
+ loop->endgame_handles = NULL;
+ loop->ev = (default_loop ? ev_default_loop : ev_loop_new)(flags);
+ ev_set_userdata(loop->ev, loop);
+ eio_channel_init(&loop->uv_eio_channel, loop);
+#if __linux__
+ RB_INIT(&loop->inotify_watchers);
+ loop->inotify_fd = -1;
+#endif
+ return 0;
+}
+
+
+void uv__loop_delete(uv_loop_t* loop) {
+ uv_ares_destroy(loop, loop->channel);
+ ev_loop_destroy(loop->ev);
+#if __linux__
+ if (loop->inotify_fd == -1) return;
+ ev_io_stop(loop->ev, &loop->inotify_read_watcher);
+ close(loop->inotify_fd);
+ loop->inotify_fd = -1;
+#endif
+}
}
-int uv_pipe_cleanup(uv_pipe_t* handle) {
- int saved_errno;
- int status;
-
- saved_errno = errno;
- status = -1;
-
+void uv__pipe_close(uv_pipe_t* handle) {
if (handle->pipe_fname) {
/*
* Unlink the file system entity before closing the file descriptor.
* Doing it the other way around introduces a race where our process
* unlinks a socket with the same name that's just been created by
* another thread or process.
- *
- * This is less of an issue now that we attach a file lock
- * to the socket but it's still a best practice.
*/
unlink(handle->pipe_fname);
free((void*)handle->pipe_fname);
}
- errno = saved_errno;
- return status;
+ uv__stream_close((uv_stream_t*)handle);
}
sockfd = uv__accept(pipe->fd, (struct sockaddr *)&saddr, sizeof saddr);
if (sockfd == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- assert(0 && "EAGAIN on uv__accept(pipefd)");
- } else {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
uv__set_sys_error(pipe->loop, errno);
+ pipe->connection_cb((uv_stream_t*)pipe, -1);
}
} else {
pipe->accepted_fd = sockfd;
pipe->connection_cb((uv_stream_t*)pipe, 0);
if (pipe->accepted_fd == sockfd) {
- /* The user hasn't yet accepted called uv_accept() */
+ /* The user hasn't called uv_accept() yet */
ev_io_stop(pipe->loop->ev, &pipe->read_watcher);
}
}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+
+static void uv__prepare(EV_P_ ev_prepare* w, int revents) {
+ uv_prepare_t* prepare = container_of(w, uv_prepare_t, prepare_watcher);
+
+ if (prepare->prepare_cb) {
+ prepare->prepare_cb(prepare, 0);
+ }
+}
+
+
+int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare) {
+ uv__handle_init(loop, (uv_handle_t*)prepare, UV_PREPARE);
+ loop->counters.prepare_init++;
+
+ ev_prepare_init(&prepare->prepare_watcher, uv__prepare);
+ prepare->prepare_cb = NULL;
+
+ return 0;
+}
+
+
+int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb) {
+ int was_active = ev_is_active(&prepare->prepare_watcher);
+
+ prepare->prepare_cb = cb;
+
+ ev_prepare_start(prepare->loop->ev, &prepare->prepare_watcher);
+
+ if (!was_active) {
+ ev_unref(prepare->loop->ev);
+ }
+
+ return 0;
+}
+
+
+int uv_prepare_stop(uv_prepare_t* prepare) {
+ int was_active = ev_is_active(&prepare->prepare_watcher);
+
+ ev_prepare_stop(prepare->loop->ev, &prepare->prepare_watcher);
+
+ if (was_active) {
+ ev_ref(prepare->loop->ev);
+ }
+ return 0;
+}
+
+
+int uv__prepare_active(const uv_prepare_t* handle) {
+ return ev_is_active(&handle->prepare_watcher);
+}
+
+
+void uv__prepare_close(uv_prepare_t* handle) {
+ uv_prepare_stop(handle);
+}
int uv__make_pipe(int fds[2], int flags) {
-#if HAVE_SYS_PIPE2
+#if __linux__
int fl;
fl = O_CLOEXEC;
if (flags & UV__F_NONBLOCK)
fl |= O_NONBLOCK;
- if (sys_pipe2(fds, fl) == 0)
+ if (uv__pipe2(fds, fl) == 0)
return 0;
if (errno != ENOSYS)
return -1;
-
- /* errno == ENOSYS so maybe the kernel headers lied about
- * the availability of pipe2(). This can happen if people
- * build libuv against newer kernel headers than the kernel
- * they actually run the software on.
- */
#endif
if (pipe(fds))
pid_t pid;
int flags;
+ assert(options.file != NULL);
+ assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID)));
+
+
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
loop->counters.process_init++;
_exit(127);
}
+ if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
+ perror("setgid()");
+ _exit(127);
+ }
+
+ if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
+ perror("setuid()");
+ _exit(127);
+ }
+
environ = options.env;
execvp(options.file, options.args);
return uv_ok_;
}
}
+
+
+void uv__process_close(uv_process_t* handle) {
+ ev_child_stop(handle->loop->ev, &handle->child_watcher);
+}
req->cb(req, req->error ? -1 : 0);
}
}
+
+ if (stream->flags & UV_SHUTTING) {
+ uv_shutdown_t* req = stream->shutdown_req;
+ if (req && req->cb) {
+ uv__set_artificial_error(stream->loop, UV_EINTR);
+ req->cb(req, -1);
+ }
+ }
}
fd = uv__accept(stream->fd, (struct sockaddr*)&addr, sizeof addr);
if (fd < 0) {
- if (errno == EAGAIN) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
/* No problem. */
return;
} else if (errno == EMFILE) {
assert(stream->shutdown_req);
req = stream->shutdown_req;
+ stream->shutdown_req = NULL;
if (shutdown(stream->fd, SHUT_WR)) {
/* Error. Report it. User should call uv_close(). */
}
if (n < 0) {
- if (errno != EAGAIN) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
/* Error */
req->error = errno;
stream->write_queue_size -= uv__write_req_size(req);
if (nread < 0) {
/* Error */
- if (errno == EAGAIN) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
/* Wait for the next one. */
if (stream->flags & UV_READING) {
ev_io_start(ev, &stream->read_watcher);
}
/* Initialize request */
- uv__req_init(stream->loop, (uv_req_t*)req);
+ uv__req_init(stream->loop, req, UV_SHUTDOWN);
req->handle = stream;
req->cb = cb;
-
stream->shutdown_req = req;
- req->type = UV_SHUTDOWN;
((uv_handle_t*)stream)->flags |= UV_SHUTTING;
}
}
- uv__req_init(stream->loop, (uv_req_t*)req);
+ uv__req_init(stream->loop, req, UV_CONNECT);
req->cb = cb;
req->handle = stream;
- req->type = UV_CONNECT;
ngx_queue_init(&req->queue);
if (stream->connect_req) {
empty_queue = (stream->write_queue_size == 0);
/* Initialize the req */
- uv__req_init(stream->loop, (uv_req_t*)req);
+ uv__req_init(stream->loop, req, UV_WRITE);
req->cb = cb;
req->handle = stream;
req->error = 0;
req->send_handle = send_handle;
- req->type = UV_WRITE;
ngx_queue_init(&req->queue);
if (bufcnt <= UV_REQ_BUFSML_SIZE) {
}
-int uv_is_readable(uv_stream_t* stream) {
+int uv_is_readable(const uv_stream_t* stream) {
return stream->flags & UV_READABLE;
}
-int uv_is_writable(uv_stream_t* stream) {
+int uv_is_writable(const uv_stream_t* stream) {
return stream->flags & UV_WRITABLE;
}
+
+
+void uv__stream_close(uv_stream_t* handle) {
+ uv_read_stop(handle);
+ ev_io_stop(handle->loop->ev, &handle->write_watcher);
+
+ close(handle->fd);
+ handle->fd = -1;
+
+ if (handle->accepted_fd >= 0) {
+ close(handle->accepted_fd);
+ handle->accepted_fd = -1;
+ }
+
+ assert(!ev_is_active(&handle->read_watcher));
+ assert(!ev_is_active(&handle->write_watcher));
+}
#include <sys/time.h>
#include <unistd.h>
#include <kstat.h>
+#include <fcntl.h>
#if HAVE_PORTS_FS
# include <sys/port.h>
}
-void uv__fs_event_destroy(uv_fs_event_t* handle) {
+void uv__fs_event_close(uv_fs_event_t* handle) {
ev_ref(handle->loop->ev);
ev_io_stop(handle->loop->ev, &handle->event_watcher);
close(handle->fd);
}
-void uv__fs_event_destroy(uv_fs_event_t* handle) {
+void uv__fs_event_close(uv_fs_event_t* handle) {
UNREACHABLE();
}
uv_err_t uv_resident_set_memory(size_t* rss) {
- pid_t pid = getpid();
psinfo_t psinfo;
- char pidpath[1024];
- FILE *f;
+ uv_err_t err;
+ int fd;
- sprintf(pidpath, "/proc/%d/psinfo", (int)pid);
-
- f = fopen(pidpath, "r");
- if (!f) return uv__new_sys_error(errno);
-
- if (fread(&psinfo, sizeof(psinfo_t), 1, f) != 1) {
- fclose (f);
+ fd = open("/proc/self/psinfo", O_RDONLY);
+ if (fd == -1)
return uv__new_sys_error(errno);
- }
- /* XXX correct? */
+ err = uv_ok_;
- *rss = (size_t) psinfo.pr_rssize * 1024;
+ if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo))
+ *rss = (size_t)psinfo.pr_rssize * 1024;
+ else
+ err = uv__new_sys_error(EINVAL);
- fclose (f);
+ close(fd);
- return uv_ok_;
+ return err;
}
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include <assert.h>
+
+
+static int uv__timer_repeating(const uv_timer_t* timer) {
+ return timer->flags & UV_TIMER_REPEAT;
+}
+
+
+static void uv__timer_cb(EV_P_ ev_timer* w, int revents) {
+ uv_timer_t* timer = container_of(w, uv_timer_t, timer_watcher);
+
+ assert(uv__timer_active(timer));
+
+ if (!uv__timer_repeating(timer)) {
+ timer->flags &= ~UV_TIMER_ACTIVE;
+ ev_ref(EV_A);
+ }
+
+ if (timer->timer_cb) {
+ timer->timer_cb(timer, 0);
+ }
+}
+
+
+int uv_timer_init(uv_loop_t* loop, uv_timer_t* timer) {
+ uv__handle_init(loop, (uv_handle_t*)timer, UV_TIMER);
+ loop->counters.timer_init++;
+
+ ev_init(&timer->timer_watcher, uv__timer_cb);
+
+ return 0;
+}
+
+
+int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout,
+ int64_t repeat) {
+ if (uv__timer_active(timer)) {
+ return -1;
+ }
+
+ timer->timer_cb = cb;
+ timer->flags |= UV_TIMER_ACTIVE;
+
+ if (repeat)
+ timer->flags |= UV_TIMER_REPEAT;
+ else
+ timer->flags &= ~UV_TIMER_REPEAT;
+
+ ev_timer_set(&timer->timer_watcher, timeout / 1000.0, repeat / 1000.0);
+ ev_timer_start(timer->loop->ev, &timer->timer_watcher);
+ ev_unref(timer->loop->ev);
+
+ return 0;
+}
+
+
+int uv_timer_stop(uv_timer_t* timer) {
+ if (uv__timer_active(timer)) {
+ ev_ref(timer->loop->ev);
+ }
+
+ timer->flags &= ~(UV_TIMER_ACTIVE | UV_TIMER_REPEAT);
+ ev_timer_stop(timer->loop->ev, &timer->timer_watcher);
+
+ return 0;
+}
+
+
+int uv_timer_again(uv_timer_t* timer) {
+ if (!uv__timer_active(timer)) {
+ uv__set_artificial_error(timer->loop, UV_EINVAL);
+ return -1;
+ }
+
+ assert(uv__timer_repeating(timer));
+ ev_timer_again(timer->loop->ev, &timer->timer_watcher);
+ return 0;
+}
+
+
+void uv_timer_set_repeat(uv_timer_t* timer, int64_t repeat) {
+ assert(timer->type == UV_TIMER);
+ timer->timer_watcher.repeat = repeat / 1000.0;
+
+ if (repeat)
+ timer->flags |= UV_TIMER_REPEAT;
+ else
+ timer->flags &= ~UV_TIMER_REPEAT;
+}
+
+
+int64_t uv_timer_get_repeat(uv_timer_t* timer) {
+ assert(timer->type == UV_TIMER);
+ return (int64_t)(1000 * timer->timer_watcher.repeat);
+}
+
+
+int uv__timer_active(const uv_timer_t* timer) {
+ return timer->flags & UV_TIMER_ACTIVE;
+}
+
+
+void uv__timer_close(uv_timer_t* handle) {
+ uv_timer_stop(handle);
+}
}
-void uv__udp_start_close(uv_udp_t* handle) {
+void uv__udp_close(uv_udp_t* handle) {
uv__udp_stop_write_watcher(handle);
uv__udp_stop_read_watcher(handle);
close(handle->fd);
if (uv__udp_maybe_deferred_bind(handle, addr->sa_family))
return -1;
- uv__req_init(handle->loop, (uv_req_t*)req);
+ uv__req_init(handle->loop, req, UV_UDP_SEND);
memcpy(&req->addr, addr, addrlen);
req->addrlen = addrlen;
req->send_cb = send_cb;
req->handle = handle;
req->bufcnt = bufcnt;
- req->type = UV_UDP_SEND;
if (bufcnt <= UV_REQ_BUFSML_SIZE) {
req->bufs = req->bufsml;
}
-#define X(name, level, option) \
- int uv_udp_set_##name(uv_udp_t* handle, int flag) { \
- if (setsockopt(handle->fd, level, option, &flag, sizeof(flag))) { \
- uv__set_sys_error(handle->loop, errno); \
- return -1; \
- } \
- return 0; \
- }
-
-X(broadcast, SOL_SOCKET, SO_BROADCAST)
-X(ttl, IPPROTO_IP, IP_TTL)
-
-#undef X
-
-
static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) {
#if __sun
char arg = val;
int arg = val;
#endif
-#if __sun
- if (val < 0 || val > 255) {
- uv__set_sys_error(handle->loop, EINVAL);
- return -1;
- }
-#endif
+ if (val < 0 || val > 255)
+ return uv__set_sys_error(handle->loop, EINVAL);
- if (setsockopt(handle->fd, IPPROTO_IP, option, &arg, sizeof(arg))) {
- uv__set_sys_error(handle->loop, errno);
- return -1;
- }
+ if (setsockopt(handle->fd, IPPROTO_IP, option, &arg, sizeof(arg)))
+ return uv__set_sys_error(handle->loop, errno);
+
+ return 0;
+}
+
+
+int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
+ if (setsockopt(handle->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)))
+ return uv__set_sys_error(handle->loop, errno);
+
+ return 0;
+}
+
+
+int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
+ if (ttl < 1 || ttl > 255)
+ return uv__set_sys_error(handle->loop, EINVAL);
+
+ if (setsockopt(handle->fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)))
+ return uv__set_sys_error(handle->loop, errno);
return 0;
}
#include "ares/inet_net_pton.h"
#include "ares/inet_ntop.h"
+#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
+
+size_t uv_handle_size(uv_handle_type type) {
+ switch (type) {
+ UV_HANDLE_TYPE_MAP(XX)
+ default:
+ return -1;
+ }
+}
+
+size_t uv_req_size(uv_req_type type) {
+ switch(type) {
+ UV_REQ_TYPE_MAP(XX)
+ default:
+ return -1;
+ }
+}
+
+#undef XX
size_t uv_strlcpy(char* dst, const char* src, size_t size) {
size_t n;
struct uv_ares_task_s {
UV_HANDLE_FIELDS
- UV_ARES_TASK_PRIVATE_FIELDS
+#if _WIN32
+ struct uv_req_s ares_req;
+ SOCKET sock;
+ HANDLE h_wait;
+ WSAEVENT h_event;
+ HANDLE h_close_event;
+#else
+ int sock;
+ ev_io read_watcher;
+ ev_io write_watcher;
+#endif
RB_ENTRY(uv_ares_task_s) node;
};
assert(req->type == UV_WAKEUP);
handle->async_sent = 0;
- if (handle->async_cb) {
+
+ if (!(handle->flags & UV_HANDLE_CLOSING)) {
handle->async_cb((uv_async_t*) handle, 0);
- }
- if (handle->flags & UV_HANDLE_CLOSING) {
+ } else {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
}
loop->active_udp_streams = 0;
loop->last_err = uv_ok_;
+
+ memset(&loop->counters, 0, sizeof loop->counters);
}
return uv__new_sys_error(saved_errno);
}
- handle = LoadLibraryW(filename_w);
+ handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (handle == NULL) {
saved_errno = GetLastError();
return uv__new_sys_error(saved_errno);
switch (sys_errno) {
case ERROR_SUCCESS: return UV_OK;
case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
+ case ERROR_INVALID_NAME: return UV_ENOENT;
+ case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
case ERROR_ACCESS_DENIED: return UV_EPERM;
case ERROR_NOACCESS: return UV_EACCES;
case ERROR_EA_TABLE_FULL: return UV_ENOSPC;
case ERROR_END_OF_MEDIA: return UV_ENOSPC;
case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC;
+ case ERROR_WRITE_PROTECT: return UV_EROFS;
case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
case WSAENOTCONN: return UV_ENOTCONN;
case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY;
#include "internal.h"
#define UV_FS_ASYNC_QUEUED 0x0001
-#define UV_FS_FREE_ARG0 0x0002
-#define UV_FS_FREE_ARG1 0x0004
+#define UV_FS_FREE_PATH 0x0002
+#define UV_FS_FREE_NEW_PATH 0x0004
#define UV_FS_FREE_PTR 0x0008
#define UV_FS_CLEANEDUP 0x0010
return -1; \
}
-#define STRDUP_ARG(req, i) \
- req->arg##i = (void*)strdup((const char*)req->arg##i); \
- if (!req->arg##i) { \
- uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); \
- } \
- req->flags |= UV_FS_FREE_ARG##i;
-
-#define SET_ALLOCED_ARG(req, i) \
- req->flags |= UV_FS_FREE_ARG##i;
-
-#define WRAP_REQ_ARGS1(req, a0) \
- req->arg0 = (void*)a0;
-
-#define WRAP_REQ_ARGS2(req, a0, a1) \
- WRAP_REQ_ARGS1(req, a0) \
- req->arg1 = (void*)a1;
-
-#define WRAP_REQ_ARGS3(req, a0, a1, a2) \
- WRAP_REQ_ARGS2(req, a0, a1) \
- req->arg2 = (void*)a2;
-
-#define WRAP_REQ_ARGS4(req, a0, a1, a2, a3) \
- WRAP_REQ_ARGS3(req, a0, a1, a2) \
- req->arg3 = (void*)a3;
-
#define QUEUE_FS_TP_JOB(loop, req) \
if (!QueueUserWorkItem(&uv_fs_thread_proc, \
req, \
void fs__read(uv_fs_t* req, uv_file file, void *buf, size_t length,
- off_t offset) {
+ int64_t offset) {
HANDLE handle;
OVERLAPPED overlapped, *overlapped_ptr;
LARGE_INTEGER offset_;
void fs__write(uv_fs_t* req, uv_file file, void *buf, size_t length,
- off_t offset) {
+ int64_t offset) {
HANDLE handle;
OVERLAPPED overlapped, *overlapped_ptr;
LARGE_INTEGER offset_;
}
-void fs__ftruncate(uv_fs_t* req, uv_file file, off_t offset) {
+void fs__ftruncate(uv_fs_t* req, uv_file file, int64_t offset) {
int result;
VERIFY_UV_FILE(file, req);
- result = _chsize(file, offset);
+ result = _chsize_s(file, offset);
SET_REQ_RESULT(req, result);
}
void fs__sendfile(uv_fs_t* req, uv_file out_file, uv_file in_file,
- off_t in_offset, size_t length) {
+ int64_t in_offset, size_t length) {
const size_t max_buf_size = 65536;
size_t buf_size = length < max_buf_size ? length : max_buf_size;
int n, result = 0;
+ int64_t result_offset = 0;
char* buf = (char*)malloc(buf_size);
if (!buf) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
if (in_offset != -1) {
- result = _lseek(in_file, in_offset, SEEK_SET);
+ result_offset = _lseeki64(in_file, in_offset, SEEK_SET);
}
- if (result != -1) {
+ if (result_offset == -1) {
+ result = -1;
+ } else {
while (length > 0) {
n = _read(in_file, buf, length < buf_size ? length : buf_size);
if (n == 0) {
switch (req->fs_type) {
case UV_FS_OPEN:
- fs__open(req, req->pathw, (int)req->arg0, (int)req->arg1);
+ fs__open(req, req->pathw, req->file_flags, (int)req->mode);
break;
case UV_FS_CLOSE:
- fs__close(req, (uv_file)req->arg0);
+ fs__close(req, req->file);
break;
case UV_FS_READ:
- fs__read(req,
- (uv_file) req->arg0,
- req->arg1,
- (size_t) req->arg2,
- (off_t) req->arg3);
+ fs__read(req, req->file, req->buf, req->length, req->offset);
break;
case UV_FS_WRITE:
- fs__write(req,
- (uv_file)req->arg0,
- req->arg1,
- (size_t) req->arg2,
- (off_t) req->arg3);
+ fs__write(req, req->file, req->buf, req->length, req->offset);
break;
case UV_FS_UNLINK:
fs__unlink(req, req->pathw);
break;
case UV_FS_MKDIR:
- fs__mkdir(req, req->pathw, (int)req->arg0);
+ fs__mkdir(req, req->pathw, req->mode);
break;
case UV_FS_RMDIR:
fs__rmdir(req, req->pathw);
break;
case UV_FS_READDIR:
- fs__readdir(req, req->pathw, (int)req->arg0);
+ fs__readdir(req, req->pathw, req->file_flags);
break;
case UV_FS_STAT:
case UV_FS_LSTAT:
fs__stat(req, req->pathw);
break;
case UV_FS_FSTAT:
- fs__fstat(req, (uv_file)req->arg0);
+ fs__fstat(req, req->file);
break;
case UV_FS_RENAME:
- fs__rename(req, req->pathw, (const wchar_t*)req->arg0);
+ fs__rename(req, req->pathw, req->new_pathw);
break;
case UV_FS_FSYNC:
case UV_FS_FDATASYNC:
- fs__fsync(req, (uv_file)req->arg0);
+ fs__fsync(req, req->file);
break;
case UV_FS_FTRUNCATE:
- fs__ftruncate(req, (uv_file)req->arg0, (off_t)req->arg1);
+ fs__ftruncate(req, req->file, req->offset);
break;
case UV_FS_SENDFILE:
- fs__sendfile(req,
- (uv_file) req->arg0,
- (uv_file) req->arg1,
- (off_t) req->arg2,
- (size_t) req->arg3);
+ fs__sendfile(req, req->file_out, req->file, req->offset, req->length);
break;
case UV_FS_CHMOD:
- fs__chmod(req, req->pathw, (int)req->arg0);
+ fs__chmod(req, req->pathw, req->mode);
break;
case UV_FS_FCHMOD:
- fs__fchmod(req, (uv_file)req->arg0, (int)req->arg1);
+ fs__fchmod(req, req->file, req->mode);
break;
case UV_FS_UTIME:
- fs__utime(req, req->pathw, req->arg4, req->arg5);
+ fs__utime(req, req->pathw, req->atime, req->mtime);
break;
case UV_FS_FUTIME:
- fs__futime(req, (uv_file)req->arg0, req->arg4, req->arg5);
+ fs__futime(req, req->file, req->atime, req->mtime);
break;
case UV_FS_LINK:
- fs__link(req, req->pathw, (const wchar_t*)req->arg0);
+ fs__link(req, req->pathw, req->new_pathw);
break;
case UV_FS_SYMLINK:
- fs__symlink(req, req->pathw, (const wchar_t*)req->arg0, (int)req->arg1);
+ fs__symlink(req, req->pathw, req->new_pathw, req->file_flags);
break;
case UV_FS_READLINK:
fs__readlink(req, req->pathw);
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_OPEN, path, pathw, cb);
- WRAP_REQ_ARGS2(req, flags, mode);
+ req->file_flags = flags;
+ req->mode = mode;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_OPEN);
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_CLOSE, NULL, NULL, cb);
- WRAP_REQ_ARGS1(req, file);
+ req->file = file;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_CLOSE);
int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
- size_t length, off_t offset, uv_fs_cb cb) {
+ size_t length, int64_t offset, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_READ, NULL, NULL, cb);
- WRAP_REQ_ARGS4(req, file, buf, length, offset);
+ req->file = file;
+ req->buf = buf;
+ req->length = length;
+ req->offset = offset;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_READ);
int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
- size_t length, off_t offset, uv_fs_cb cb) {
+ size_t length, int64_t offset, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_WRITE, NULL, NULL, cb);
- WRAP_REQ_ARGS4(req, file, buf, length, offset);
+ req->file = file;
+ req->buf = buf;
+ req->length = length;
+ req->offset = offset;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_WRITE);
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_MKDIR, path, pathw, cb);
- WRAP_REQ_ARGS1(req, mode);
+ req->mode = mode;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_MKDIR);
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_READDIR, path, pathw, cb);
- WRAP_REQ_ARGS1(req, flags);
+ req->file_flags = flags;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_READDIR);
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_LINK, path, pathw, cb);
- WRAP_REQ_ARGS1(req, new_pathw);
- SET_ALLOCED_ARG(req, 0);
+ req->new_pathw = new_pathw;
+ req->flags |= UV_FS_FREE_NEW_PATH;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_LINK);
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_SYMLINK, path, pathw, cb);
- WRAP_REQ_ARGS2(req, new_pathw, flags);
- SET_ALLOCED_ARG(req, 0);
+ req->new_pathw = new_pathw;
+ req->flags |= UV_FS_FREE_NEW_PATH;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_SYMLINK);
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_CHOWN, path, pathw, cb);
- WRAP_REQ_ARGS2(req, uid, gid);
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_CHOWN);
int gid, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_FCHOWN, NULL, NULL, cb);
- WRAP_REQ_ARGS3(req, file, uid, gid);
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FCHOWN);
int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_FSTAT, NULL, NULL, cb);
- WRAP_REQ_ARGS1(req, file);
+ req->file = file;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FSTAT);
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_RENAME, path, pathw, cb);
- WRAP_REQ_ARGS1(req, new_pathw);
- SET_ALLOCED_ARG(req, 0);
+ req->new_pathw = new_pathw;
+ req->flags |= UV_FS_FREE_NEW_PATH;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_RENAME);
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_FDATASYNC, NULL, NULL, cb);
- WRAP_REQ_ARGS1(req, file);
+ req->file = file;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FDATASYNC);
int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_FSYNC, NULL, NULL, cb);
- WRAP_REQ_ARGS1(req, file);
+ req->file = file;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FSYNC);
int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file,
- off_t offset, uv_fs_cb cb) {
+ int64_t offset, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_FTRUNCATE, NULL, NULL, cb);
- WRAP_REQ_ARGS2(req, file, offset);
+ req->file = file;
+ req->offset = offset;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FTRUNCATE);
int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd,
- uv_file in_fd, off_t in_offset, size_t length, uv_fs_cb cb) {
+ uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_SENDFILE, NULL, NULL, cb);
- WRAP_REQ_ARGS4(req, out_fd, in_fd, in_offset, length);
+ req->file_out = out_fd;
+ req->file = in_fd;
+ req->offset = in_offset;
+ req->length = length;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_SENDFILE);
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_CHMOD, path, pathw, cb);
- WRAP_REQ_ARGS1(req, mode);
+ req->mode = mode;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_CHMOD);
uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_FCHMOD, NULL, NULL, cb);
- WRAP_REQ_ARGS2(req, file, mode);
+ req->file = file;
+ req->mode = mode;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FCHMOD);
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_UTIME, path, pathw, cb);
- req->arg4 = (ssize_t)atime;
- req->arg5 = (ssize_t)mtime;
+ req->atime = atime;
+ req->mtime = mtime;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_UTIME);
double mtime, uv_fs_cb cb) {
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_FUTIME, NULL, NULL, cb);
- WRAP_REQ_ARGS1(req, file);
- req->arg4 = (ssize_t)atime;
- req->arg5 = (ssize_t)mtime;
+ req->file = file;
+ req->atime = atime;
+ req->mtime = mtime;
QUEUE_FS_TP_JOB(loop, req);
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FUTIME);
return;
}
- if (req->flags & UV_FS_FREE_ARG0 && req->arg0) {
- free(req->arg0);
- req->arg0 = NULL;
+ if (req->flags & UV_FS_FREE_PATH && req->pathw) {
+ free(req->pathw);
+ req->pathw = NULL;
}
- if (req->flags & UV_FS_FREE_ARG1 && req->arg1) {
- free(req->arg1);
- req->arg1 = NULL;
+ if (req->flags & UV_FS_FREE_NEW_PATH && req->new_pathw) {
+ free(req->new_pathw);
+ req->new_pathw = NULL;
}
if (req->flags & UV_FS_FREE_PTR && req->ptr) {
req->path = NULL;
}
- if (req->pathw) {
- free(req->pathw);
- req->pathw = NULL;
- }
-
if (req->flags & UV_FS_ASYNC_QUEUED) {
uv_unref(loop);
}
}
-int uv_is_active(uv_handle_t* handle) {
+int uv_is_active(const uv_handle_t* handle) {
switch (handle->type) {
case UV_TIMER:
case UV_IDLE:
}
+int uv_is_closing(const uv_handle_t* handle) {
+ return handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED);
+}
+
+
void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
LPWSAPROTOCOL_INFOW protocol_info);
+void uv_tcp_close(uv_tcp_t* tcp);
+
/*
* UDP
/*
* FS Event
*/
-void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle);
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle);
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
char* name, size_t nameSize) {
HANDLE pipeHandle;
- int errno;
+ int errorno;
int err;
char* ptr = (char*)handle;
break;
}
- errno = GetLastError();
- if (errno != ERROR_PIPE_BUSY && errno != ERROR_ACCESS_DENIED) {
- uv__set_sys_error(loop, errno);
+ errorno = GetLastError();
+ if (errorno != ERROR_PIPE_BUSY && errorno != ERROR_ACCESS_DENIED) {
+ uv__set_sys_error(loop, errorno);
err = -1;
goto done;
}
static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
- int errno;
uv_loop_t* loop;
uv_pipe_t* handle;
uv_shutdown_t* req;
/* Creates a pipe server. */
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
uv_loop_t* loop = handle->loop;
- int i, errno, nameSize;
+ int i, errorno, nameSize;
uv_pipe_accept_t* req;
if (handle->flags & UV_HANDLE_BOUND) {
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
if (handle->accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
- errno = GetLastError();
- if (errno == ERROR_ACCESS_DENIED) {
- uv__set_error(loop, UV_EADDRINUSE, errno);
- } else if (errno == ERROR_PATH_NOT_FOUND || errno == ERROR_INVALID_NAME) {
- uv__set_error(loop, UV_EACCES, errno);
+ errorno = GetLastError();
+ if (errorno == ERROR_ACCESS_DENIED) {
+ uv__set_error(loop, UV_EADDRINUSE, errorno);
+ } else if (errorno == ERROR_PATH_NOT_FOUND || errorno == ERROR_INVALID_NAME) {
+ uv__set_error(loop, UV_EACCES, errorno);
} else {
- uv__set_sys_error(loop, errno);
+ uv__set_sys_error(loop, errorno);
}
goto error;
}
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
- int errno;
uv_loop_t* loop;
uv_pipe_t* handle;
uv_connect_t* req;
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
const char* name, uv_connect_cb cb) {
uv_loop_t* loop = handle->loop;
- int errno, nameSize;
+ int errorno, nameSize;
HANDLE pipeHandle = INVALID_HANDLE_VALUE;
DWORD duplex_flags;
}
if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(wchar_t))) {
- errno = GetLastError();
+ errorno = GetLastError();
goto error;
}
if (!QueueUserWorkItem(&pipe_connect_thread_proc,
req,
WT_EXECUTELONGFUNCTION)) {
- errno = GetLastError();
+ errorno = GetLastError();
goto error;
}
return;
}
- errno = GetLastError();
+ errorno = GetLastError();
goto error;
}
(uv_pipe_t*) req->handle,
pipeHandle,
duplex_flags)) {
- errno = GetLastError();
+ errorno = GetLastError();
goto error;
}
}
/* Make this req pending reporting an error. */
- SET_REQ_ERROR(req, errno);
+ SET_REQ_ERROR(req, errorno);
uv_insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
uv_ref(loop);
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
uv_loop_t* loop = handle->loop;
- int i, errno;
+ int i;
if (!(handle->flags & UV_HANDLE_BOUND)) {
uv__set_artificial_error(loop, UV_EINVAL);
STARTUPINFOW startup;
PROCESS_INFORMATION info;
- if (!options.file) {
- uv__set_artificial_error(loop, UV_EINVAL);
+ if (options.flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
+ uv__set_artificial_error(loop, UV_ENOTSUP);
return -1;
}
+ assert(options.file != NULL);
+ assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID)));
+
uv_process_init(loop, process);
process->exit_cb = options.exit_cb;
UTF8_TO_UTF16(options.file, application);
arguments = options.args ? make_program_args(options.args,
- options.windows_verbatim_arguments) : NULL;
+ options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS) : NULL;
env = options.env ? make_program_env(options.env) : NULL;
if (options.cwd) {
}
-int uv_is_readable(uv_stream_t* handle) {
+int uv_is_readable(const uv_stream_t* handle) {
return !(handle->flags & UV_HANDLE_EOF);
}
-int uv_is_writable(uv_stream_t* handle) {
+int uv_is_writable(const uv_stream_t* handle) {
return !(handle->flags & UV_HANDLE_SHUTTING);
}
int addrsize) {
DWORD err;
int r;
- SOCKET sock;
if (handle->socket == INVALID_SOCKET) {
- sock = socket(domain, SOCK_STREAM, 0);
+ SOCKET sock = socket(domain, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
uv__set_sys_error(handle->loop, WSAGetLastError());
return -1;
int addrsize,
unsigned int flags) {
int r;
- SOCKET sock;
DWORD no = 0, yes = 1;
if ((flags & UV_UDP_IPV6ONLY) && domain != AF_INET6) {
}
if (handle->socket == INVALID_SOCKET) {
- sock = socket(domain, SOCK_DGRAM, 0);
+ SOCKET sock = socket(domain, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) {
uv__set_sys_error(handle->loop, WSAGetLastError());
return -1;
/* TODO: how to handle errors? This may fail if there is no ipv4 stack */
/* available, or when run on XP/2003 which have no support for dualstack */
/* sockets. For now we're silently ignoring the error. */
- setsockopt(sock,
+ setsockopt(handle->socket,
IPPROTO_IPV6,
IPV6_V6ONLY,
(char*) &no,
sizeof no);
}
- r = setsockopt(sock,
+ r = setsockopt(handle->socket,
SOL_SOCKET,
SO_REUSEADDR,
(char*) &yes,
}
-#define SOCKOPT_SETTER(name, option4, option6) \
+#define SOCKOPT_SETTER(name, option4, option6, validate) \
int uv_udp_set_##name(uv_udp_t* handle, int value) { \
DWORD optval = (DWORD) value; \
\
+ if (!(validate(value))) { \
+ uv__set_artificial_error(handle->loop, UV_EINVAL); \
+ return -1; \
+ } \
+ \
/* If the socket is unbound, bind to inaddr_any. */ \
if (!(handle->flags & UV_HANDLE_BOUND) && \
uv_udp_bind(handle, uv_addr_ip4_any_, 0) < 0) { \
return 0; \
}
-SOCKOPT_SETTER(multicast_loop, IP_MULTICAST_LOOP, IPV6_MULTICAST_LOOP)
-SOCKOPT_SETTER(multicast_ttl, IP_MULTICAST_TTL, IPV6_MULTICAST_HOPS)
-SOCKOPT_SETTER(ttl, IP_TTL, IPV6_HOPLIMIT)
+#define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255)
+#define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255)
+#define VALIDATE_MULTICAST_LOOP(value) (1)
+
+SOCKOPT_SETTER(ttl,
+ IP_TTL,
+ IPV6_HOPLIMIT,
+ VALIDATE_TTL)
+SOCKOPT_SETTER(multicast_ttl,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ VALIDATE_MULTICAST_TTL)
+SOCKOPT_SETTER(multicast_loop,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ VALIDATE_MULTICAST_LOOP)
#undef SOCKOPT_SETTER
+#undef VALIDATE_TTL
+#undef VALIDATE_MULTICAST_TTL
+#undef VALIDATE_MULTICAST_LOOP
#include <stdio.h>
#include <string.h>
#include <time.h>
+#include <wchar.h>
#include "uv.h"
#include "internal.h"
if (!process_title && uv__get_process_title() == -1) {
return uv__new_sys_error(GetLastError());
}
-
+
assert(process_title);
- strncpy(buffer, process_title, size);
+ strncpy(buffer, process_title, size);
LeaveCriticalSection(&process_title_lock);
return uv_ok_;
uv_err_t uv_uptime(double* uptime) {
- *uptime = (double)GetTickCount()/1000.0;
- return uv_ok_;
+ BYTE stack_buffer[4096];
+ BYTE* malloced_buffer = NULL;
+ BYTE* buffer = (BYTE*) stack_buffer;
+ size_t buffer_size = sizeof(stack_buffer);
+ DWORD data_size;
+
+ PERF_DATA_BLOCK* data_block;
+ PERF_OBJECT_TYPE* object_type;
+ PERF_COUNTER_DEFINITION* counter_definition;
+
+ DWORD i;
+
+ for (;;) {
+ LONG result;
+
+ data_size = (DWORD) buffer_size;
+ result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
+ L"2",
+ NULL,
+ NULL,
+ buffer,
+ &data_size);
+ if (result == ERROR_SUCCESS) {
+ break;
+ } else if (result != ERROR_MORE_DATA) {
+ *uptime = 0;
+ return uv__new_sys_error(result);
+ }
+
+ free(malloced_buffer);
+
+ buffer_size *= 2;
+ /* Don't let the buffer grow infinitely. */
+ if (buffer_size > 1 << 20) {
+ goto internalError;
+ }
+
+ buffer = malloced_buffer = (BYTE*) malloc(buffer_size);
+ if (malloced_buffer == NULL) {
+ *uptime = 0;
+ return uv__new_artificial_error(UV_ENOMEM);
+ }
+ }
+
+ if (data_size < sizeof(*data_block))
+ goto internalError;
+
+ data_block = (PERF_DATA_BLOCK*) buffer;
+
+ if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
+ goto internalError;
+
+ if (data_size < data_block->HeaderLength + sizeof(*object_type))
+ goto internalError;
+
+ object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
+
+ if (object_type->NumInstances != PERF_NO_INSTANCES)
+ goto internalError;
+
+ counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
+ data_block->HeaderLength + object_type->HeaderLength);
+ for (i = 0; i < object_type->NumCounters; i++) {
+ if ((BYTE*) counter_definition + sizeof(*counter_definition) >
+ buffer + data_size) {
+ break;
+ }
+
+ if (counter_definition->CounterNameTitleIndex == 674 &&
+ counter_definition->CounterSize == sizeof(uint64_t)) {
+ if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
+ !(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
+ goto internalError;
+ } else {
+ BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
+ counter_definition->CounterOffset;
+ uint64_t value = *((uint64_t*) address);
+ *uptime = (double) (object_type->PerfTime.QuadPart - value) /
+ (double) object_type->PerfFreq.QuadPart;
+ free(malloced_buffer);
+ return uv_ok_;
+ }
+ }
+
+ counter_definition = (PERF_COUNTER_DEFINITION*)
+ ((BYTE*) counter_definition + counter_definition->ByteLength);
+ }
+
+ /* If we get here, the uptime value was not found. */
+ free(malloced_buffer);
+ *uptime = 0;
+ return uv__new_artificial_error(UV_ENOSYS);
+
+ internalError:
+ free(malloced_buffer);
+ *uptime = 0;
+ return uv__new_artificial_error(UV_EIO);
}
*count = 0;
- for (i = 0; i < system_info.dwNumberOfProcessors; i++) {
+ for (i = 0; i < system_info.dwNumberOfProcessors; i++) {
_snprintf(key, sizeof(key), "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE,
RegCloseKey(processor_key);
processor_key = NULL;
-
+
cpu_info = &(*cpu_infos)[i];
/* $TODO: find times on windows */
}
}
}
-
+
assert(name);
address->name = name;
(FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_WARNING)))
/* from ntifs.h */
-/* MinGW already has it */
-#if defined(_MSC_VER) || defined(__MINGW64__)
+/* MinGW already has it, mingw-w64 does not. */
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
USHORT ReparseDataLength;
# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
#endif
-#ifdef __MINGW32__
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
typedef struct _OVERLAPPED_ENTRY {
ULONG_PTR lpCompletionKey;
LPOVERLAPPED lpOverlapped;
#define IOCTL_AFD_RECEIVE_DATAGRAM \
_AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER)
-#if defined(__MINGW32__) && !defined(__MINGW64__)
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP {
/* FIXME: __C89_NAMELESS was removed */
static int pipe_echo_start(char* pipeName) {
int r;
+#ifndef _WIN32
+ {
+ uv_fs_t req;
+ uv_fs_unlink(uv_default_loop(), &req, pipeName, NULL);
+ uv_fs_req_cleanup(&req);
+ }
+#endif
+
server = (uv_handle_t*)&pipeServer;
serverType = PIPE;
static void* dowait(void* data) {
dowait_args* args = data;
- int i, status, r;
+ int i, r;
process_info_t* p;
for (i = 0; i < args->n; i++) {
p = (process_info_t*)(args->vec + i * sizeof(process_info_t));
if (p->terminated) continue;
- status = 0;
r = waitpid(p->pid, &p->status, 0);
if (r < 0) {
perror("waitpid");
}
-typedef void* (*uv_thread_cb)(void* arg);
-
-
-uintptr_t uv_create_thread(void (*entry)(void* arg), void* arg) {
- pthread_t t;
- uv_thread_cb cb = (uv_thread_cb)entry;
- int r = pthread_create(&t, NULL, cb, arg);
-
- if (r) {
- return 0;
- }
-
- return (uintptr_t)t;
-}
-
-
-/* Wait for a thread to terminate. Should return 0 if the thread ended, -1 on
- * error.
- */
-int uv_wait_thread(uintptr_t thread_id) {
- return pthread_join((pthread_t)thread_id, NULL);
-}
-
-
/* Pause the calling thread for a number of milliseconds. */
void uv_sleep(int msec) {
usleep(msec * 1000);
}
-typedef struct {
- void (*entry)(void* arg);
- void* arg;
-} thread_info_t;
-
-
-static unsigned __stdcall create_thread_helper(void* info) {
- /* Copy thread info locally, then free it */
- void (*entry)(void* arg) = ((thread_info_t*) info)->entry;
- void* arg = ((thread_info_t*) info)->arg;
-
- free(info);
-
- /* Run the actual thread proc */
- entry(arg);
-
- /* Finalize */
- _endthreadex(0);
- return 0;
-}
-
-
-/* Create a thread. Returns the thread identifier, or 0 on failure. */
-uintptr_t uv_create_thread(void (*entry)(void* arg), void* arg) {
- uintptr_t result;
- thread_info_t* info;
-
- info = (thread_info_t*) malloc(sizeof *info);
- if (info == NULL) {
- return 0;
- }
-
- info->entry = entry;
- info->arg = arg;
-
- result = _beginthreadex(NULL,
- 0,
- &create_thread_helper,
- (void*) info,
- 0,
- NULL);
-
- if (result == 0) {
- free(info);
- return 0;
- }
-
- return result;
-}
-
-
-/* Wait for a thread to terminate. Should return 0 if the thread ended, -1 on
- * error.
- */
-int uv_wait_thread(uintptr_t thread_id) {
- if (WaitForSingleObject((HANDLE)thread_id, INFINITE) != WAIT_OBJECT_0) {
- return -1;
- }
-
- return 0;
-}
-
-
/* Pause the calling thread for a number of milliseconds. */
void uv_sleep(int msec) {
Sleep(msec);
int run_helper_##name()
-/* Create a thread. Returns the thread identifier, or 0 on failure. */
-uintptr_t uv_create_thread(void (*entry)(void* arg), void* arg);
-
-/* Wait for a thread to terminate. Should return 0 if the thread ended, -1 on
- * error.
- */
-int uv_wait_thread(uintptr_t thread_id);
-
/* Pause the calling thread for a number of milliseconds. */
void uv_sleep(int msec);
#include <stdio.h>
#include <stdlib.h>
+static uv_thread_t thread;
+static uv_mutex_t mutex;
-static uv_prepare_t prepare_handle;
+static uv_prepare_t prepare;
+static uv_async_t async;
-static uv_async_t async1_handle;
-/* static uv_handle_t async2_handle; */
+static volatile int async_cb_called;
+static int prepare_cb_called;
+static int close_cb_called;
-static int prepare_cb_called = 0;
-static volatile int async1_cb_called = 0;
-static int async1_closed = 0;
-/* static volatile int async2_cb_called = 0; */
-
-static int close_cb_called = 0;
-
-static uintptr_t thread1_id = 0;
-#if 0
-static uintptr_t thread2_id = 0;
-static uintptr_t thread3_id = 0;
-#endif
-
-
-/* Thread 1 makes sure that async1_cb_called reaches 3 before exiting. */
-void thread1_entry(void *arg) {
- uv_sleep(50);
-
- while (1) {
- switch (async1_cb_called) {
- case 0:
- uv_async_send(&async1_handle);
- break;
-
- case 1:
- uv_async_send(&async1_handle);
- break;
-
- case 2:
- uv_async_send(&async1_handle);
- break;
-
- default:
- return;
- }
- }
-}
-
-#if 0
-/* Thread 2 calls uv_async_send on async_handle_2 8 times. */
-void thread2_entry(void *arg) {
- int i;
-
- while (1) {
- switch (async1_cb_called) {
- case 0:
- uv_async_send(&async2_handle);
- break;
+void thread_cb(void *arg) {
+ int n;
+ int r;
- case 1:
- uv_async_send(&async2_handle);
- break;
+ for (;;) {
+ uv_mutex_lock(&mutex);
+ n = async_cb_called;
+ uv_mutex_unlock(&mutex);
- case 2:
- uv_async_send(&async2_handle);
- break;
+ if (n == 3) {
+ break;
}
- uv_sleep(5);
- }
- if (async1_cb_called == 20) {
- uv_close(handle);
+ r = uv_async_send(&async);
+ ASSERT(r == 0);
}
}
-/* Thread 3 calls uv_async_send on async_handle_2 8 times
- * after waiting half a second first.
- */
-void thread3_entry(void *arg) {
- int i;
-
- for (i = 0; i < 8; i++) {
- uv_async_send(&async2_handle);
- }
-}
-#endif
-
-
static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
close_cb_called++;
}
-static void async1_cb(uv_async_t* handle, int status) {
- ASSERT(handle == &async1_handle);
- ASSERT(status == 0);
-
- async1_cb_called++;
- printf("async1_cb #%d\n", async1_cb_called);
-
- if (async1_cb_called > 2 && !async1_closed) {
- async1_closed = 1;
- uv_close((uv_handle_t*)handle, close_cb);
- }
-}
-
+static void async_cb(uv_async_t* handle, int status) {
+ int n;
-#if 0
-static void async2_cb(uv_handle_t* handle, int status) {
- ASSERT(handle == &async2_handle);
+ ASSERT(handle == &async);
ASSERT(status == 0);
- async2_cb_called++;
- printf("async2_cb #%d\n", async2_cb_called);
+ uv_mutex_lock(&mutex);
+ n = ++async_cb_called;
+ uv_mutex_unlock(&mutex);
- if (async2_cb_called == 16) {
- uv_close(handle);
+ if (n == 3) {
+ uv_close((uv_handle_t*)&async, close_cb);
+ uv_close((uv_handle_t*)&prepare, close_cb);
}
}
-#endif
static void prepare_cb(uv_prepare_t* handle, int status) {
- ASSERT(handle == &prepare_handle);
- ASSERT(status == 0);
-
- switch (prepare_cb_called) {
- case 0:
- thread1_id = uv_create_thread(thread1_entry, NULL);
- ASSERT(thread1_id != 0);
- break;
-
-#if 0
- case 1:
- thread2_id = uv_create_thread(thread2_entry, NULL);
- ASSERT(thread2_id != 0);
- break;
-
- case 2:
- thread3_id = uv_create_thread(thread3_entry, NULL);
- ASSERT(thread3_id != 0);
- break;
-#endif
+ int r;
- case 1:
- uv_close((uv_handle_t*)handle, close_cb);
- break;
+ ASSERT(handle == &prepare);
+ ASSERT(status == 0);
- default:
- FATAL("Should never get here");
- }
+ if (prepare_cb_called++)
+ return;
- prepare_cb_called++;
+ r = uv_thread_create(&thread, thread_cb, NULL);
+ ASSERT(r == 0);
+ uv_mutex_unlock(&mutex);
}
TEST_IMPL(async) {
int r;
- r = uv_prepare_init(uv_default_loop(), &prepare_handle);
- ASSERT(r == 0);
- r = uv_prepare_start(&prepare_handle, prepare_cb);
+ r = uv_mutex_init(&mutex);
ASSERT(r == 0);
+ uv_mutex_lock(&mutex);
- r = uv_async_init(uv_default_loop(), &async1_handle, async1_cb);
+ r = uv_prepare_init(uv_default_loop(), &prepare);
ASSERT(r == 0);
-
-#if 0
- r = uv_async_init(&async2_handle, async2_cb, close_cb, NULL);
+ r = uv_prepare_start(&prepare, prepare_cb);
ASSERT(r == 0);
-#endif
- r = uv_run(uv_default_loop());
+ r = uv_async_init(uv_default_loop(), &async, async_cb);
ASSERT(r == 0);
- r = uv_wait_thread(thread1_id);
- ASSERT(r == 0);
-#if 0
- r = uv_wait_thread(thread2_id);
- ASSERT(r == 0);
- r = uv_wait_thread(thread3_id);
+ r = uv_run(uv_default_loop());
ASSERT(r == 0);
-#endif
- ASSERT(prepare_cb_called == 2);
- ASSERT(async1_cb_called > 2);
- /* ASSERT(async2_cb_called = 16); */
+ ASSERT(prepare_cb_called > 0);
+ ASSERT(async_cb_called == 3);
ASSERT(close_cb_called == 2);
return 0;
uv_fs_t req;
r = uv_fs_rmdir(loop, &req, name, NULL);
r = uv_fs_mkdir(loop, &req, name, 0755, NULL);
- ASSERT(r == 0);
+ ASSERT(r == 0 || uv_last_error(loop).code == UV_EEXIST);
uv_fs_req_cleanup(&req);
}
r = uv_fs_event_init(uv_default_loop(), &fs_event, "watch_dir", NULL, 0);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.fs_event_init == ++fs_event_init_prev);
- r = uv_fs_rmdir(uv_default_loop(), &fs_req, "watch_dir", NULL);
- ASSERT(r == 0);
+ uv_fs_rmdir(uv_default_loop(), &fs_req, "watch_dir", NULL);
uv_fs_req_cleanup(&fs_req);
return 0;
#include <string.h>
#include <fcntl.h>
+#ifndef HAVE_KQUEUE
+# if __APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__
+# define HAVE_KQUEUE 1
+# endif
+#endif
+
static uv_fs_event_t fs_event;
static uv_timer_t timer;
static int timer_cb_called = 0;
return 0;
}
+#if HAVE_KQUEUE
+
+/* kqueue doesn't register fs events if you don't have an active watcher.
+ * The file descriptor needs to be part of the kqueue set of interest and
+ * that's not the case until we actually enter the event loop.
+ */
+TEST_IMPL(fs_event_close_in_callback) {
+ fprintf(stderr, "Skipping test, doesn't work with kqueue.\n");
+ return 0;
+}
+
+#else /* !HAVE_KQUEUE */
static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
int events, int status) {
return 0;
}
+
+#endif /* HAVE_KQUEUE */
uv_fs_req_cleanup(req);
if (close_cb_count == 3) {
r = uv_fs_unlink(loop, &unlink_req, "test_file2", unlink_cb);
+ ASSERT(r == 0);
}
}
ftruncate_cb_count++;
uv_fs_req_cleanup(req);
r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
+ ASSERT(r == 0);
}
ASSERT(strcmp(buf, "test-bu") == 0);
r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
}
+ ASSERT(r == 0);
}
memset(buf, 0, sizeof(buf));
r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1,
read_cb);
+ ASSERT(r == 0);
}
fsync_cb_count++;
uv_fs_req_cleanup(req);
r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
+ ASSERT(r == 0);
}
fdatasync_cb_count++;
uv_fs_req_cleanup(req);
r = uv_fs_fsync(loop, &fsync_req, open_req1.result, fsync_cb);
+ ASSERT(r == 0);
}
write_cb_count++;
uv_fs_req_cleanup(req);
r = uv_fs_fdatasync(loop, &fdatasync_req, open_req1.result, fdatasync_cb);
+ ASSERT(r == 0);
}
uv_fs_req_cleanup(req);
r = uv_fs_write(loop, &write_req, req->result, test_buf, sizeof(test_buf),
-1, write_cb);
+ ASSERT(r == 0);
}
return 0;
}
+
+
+TEST_IMPL(fs_read_file_eof) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWRITE | S_IREAD, NULL);
+ ASSERT(r != -1);
+ ASSERT(open_req1.result != -1);
+ uv_fs_req_cleanup(&open_req1);
+
+ r = uv_fs_write(loop, &write_req, open_req1.result, test_buf,
+ sizeof(test_buf), -1, NULL);
+ ASSERT(r != -1);
+ ASSERT(write_req.result != -1);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+ ASSERT(r != -1);
+ ASSERT(close_req.result != -1);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(loop, &open_req1, "test_file", O_RDONLY, 0, NULL);
+ ASSERT(r != -1);
+ ASSERT(open_req1.result != -1);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf, 0, sizeof(buf));
+ r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1,
+ NULL);
+ ASSERT(r != -1);
+ ASSERT(read_req.result != -1);
+ ASSERT(strcmp(buf, test_buf) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf),
+ read_req.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(read_req.result == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+ ASSERT(r != -1);
+ ASSERT(close_req.result != -1);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+
+ return 0;
+}
uint64_t free_mem = uv_get_free_memory();
uint64_t total_mem = uv_get_total_memory();
- printf("free_mem=%zu, total_mem=%zu\n", (size_t)free_mem, (size_t)total_mem);
+ printf("free_mem=%llu, total_mem=%llu\n",
+ (unsigned long long) free_mem,
+ (unsigned long long) total_mem);
ASSERT(free_mem > 0);
ASSERT(total_mem > 0);
#include <stdio.h>
#include <string.h> /* strlen */
-ares_channel channel;
-struct ares_options options;
-int optmask;
-
-int ares_bynamecallbacks;
-int bynamecallbacksig;
-int ares_byaddrcallbacks;
-int byaddrcallbacksig;
+static ares_channel channel;
+static struct ares_options options;
+static int optmask;
+
+static int ares_bynamecallbacks;
+static int bynamecallbacksig;
+static int ares_byaddrcallbacks;
+static int byaddrcallbacksig;
static void aresbynamecallback( void *arg,
int status,
uv_pipe_open(&ctx.channel, 0);
ASSERT(uv_is_readable((uv_stream_t*)&ctx.channel));
ASSERT(uv_is_writable((uv_stream_t*)&ctx.channel));
+ ASSERT(!uv_is_closing((uv_handle_t*)&ctx.channel));
r = uv_read2_start((uv_stream_t*)&ctx.channel, alloc_cb, read2_cb);
ASSERT(r == 0);
ASSERT(uv_is_readable((uv_stream_t*) &channel));
ASSERT(uv_is_writable((uv_stream_t*) &channel));
+ ASSERT(!uv_is_closing((uv_handle_t*) &channel));
r = uv_tcp_init(uv_default_loop(), &tcp_server);
ASSERT(r == 0);
ASSERT(uv_is_readable((uv_stream_t*)&channel));
ASSERT(uv_is_writable((uv_stream_t*)&channel));
+ ASSERT(!uv_is_closing((uv_handle_t*)&channel));
r = uv_tcp_init(uv_default_loop(), &tcp_server);
ASSERT(r == 0);
TEST_DECLARE (stdio_over_pipes)
TEST_DECLARE (ipc_listen_before_write)
TEST_DECLARE (ipc_listen_after_write)
+#ifndef _WIN32
TEST_DECLARE (ipc_send_recv_pipe)
+#endif
TEST_DECLARE (ipc_send_recv_tcp)
TEST_DECLARE (ipc_tcp_connection)
TEST_DECLARE (tcp_ping_pong)
TEST_DECLARE (spawn_and_kill)
TEST_DECLARE (spawn_and_kill_with_std)
TEST_DECLARE (spawn_and_ping)
+TEST_DECLARE (spawn_setuid_fails)
+TEST_DECLARE (spawn_setgid_fails)
TEST_DECLARE (kill)
TEST_DECLARE (fs_file_noent)
TEST_DECLARE (fs_file_nametoolong)
TEST_DECLARE (fs_event_no_callback_on_close)
TEST_DECLARE (fs_event_immediate_close)
TEST_DECLARE (fs_event_close_with_pending_event)
-TEST_DECLARE (fs_event_close_in_callback);
+TEST_DECLARE (fs_event_close_in_callback)
TEST_DECLARE (fs_readdir_empty_dir)
TEST_DECLARE (fs_readdir_file)
TEST_DECLARE (fs_open_dir)
TEST_DECLARE (listen_with_simultaneous_accepts)
TEST_DECLARE (listen_no_simultaneous_accepts)
TEST_DECLARE (fs_stat_root)
+#else
+TEST_DECLARE (spawn_setuid_setgid)
#endif
HELPER_DECLARE (tcp4_echo_server)
HELPER_DECLARE (tcp6_echo_server)
TEST_ENTRY (stdio_over_pipes)
TEST_ENTRY (ipc_listen_before_write)
TEST_ENTRY (ipc_listen_after_write)
+#ifndef _WIN32
TEST_ENTRY (ipc_send_recv_pipe)
+#endif
TEST_ENTRY (ipc_send_recv_tcp)
TEST_ENTRY (ipc_tcp_connection)
TEST_ENTRY (spawn_and_kill)
TEST_ENTRY (spawn_and_kill_with_std)
TEST_ENTRY (spawn_and_ping)
+ TEST_ENTRY (spawn_setuid_fails)
+ TEST_ENTRY (spawn_setgid_fails)
TEST_ENTRY (kill)
#ifdef _WIN32
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
TEST_ENTRY (listen_with_simultaneous_accepts)
TEST_ENTRY (listen_no_simultaneous_accepts)
TEST_ENTRY (fs_stat_root)
+#else
+ TEST_ENTRY (spawn_setuid_setgid)
#endif
TEST_ENTRY (fs_file_noent)
static int idle_2_cb_started = 0;
static int idle_2_is_active = 0;
-static int timer_cb_called = 0;
-
static void timer_cb(uv_timer_t* handle, int status) {
ASSERT(handle == &timer_handle);
ASSERT(status == 0);
-
- timer_cb_called++;
}
ASSERT(idle_2_close_cb_called == idle_2_cb_started);
ASSERT(idle_2_is_active == 0);
- ASSERT(timer_cb_called > 0);
-
return 0;
}
ASSERT(uv_is_readable(req->handle));
ASSERT(uv_is_writable(req->handle));
+ ASSERT(!uv_is_closing((uv_handle_t *)req->handle));
pinger_write_ping(pinger);
ASSERT(connect_cb_called == 1);
return 0;
-}
\ No newline at end of file
+}
err = uv_get_process_title(buffer, sizeof(buffer));
ASSERT(UV_OK == err.code);
- fprintf(stderr, "uv_get_process_title: %s\n", buffer);
+ printf("uv_get_process_title: %s\n", buffer);
err = uv_resident_set_memory(&rss);
ASSERT(UV_OK == err.code);
- fprintf(stderr, "uv_resident_set_memory: %zu\n", rss);
+ printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss);
err = uv_uptime(&uptime);
ASSERT(UV_OK == err.code);
- fprintf(stderr, "uv_uptime: %f\n", uptime);
+ ASSERT(uptime > 0);
+ printf("uv_uptime: %f\n", uptime);
err = uv_cpu_info(&cpus, &count);
ASSERT(UV_OK == err.code);
- fprintf(stderr, "uv_cpu_info:\n");
+ printf("uv_cpu_info:\n");
for (i = 0; i < count; i++) {
- fprintf(stderr, " model: %s\n", cpus[i].model);
- fprintf(stderr, " speed: %d\n", cpus[i].speed);
- fprintf(stderr, " times.sys: %zu\n", (size_t)cpus[i].cpu_times.sys);
- fprintf(stderr, " times.user: %zu\n", (size_t)cpus[i].cpu_times.user);
- fprintf(stderr, " times.idle: %zu\n", (size_t)cpus[i].cpu_times.idle);
- fprintf(stderr, " times.irq: %zu\n", (size_t)cpus[i].cpu_times.irq);
- fprintf(stderr, " times.nice: %zu\n", (size_t)cpus[i].cpu_times.nice);
+ printf(" model: %s\n", cpus[i].model);
+ printf(" speed: %d\n", cpus[i].speed);
+ printf(" times.sys: %llu\n", (unsigned long long) cpus[i].cpu_times.sys);
+ printf(" times.user: %llu\n",
+ (unsigned long long) cpus[i].cpu_times.user);
+ printf(" times.idle: %llu\n",
+ (unsigned long long) cpus[i].cpu_times.idle);
+ printf(" times.irq: %llu\n", (unsigned long long) cpus[i].cpu_times.irq);
+ printf(" times.nice: %llu\n",
+ (unsigned long long) cpus[i].cpu_times.nice);
}
uv_free_cpu_info(cpus, count);
err = uv_interface_addresses(&interfaces, &count);
ASSERT(UV_OK == err.code);
- fprintf(stderr, "uv_interface_addresses:\n");
+ printf("uv_interface_addresses:\n");
for (i = 0; i < count; i++) {
- fprintf(stderr, " name: %s\n", interfaces[i].name);
- fprintf(stderr, " internal: %d\n", interfaces[i].is_internal);
+ printf(" name: %s\n", interfaces[i].name);
+ printf(" internal: %d\n", interfaces[i].is_internal);
if (interfaces[i].address.address4.sin_family == AF_INET) {
uv_ip4_name(&interfaces[i].address.address4, buffer, sizeof(buffer));
uv_ip6_name(&interfaces[i].address.address6, buffer, sizeof(buffer));
}
- fprintf(stderr, " address: %s\n", buffer);
+ printf(" address: %s\n", buffer);
}
uv_free_interface_addresses(interfaces, count);
r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
ASSERT(r == 0);
+ ASSERT(!uv_is_closing((uv_handle_t*) req->handle));
uv_close((uv_handle_t*) req->handle, close_cb);
+ ASSERT(uv_is_closing((uv_handle_t*) req->handle));
connect_cb_called++;
}
#include <stdlib.h>
#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+
static int close_cb_called;
static int exit_cb_called;
static uv_process_t process;
}
+static void exit_cb_failure_expected(uv_process_t* process, int exit_status,
+ int term_signal) {
+ printf("exit_cb\n");
+ exit_cb_called++;
+ ASSERT(exit_status == 127);
+ ASSERT(term_signal == 0);
+ uv_close((uv_handle_t*)process, close_cb);
+}
+
+
+static void exit_cb_unexpected(uv_process_t* process, int exit_status,
+ int term_signal) {
+ ASSERT(0 && "should not have been called");
+}
+
+
static void kill_cb(uv_process_t* process, int exit_status, int term_signal) {
uv_err_t err;
if (nread > 0) {
output_used += nread;
} else if (nread < 0) {
- if (err.code == UV_EOF) {
- uv_close((uv_handle_t*)tcp, close_cb);
- }
+ ASSERT(err.code == UV_EOF);
+ uv_close((uv_handle_t*)tcp, close_cb);
}
}
options.file = exepath;
options.args = args;
options.exit_cb = exit_cb;
+ options.flags = 0;
}
TEST_IMPL(spawn_and_kill_with_std) {
int r;
- uv_pipe_t out;
- uv_pipe_t in;
+ uv_pipe_t in, out, err;
+ uv_write_t write;
+ char message[] = "Nancy's joining me because the message this evening is "
+ "not my message but ours.";
+ uv_buf_t buf;
init_process_options("spawn_helper4", kill_cb);
- uv_pipe_init(uv_default_loop(), &out, 0);
- uv_pipe_init(uv_default_loop(), &in, 0);
- options.stdout_stream = &out;
+ r = uv_pipe_init(uv_default_loop(), &in, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &out, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &err, 0);
+ ASSERT(r == 0);
+
options.stdin_stream = ∈
+ options.stdout_stream = &out;
+ options.stderr_stream = &err;
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
+ buf = uv_buf_init(message, sizeof message);
+ r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read);
+ ASSERT(r == 0);
+
r = uv_timer_init(uv_default_loop(), &timer);
ASSERT(r == 0);
ASSERT(r == 0);
ASSERT(exit_cb_called == 1);
- ASSERT(close_cb_called == 2); /* Once for process and once for timer. */
+ ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */
return 0;
}
ptr += GetEnvironmentVariableW(L"SYSTEMDRIVE", ptr, expected + sizeof(expected) - ptr);
++ptr;
*ptr = '\0';
-
+
result = make_program_env(environment);
for (str = result; *str; str += wcslen(str) + 1) {
}
ASSERT(wcscmp(expected, result) == 0);
-
+
+ return 0;
+}
+#endif
+
+#ifndef _WIN32
+TEST_IMPL(spawn_setuid_setgid) {
+ int r;
+
+ /* if not root, then this will fail. */
+ uv_uid_t uid = getuid();
+ if (uid != 0) {
+ fprintf(stderr, "spawn_setuid_setgid skipped: not root\n");
+ return 0;
+ }
+
+ init_process_options("spawn_helper1", exit_cb);
+
+ /* become the "nobody" user. */
+ struct passwd* pw;
+ pw = getpwnam("nobody");
+ ASSERT(pw != NULL);
+ options.uid = pw->pw_uid;
+ options.gid = pw->pw_gid;
+ options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID;
+
+ r = uv_spawn(uv_default_loop(), &process, options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop());
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+#endif
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_setuid_fails) {
+ int r;
+
+ /* if root, become nobody. */
+ uv_uid_t uid = getuid();
+ if (uid == 0) {
+ struct passwd* pw;
+ pw = getpwnam("nobody");
+ ASSERT(pw != NULL);
+ r = setuid(pw->pw_uid);
+ ASSERT(r == 0);
+ }
+
+ init_process_options("spawn_helper1", exit_cb_failure_expected);
+
+ options.flags |= UV_PROCESS_SETUID;
+ options.uid = (uv_uid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop());
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_setgid_fails) {
+ int r;
+
+ /* if root, become nobody. */
+ uv_uid_t uid = getuid();
+ if (uid == 0) {
+ struct passwd* pw;
+ pw = getpwnam("nobody");
+ ASSERT(pw != NULL);
+ r = setuid(pw->pw_uid);
+ ASSERT(r == 0);
+ }
+
+ init_process_options("spawn_helper1", exit_cb_failure_expected);
+
+ options.flags |= UV_PROCESS_SETGID;
+ options.gid = (uv_gid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop());
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ return 0;
+}
+#endif
+
+
+#ifdef _WIN32
+TEST_IMPL(spawn_setuid_fails) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb_unexpected);
+
+ options.flags |= UV_PROCESS_SETUID;
+ options.uid = (uv_uid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, options);
+ ASSERT(r == -1);
+ ASSERT(uv_last_error(uv_default_loop()).code == UV_ENOTSUP);
+
+ r = uv_run(uv_default_loop());
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
+ return 0;
+}
+
+
+TEST_IMPL(spawn_setgid_fails) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb_unexpected);
+
+ options.flags |= UV_PROCESS_SETGID;
+ options.gid = (uv_gid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, options);
+ ASSERT(r == -1);
+ ASSERT(uv_last_error(uv_default_loop()).code == UV_ENOTSUP);
+
+ r = uv_run(uv_default_loop());
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
return 0;
}
#endif
static int output_used;
-typedef struct {
- uv_write_t req;
- uv_buf_t buf;
-} write_req_t;
-
-
static void close_cb(uv_handle_t* handle) {
printf("close_cb\n");
close_cb_called++;
static uv_buf_t on_alloc(uv_handle_t* handle, size_t suggested_size) {
- uv_buf_t buf;
- buf.base = output + output_used;
- buf.len = OUTPUT_SIZE - output_used;
- return buf;
+ return uv_buf_init(output + output_used, OUTPUT_SIZE - output_used);
}
static void after_write(uv_write_t* req, int status) {
- write_req_t* wr;
-
if (status) {
uv_err_t err = uv_last_error(loop);
fprintf(stderr, "uv_write error: %s\n", uv_strerror(err));
ASSERT(0);
}
- wr = (write_req_t*) req;
-
/* Free the read/write buffer and the request */
- free(wr);
+ free(req);
after_write_cb_called++;
}
-static void on_read(uv_stream_t* tcp, ssize_t nread, uv_buf_t buf) {
- write_req_t* write_req;
+static void on_read(uv_stream_t* tcp, ssize_t nread, uv_buf_t rdbuf) {
+ uv_write_t* req;
+ uv_buf_t wrbuf;
int r;
- uv_err_t err = uv_last_error(uv_default_loop());
- ASSERT(nread > 0 || err.code == UV_EOF);
+ ASSERT(nread > 0 || uv_last_error(uv_default_loop()).code == UV_EOF);
if (nread > 0) {
output_used += nread;
if (output_used == 12) {
ASSERT(memcmp("hello world\n", output, 12) == 0);
- write_req = (write_req_t*)malloc(sizeof(*write_req));
- write_req->buf = uv_buf_init(output, output_used);
- r = uv_write(&write_req->req, (uv_stream_t*)&in, &write_req->buf, 1, after_write);
+ wrbuf = uv_buf_init(output, output_used);
+ req = malloc(sizeof(*req));
+ r = uv_write(req, (uv_stream_t*)&in, &wrbuf, 1, after_write);
ASSERT(r == 0);
}
}
}
-static uv_buf_t on_read_alloc(uv_handle_t* handle,
- size_t suggested_size) {
- uv_buf_t buf;
- buf.base = (char*)malloc(suggested_size);
- buf.len = suggested_size;
- return buf;
+static uv_buf_t on_read_alloc(uv_handle_t* handle, size_t suggested_size) {
+ return uv_buf_init(malloc(suggested_size), suggested_size);
}
ASSERT(close_cb_called == 2);
return 0;
-}
\ No newline at end of file
+}
TEST_IMPL(udp_options) {
+ static int invalid_ttls[] = { -1, 0, 256 };
uv_loop_t* loop;
uv_udp_t h;
int i, r;
r |= uv_udp_set_broadcast(&h, 0);
ASSERT(r == 0);
- /* values 0-255 should work */
- for (i = 0; i <= 255; i++) {
+ /* values 1-255 should work */
+ for (i = 1; i <= 255; i++) {
r = uv_udp_set_ttl(&h, i);
ASSERT(r == 0);
}
- /* anything >255 should fail */
- r = uv_udp_set_ttl(&h, 256);
- ASSERT(r == -1);
- ASSERT(uv_last_error(loop).code == UV_EINVAL);
- /* don't test ttl=-1, it's a valid value on some platforms */
+ for (i = 0; i < (int) ARRAY_SIZE(invalid_ttls); i++) {
+ r = uv_udp_set_ttl(&h, invalid_ttls[i]);
+ ASSERT(r == -1);
+ ASSERT(uv_last_error(loop).code == UV_EINVAL);
+ }
r = uv_udp_set_multicast_loop(&h, 1);
r |= uv_udp_set_multicast_loop(&h, 1);
'include/uv-private/ev.h',
'include/uv-private/ngx-queue.h',
'include/uv-private/uv-unix.h',
- 'src/unix/core.c',
- 'src/unix/uv-eio.c',
- 'src/unix/uv-eio.h',
- 'src/unix/fs.c',
- 'src/unix/udp.c',
- 'src/unix/tcp.c',
- 'src/unix/pipe.c',
- 'src/unix/tty.c',
- 'src/unix/stream.c',
+ 'src/unix/async.c',
'src/unix/cares.c',
+ 'src/unix/check.c',
+ 'src/unix/core.c',
'src/unix/dl.c',
- 'src/unix/error.c',
- 'src/unix/thread.c',
- 'src/unix/process.c',
- 'src/unix/internal.h',
'src/unix/eio/ecb.h',
'src/unix/eio/eio.c',
'src/unix/eio/xthread.h',
+ 'src/unix/error.c',
'src/unix/ev/ev.c',
'src/unix/ev/ev_vars.h',
'src/unix/ev/ev_wrap.h',
'src/unix/ev/event.h',
+ 'src/unix/fs.c',
+ 'src/unix/idle.c',
+ 'src/unix/internal.h',
+ 'src/unix/loop.c',
+ 'src/unix/pipe.c',
+ 'src/unix/prepare.c',
+ 'src/unix/process.c',
+ 'src/unix/stream.c',
+ 'src/unix/tcp.c',
+ 'src/unix/thread.c',
+ 'src/unix/timer.c',
+ 'src/unix/tty.c',
+ 'src/unix/udp.c',
+ 'src/unix/uv-eio.c',
+ 'src/unix/uv-eio.h',
],
'include_dirs': [ 'src/unix/ev', ],
'libraries': [ '-lm' ]
],
},
'defines': [
+ '_DARWIN_USE_64_BIT_INODE=1',
'EV_CONFIG_H="config_darwin.h"',
'EIO_CONFIG_H="config_darwin.h"',
]
'sources': [
'src/unix/linux/core.c',
'src/unix/linux/inotify.c',
+ 'src/unix/linux/syscalls.c',
+ 'src/unix/linux/syscalls.h',
],
'defines': [
'EV_CONFIG_H="config_linux.h"',