$<
clean: clean-platform
- $(RM) -f src/*.o *.a test/run-tests$(E) test/run-benchmarks$(E)
+ $(RM) -f *.a *.so test/run-tests$(E) test/run-benchmarks$(E)
distclean: distclean-platform
- $(RM) -f src/*.o *.a test/run-tests$(E) test/run-benchmarks$(E)
+ $(RM) -f *.a *.so test/run-tests$(E) test/run-benchmarks$(E)
--- /dev/null
+#!/bin/sh
+
+# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+SPARSE=${SPARSE:-sparse}
+
+SPARSE_FLAGS=${SPARSE_FLAGS:-"
+-D__POSIX__
+-Wsparse-all
+-Wno-do-while
+-Wno-transparent-union
+-Iinclude
+-Iinclude/uv-private
+-Isrc
+"}
+
+SOURCES="
+include/uv-private/ngx-queue.h
+include/uv-private/tree.h
+include/uv-private/uv-unix.h
+include/uv.h
+src/fs-poll.c
+src/inet.c
+src/unix/async.c
+src/unix/core.c
+src/unix/dl.c
+src/unix/error.c
+src/unix/fs.c
+src/unix/getaddrinfo.c
+src/unix/internal.h
+src/unix/loop-watcher.c
+src/unix/loop.c
+src/unix/pipe.c
+src/unix/poll.c
+src/unix/process.c
+src/unix/signal.c
+src/unix/stream.c
+src/unix/tcp.c
+src/unix/thread.c
+src/unix/threadpool.c
+src/unix/timer.c
+src/unix/tty.c
+src/unix/udp.c
+src/uv-common.c
+src/uv-common.h
+"
+
+TESTS="
+test/benchmark-async-pummel.c
+test/benchmark-async.c
+test/benchmark-fs-stat.c
+test/benchmark-getaddrinfo.c
+test/benchmark-loop-count.c
+test/benchmark-million-async.c
+test/benchmark-million-timers.c
+test/benchmark-multi-accept.c
+test/benchmark-ping-pongs.c
+test/benchmark-pound.c
+test/benchmark-pump.c
+test/benchmark-sizes.c
+test/benchmark-spawn.c
+test/benchmark-tcp-write-batch.c
+test/benchmark-thread.c
+test/benchmark-udp-pummel.c
+test/blackhole-server.c
+test/dns-server.c
+test/echo-server.c
+test/run-benchmarks.c
+test/run-tests.c
+test/runner-unix.c
+test/runner-unix.h
+test/runner.c
+test/runner.h
+test/task.h
+test/test-active.c
+test/test-async.c
+test/test-barrier.c
+test/test-callback-order.c
+test/test-callback-stack.c
+test/test-condvar.c
+test/test-connection-fail.c
+test/test-cwd-and-chdir.c
+test/test-delayed-accept.c
+test/test-dlerror.c
+test/test-embed.c
+test/test-error.c
+test/test-fail-always.c
+test/test-fs-event.c
+test/test-fs-poll.c
+test/test-fs.c
+test/test-get-currentexe.c
+test/test-get-loadavg.c
+test/test-get-memory.c
+test/test-getaddrinfo.c
+test/test-getsockname.c
+test/test-hrtime.c
+test/test-idle.c
+test/test-ipc-send-recv.c
+test/test-ipc.c
+test/test-loop-handles.c
+test/test-multiple-listen.c
+test/test-mutexes.c
+test/test-pass-always.c
+test/test-ping-pong.c
+test/test-pipe-bind-error.c
+test/test-pipe-connect-error.c
+test/test-platform-output.c
+test/test-poll-close.c
+test/test-poll.c
+test/test-process-title.c
+test/test-ref.c
+test/test-run-nowait.c
+test/test-run-once.c
+test/test-semaphore.c
+test/test-shutdown-close.c
+test/test-shutdown-eof.c
+test/test-signal-multiple-loops.c
+test/test-signal.c
+test/test-spawn.c
+test/test-stdio-over-pipes.c
+test/test-tcp-bind-error.c
+test/test-tcp-bind6-error.c
+test/test-tcp-close-while-connecting.c
+test/test-tcp-close.c
+test/test-tcp-connect-error-after-write.c
+test/test-tcp-connect-error.c
+test/test-tcp-connect-timeout.c
+test/test-tcp-connect6-error.c
+test/test-tcp-flags.c
+test/test-tcp-open.c
+test/test-tcp-read-stop.c
+test/test-tcp-shutdown-after-write.c
+test/test-tcp-unexpected-read.c
+test/test-tcp-write-error.c
+test/test-tcp-write-to-half-open-connection.c
+test/test-tcp-writealot.c
+test/test-thread.c
+test/test-threadpool-cancel.c
+test/test-threadpool.c
+test/test-timer-again.c
+test/test-timer.c
+test/test-tty.c
+test/test-udp-dgram-too-big.c
+test/test-udp-ipv6.c
+test/test-udp-multicast-join.c
+test/test-udp-multicast-ttl.c
+test/test-udp-open.c
+test/test-udp-options.c
+test/test-udp-send-and-recv.c
+test/test-util.c
+test/test-walk-handles.c
+"
+
+case `uname -s` in
+AIX)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D_AIX=1"
+ SOURCES="$SOURCES
+ src/unix/aix.c"
+ ;;
+Darwin)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__APPLE__=1"
+ SOURCES="$SOURCES
+ include/uv-private/uv-bsd.h
+ src/unix/darwin.c
+ src/unix/kqueue.c
+ src/unix/fsevents.c"
+ ;;
+DragonFly)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__DragonFly__=1"
+ SOURCES="$SOURCES
+ include/uv-private/uv-bsd.h
+ src/unix/kqueue.c
+ src/unix/freebsd.c"
+ ;;
+FreeBSD)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__FreeBSD__=1"
+ SOURCES="$SOURCES
+ include/uv-private/uv-bsd.h
+ src/unix/kqueue.c
+ src/unix/freebsd.c"
+ ;;
+Linux)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__linux__=1"
+ SOURCES="$SOURCES
+ include/uv-private/uv-linux.h
+ src/unix/linux/inotify.c
+ src/unix/linux/linux-core.c
+ src/unix/linux/syscalls.c
+ src/unix/linux/syscalls.h"
+ ;;
+NetBSD)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__NetBSD__=1"
+ SOURCES="$SOURCES
+ include/uv-private/uv-bsd.h
+ src/unix/kqueue.c
+ src/unix/netbsd.c"
+ ;;
+OpenBSD)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__OpenBSD__=1"
+ SOURCES="$SOURCES
+ include/uv-private/uv-bsd.h
+ src/unix/kqueue.c
+ src/unix/openbsd.c"
+ ;;
+SunOS)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__sun=1"
+ SOURCES="$SOURCES
+ include/uv-private/uv-sunos.h
+ src/unix/sunos.c"
+ ;;
+esac
+
+for ARCH in __i386__ __x86_64__ __arm__; do
+ $SPARSE $SPARSE_FLAGS -D$ARCH=1 $SOURCES
+done
+
+# Tests are architecture independent.
+$SPARSE $SPARSE_FLAGS -Itest $TESTS
RUNNER_LDFLAGS += -pthread
endif
+OBJDIR := out
+ifeq ($(MAKECMDGOALS), test)
+ OBJDIR := $(OBJDIR)/test
+endif
+
+OBJS := $(addprefix $(OBJDIR)/,$(OBJS))
+
libuv.a: $(OBJS)
$(AR) rcs $@ $^
libuv.$(SOEXT): $(OBJS)
$(CC) -shared -o $@ $^ $(LDFLAGS)
-src/%.o: src/%.c include/uv.h include/uv-private/uv-unix.h
+$(OBJDIR)/src/unix/%.o: src/unix/%.c include/uv.h include/uv-private/uv-unix.h src/unix/internal.h
+ @mkdir -p $(dir $@)
$(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
-src/unix/%.o: src/unix/%.c include/uv.h include/uv-private/uv-unix.h src/unix/internal.h
+$(OBJDIR)/src/%.o: src/%.c include/uv.h include/uv-private/uv-unix.h
+ @mkdir -p $(dir $@)
$(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
clean-platform:
- -rm -f src/unix/*.o
- -rm -f src/unix/linux/*.o
- -rm -rf test/run-tests.dSYM run-benchmarks.dSYM
+ -rm -rf $(OBJDIR)
+ -rm -f libuv.a libuv.$(SOEXT) test/run-{tests,benchmarks}.dSYM
distclean-platform:
- -rm -f src/unix/*.o
- -rm -f src/unix/linux/*.o
- -rm -rf test/run-tests.dSYM run-benchmarks.dSYM
+ -rm -rf $(OBJDIR)
+ -rm -f libuv.a libuv.$(SOEXT) test/run-{tests,benchmarks}.dSYM
#include <sys/port.h>
#include <port.h>
-#if defined(PORT_SOURCE_FILE)
-
-# define UV_PLATFORM_LOOP_FIELDS \
+/* For the sake of convenience and reduced #ifdef-ery in src/unix/sunos.c,
+ * add the fs_event fields even when this version of SunOS doesn't support
+ * file watching.
+ */
+#define UV_PLATFORM_LOOP_FIELDS \
uv__io_t fs_event_watcher; \
int fs_fd; \
+#if defined(PORT_SOURCE_FILE)
+
# define UV_PLATFORM_FS_EVENT_FIELDS \
file_obj_t fo; \
int fd; \
typedef struct uv_interface_address_s uv_interface_address_t;
+typedef enum {
+ UV_RUN_DEFAULT = 0,
+ UV_RUN_ONCE,
+ UV_RUN_NOWAIT
+} uv_run_mode;
+
+
/*
* This function must be called before any other functions in libuv.
*
UV_EXTERN int uv_run(uv_loop_t*);
/*
- * Poll for new events once. Note that this function blocks if there are no
- * pending events. Returns zero when done (no active handles or requests left),
- * or non-zero if more events are expected (meaning you should call
- * uv_run_once() again sometime in the future).
+ * This function runs the event loop. It will act differently depending on the
+ * specified mode:
+ * - UV_RUN_DEFAULT: Runs the event loop until the reference count drops to
+ * zero. Always returns zero.
+ * - UV_RUN_ONCE: Poll for new events once. Note that this function blocks if
+ * there are no pending events. Returns zero when done (no active handles
+ * or requests left), or non-zero if more events are expected (meaning you
+ * should run the event loop again sometime in the future).
+ * - UV_RUN_NOWAIT: Poll for new events once but don't block if there are no
+ * pending events.
*/
-UV_EXTERN int uv_run_once(uv_loop_t*);
+UV_EXTERN int uv_run2(uv_loop_t*, uv_run_mode mode);
/*
* Manually modify the event loop's reference count. Useful if the user wants
* Get backend file descriptor. Only kqueue, epoll and event ports are
* supported.
*
- * This can be used in conjuction with uv_run_once() to poll in one thread and
+ * This can be used in conjunction with uv_run_once() to poll in one thread and
* run the event loop's event callbacks in another.
*
* Useful for embedding libuv's event loop in another event loop.
* ultra efficient so don't go creating a million event loops with a million
* signal watchers.
*
- * TODO(bnoordhuis) As of 2012-08-10 only the default event loop supports
- * signals. That will be fixed.
+ * Note to Linux users: SIGRT0 and SIGRT1 (signals 32 and 33) are used by the
+ * NPTL pthreads library to manage threads. Installing watchers for those
+ * signals will lead to unpredictable behavior and is strongly discouraged.
+ * Future versions of libuv may simply reject them.
*
* Some signal support is available on Windows:
*
UV_SIGNAL_PRIVATE_FIELDS
};
-/* These functions are no-ops on Windows. */
UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle);
+
UV_EXTERN int uv_signal_start(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum);
+
UV_EXTERN int uv_signal_stop(uv_signal_t* handle);
/*
* Disables inheritance for file descriptors / handles that this process
* inherited from its parent. The effect is that child processes spawned by
- * this proces don't accidently inherit these handles.
+ * this process don't accidentally inherit these handles.
*
* It is recommended to call this function as early in your program as possible,
* before the inherited file descriptors can be closed or duplicated.
UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib);
/*
- * Close the shared libary.
+ * Close the shared library.
*/
UV_EXTERN void uv_dlclose(uv_lib_t* lib);
static int statbuf_eq(const uv_statbuf_t* a, const uv_statbuf_t* b) {
-#ifdef _WIN32
+#if defined(_WIN32)
return a->st_mtime == b->st_mtime
&& a->st_size == b->st_size
&& a->st_mode == b->st_mode;
#else
/* Jump through a few hoops to get sub-second granularity on Linux. */
-# if __linux__
-# if __USE_MISC /* _BSD_SOURCE || _SVID_SOURCE */
+# if defined(__linux__)
+# if defined(__USE_MISC) /* _BSD_SOURCE || _SVID_SOURCE */
if (a->st_ctim.tv_nsec != b->st_ctim.tv_nsec) return 0;
if (a->st_mtim.tv_nsec != b->st_mtim.tv_nsec) return 0;
# else
# endif
/* Jump through different hoops on OS X. */
-# if __APPLE__
+# if defined(__APPLE__)
# if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
if (a->st_ctimespec.tv_nsec != b->st_ctimespec.tv_nsec) return 0;
if (a->st_mtimespec.tv_nsec != b->st_mtimespec.tv_nsec) return 0;
}
-#ifdef _WIN32
+#if defined(_WIN32)
#include "win/internal.h"
#include "win/handle-inl.h"
#include <sys/proc.h>
#include <sys/procfs.h>
-uint64_t uv_hrtime() {
+uint64_t uv__hrtime(void) {
uint64_t G = 1000000000;
timebasestruct_t t;
read_wall_time(&t, TIMEBASE_SZ);
* on x86, it's about 4x faster. It probably makes zero difference in the
* grand scheme of things but I'm OCD enough not to let this one pass.
*/
-#if __i386__ || __x86_64__
+#if defined(__i386__) || defined(__x86_64__)
{
unsigned int val = 1;
__asm__ __volatile__("xchgl %0, %1" : "+r" (val) : "m" (*ptr));
return val != 0;
}
-#elif __GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 1 /* gcc >= 4.1 */
+#elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 0)
return __sync_val_compare_and_swap(ptr, 0, 1) != 0;
#else
*ptr = 1;
static uv_loop_t* default_loop_ptr;
+uint64_t uv_hrtime(void) {
+ return uv__hrtime();
+}
+
+
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
}
-static int uv__run(uv_loop_t* loop) {
- uv_update_time(loop);
- uv__run_timers(loop);
- uv__run_idle(loop);
- uv__run_prepare(loop);
- uv__run_pending(loop);
- uv__io_poll(loop, uv_backend_timeout(loop));
- uv__run_check(loop);
- uv__run_closing_handles(loop);
- return uv__has_active_handles(loop) || uv__has_active_reqs(loop);
+static int uv__loop_alive(uv_loop_t* loop) {
+ return uv__has_active_handles(loop) ||
+ uv__has_active_reqs(loop) ||
+ loop->closing_handles != NULL;
}
-int uv_run(uv_loop_t* loop) {
- while (uv__run(loop));
- return 0;
+int uv_run2(uv_loop_t* loop, uv_run_mode mode) {
+ int r;
+
+ if (!uv__loop_alive(loop))
+ return 0;
+
+ do {
+ uv__update_time(loop);
+ uv__run_timers(loop);
+ uv__run_idle(loop);
+ uv__run_prepare(loop);
+ uv__run_pending(loop);
+ uv__io_poll(loop, (mode & UV_RUN_NOWAIT ? 0 : uv_backend_timeout(loop)));
+ uv__run_check(loop);
+ uv__run_closing_handles(loop);
+ r = uv__loop_alive(loop);
+ } while (r && !(mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)));
+
+ return r;
}
-int uv_run_once(uv_loop_t* loop) {
- return uv__run(loop);
+int uv_run(uv_loop_t* loop) {
+ return uv_run2(loop, UV_RUN_DEFAULT);
}
void uv_update_time(uv_loop_t* loop) {
- loop->time = uv_hrtime() / 1000000;
+ uv__update_time(loop);
}
assert(sockfd >= 0);
while (1) {
-#if __linux__
+#if defined(__linux__)
static int no_accept4;
if (no_accept4)
if (r == -1)
return -1;
+ /* Bail out now if already set/clear. */
+ if (!!(r & O_NONBLOCK) == !!set)
+ return 0;
+
if (set)
flags = r | O_NONBLOCK;
else
if (r == -1)
return -1;
+ /* Bail out now if already set/clear. */
+ if (!!(r & FD_CLOEXEC) == !!set)
+ return 0;
+
if (set)
flags = r | FD_CLOEXEC;
else
}
-/* TODO move to uv-common.c? */
-size_t uv__strlcpy(char* dst, const char* src, size_t size) {
- const char *org;
-
- if (size == 0) {
- return 0;
- }
-
- org = src;
- while (--size && *src) {
- *dst++ = *src++;
- }
- *dst = '\0';
-
- return src - org;
-}
-
-
uv_err_t uv_cwd(char* buffer, size_t size) {
if (!buffer || !size) {
return uv__new_artificial_error(UV_EINVAL);
*/
#include "uv.h"
-#include "../uv-common.h"
+#include "internal.h"
#include <assert.h>
#include <stdint.h>
}
-uint64_t uv_hrtime() {
+uint64_t uv__hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
+
void uv_loadavg(double avg[3]) {
/* Unsupported as of cygwin 1.7.7 */
avg[0] = avg[1] = avg[2] = 0;
}
-uint64_t uv_hrtime(void) {
+uint64_t uv__hrtime(void) {
mach_timebase_info_data_t info;
if (mach_timebase_info(&info) != KERN_SUCCESS)
}
-uint64_t uv_hrtime(void) {
+uint64_t uv__hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
errno == EIO ||
errno == ENOTSOCK ||
errno == EXDEV) {
+ errno = 0;
return uv__fs_sendfile_emul(req);
}
errno == EIO ||
errno == ENOTSOCK ||
errno == EXDEV) {
+ errno = 0;
return uv__fs_sendfile_emul(req);
}
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
uv_getaddrinfo_t* req = container_of(w, uv_getaddrinfo_t, work_req);
struct addrinfo *res = req->res;
-#if __sun
+#if defined(__sun)
size_t hostlen;
if (req->hostname)
if (req->retcode == 0) {
/* OK */
-#if EAI_NODATA /* FreeBSD deprecated EAI_NODATA */
+#if defined(EAI_NODATA) /* FreeBSD deprecated EAI_NODATA */
} else if (req->retcode == EAI_NONAME || req->retcode == EAI_NODATA) {
#else
} else if (req->retcode == EAI_NONAME) {
#endif
uv__set_sys_error(req->loop, ENOENT); /* FIXME compatibility hack */
-#if __sun
+#if defined(__sun)
} else if (req->retcode == EAI_MEMORY && hostlen >= MAXHOSTNAMELEN) {
uv__set_sys_error(req->loop, ENOENT);
#endif
# define inline __inline
#endif
-#undef HAVE_PORTS_FS
-
-#if __linux__
+#if defined(__linux__)
# include "linux/syscalls.h"
#endif /* __linux__ */
#if defined(__sun)
# include <sys/port.h>
# include <port.h>
-# ifdef PORT_SOURCE_FILE
-# define HAVE_PORTS_FS 1
-# endif
# define futimes(fd, tv) futimesat(fd, (void*)0, tv)
#endif /* __sun */
UV_TCP_SINGLE_ACCEPT = 0x400 /* Only accept() when idle. */
};
-__attribute__((unused))
-static void uv__req_init(uv_loop_t* loop, uv_req_t* req, uv_req_type type) {
- req->type = type;
- uv__req_register(loop, req);
-}
-#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);
/* signal */
void uv__signal_close(uv_signal_t* handle);
void uv__signal_global_once_init(void);
-void uv__signal_loop_cleanup();
+void uv__signal_loop_cleanup(uv_loop_t* loop);
/* thread pool */
void uv__work_submit(uv_loop_t* loop,
void uv__work_done(uv_async_t* handle, int status);
/* platform specific */
+uint64_t uv__hrtime(void);
int uv__kqueue_init(uv_loop_t* loop);
int uv__platform_loop_init(uv_loop_t* loop, int default_loop);
void uv__platform_loop_delete(uv_loop_t* loop);
#endif /* defined(__APPLE__) */
+__attribute__((unused))
+static void uv__req_init(uv_loop_t* loop, uv_req_t* req, uv_req_type type) {
+ req->type = type;
+ uv__req_register(loop, req);
+}
+#define uv__req_init(loop, req, type) \
+ uv__req_init((loop), (uv_req_t*)(req), (type))
+
+__attribute__((unused))
+static void uv__update_time(uv_loop_t* loop) {
+ loop->time = uv__hrtime() / 1000000;
+}
+
#endif /* UV_UNIX_INTERNAL_H_ */
ARRAY_SIZE(events),
timeout == -1 ? NULL : &spec);
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
if (nfds == 0) {
assert(timeout != -1);
return;
update_timeout:
assert(timeout > 0);
- diff = uv_hrtime() / 1000000;
- assert(diff >= base);
- diff -= base;
-
+ diff = loop->time - base;
if (diff >= (uint64_t) timeout)
return;
# define CLOCK_BOOTTIME 7
#endif
-static char buf[MAXPATHLEN + 1];
static void* args_mem;
static struct {
ARRAY_SIZE(events),
timeout);
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
if (nfds == 0) {
assert(timeout != -1);
return;
update_timeout:
assert(timeout > 0);
- diff = uv_hrtime() / 1000000;
- assert(diff >= base);
- diff -= base;
-
+ diff = loop->time - base;
if (diff >= (uint64_t) timeout)
return;
}
-uint64_t uv_hrtime() {
+uint64_t uv__hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
size_t page_size = getpagesize();
char *cbuf;
int foundExeEnd;
+ char buf[PATH_MAX + 1];
f = fopen("/proc/self/stat", "r");
if (!f) return uv__new_sys_error(errno);
static const char model_marker[] = "";
static const char speed_marker[] = "";
#endif
+ static const char bogus_model[] = "unknown";
unsigned int model_idx;
unsigned int speed_idx;
char buf[1024];
char* model;
FILE* fp;
+ char* inferred_model;
fp = fopen("/proc/cpuinfo", "r");
if (fp == NULL)
}
}
fclose(fp);
+
+ /* Now we want to make sure that all the models contain *something*:
+ * it's not safe to leave them as null.
+ */
+ if (model_idx == 0) {
+ /* No models at all: fake up the first one. */
+ ci[0].model = strndup(bogus_model, sizeof(bogus_model) - 1);
+ model_idx = 1;
+ }
+
+ /* Not enough models, but we do have at least one. So we'll just
+ * copy the rest down: it might be better to indicate somehow that
+ * the remaining ones have been guessed.
+ */
+ inferred_model = ci[model_idx - 1].model;
+
+ while (model_idx < numcpus) {
+ ci[model_idx].model = strndup(inferred_model, strlen(inferred_model));
+ model_idx++;
+ }
}
#include <sys/types.h>
#include <errno.h>
-#if __i386__
+#if defined(__i386__)
# ifndef __NR_socketcall
# define __NR_socketcall 102
# endif
#endif
-#if __arm__
-# if __thumb__ || __ARM_EABI__
+#if defined(__arm__)
+# if defined(__thumb__) || defined(__ARM_EABI__)
# define UV_SYSCALL_BASE 0
# else
# define UV_SYSCALL_BASE 0x900000
#endif /* __arm__ */
#ifndef __NR_accept4
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_accept4 288
-# elif __i386__
+# elif defined(__i386__)
/* Nothing. Handled through socketcall(). */
-# elif __arm__
+# elif defined(__arm__)
# define __NR_accept4 (UV_SYSCALL_BASE + 366)
# endif
#endif /* __NR_accept4 */
#ifndef __NR_eventfd
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_eventfd 284
-# elif __i386__
+# elif defined(__i386__)
# define __NR_eventfd 323
-# elif __arm__
+# elif defined(__arm__)
# define __NR_eventfd (UV_SYSCALL_BASE + 351)
# endif
#endif /* __NR_eventfd */
#ifndef __NR_eventfd2
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_eventfd2 290
-# elif __i386__
+# elif defined(__i386__)
# define __NR_eventfd2 328
-# elif __arm__
+# elif defined(__arm__)
# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
# endif
#endif /* __NR_eventfd2 */
#ifndef __NR_epoll_create
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_epoll_create 213
-# elif __i386__
+# elif defined(__i386__)
# define __NR_epoll_create 254
-# elif __arm__
+# elif defined(__arm__)
# define __NR_epoll_create (UV_SYSCALL_BASE + 250)
# endif
#endif /* __NR_epoll_create */
#ifndef __NR_epoll_create1
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_epoll_create1 291
-# elif __i386__
+# elif defined(__i386__)
# define __NR_epoll_create1 329
-# elif __arm__
+# elif defined(__arm__)
# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357)
# endif
#endif /* __NR_epoll_create1 */
#ifndef __NR_epoll_ctl
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_epoll_ctl 233 /* used to be 214 */
-# elif __i386__
+# elif defined(__i386__)
# define __NR_epoll_ctl 255
-# elif __arm__
+# elif defined(__arm__)
# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251)
# endif
#endif /* __NR_epoll_ctl */
#ifndef __NR_epoll_wait
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_epoll_wait 232 /* used to be 215 */
-# elif __i386__
+# elif defined(__i386__)
# define __NR_epoll_wait 256
-# elif __arm__
+# elif defined(__arm__)
# define __NR_epoll_wait (UV_SYSCALL_BASE + 252)
# endif
#endif /* __NR_epoll_wait */
#ifndef __NR_epoll_pwait
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_epoll_pwait 281
-# elif __i386__
+# elif defined(__i386__)
# define __NR_epoll_pwait 319
-# elif __arm__
+# elif defined(__arm__)
# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346)
# endif
#endif /* __NR_epoll_pwait */
#ifndef __NR_inotify_init
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_inotify_init 253
-# elif __i386__
+# elif defined(__i386__)
# define __NR_inotify_init 291
-# elif __arm__
+# elif defined(__arm__)
# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
# endif
#endif /* __NR_inotify_init */
#ifndef __NR_inotify_init1
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_inotify_init1 294
-# elif __i386__
+# elif defined(__i386__)
# define __NR_inotify_init1 332
-# elif __arm__
+# elif defined(__arm__)
# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
# endif
#endif /* __NR_inotify_init1 */
#ifndef __NR_inotify_add_watch
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_inotify_add_watch 254
-# elif __i386__
+# elif defined(__i386__)
# define __NR_inotify_add_watch 292
-# elif __arm__
+# elif defined(__arm__)
# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
# endif
#endif /* __NR_inotify_add_watch */
#ifndef __NR_inotify_rm_watch
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_inotify_rm_watch 255
-# elif __i386__
+# elif defined(__i386__)
# define __NR_inotify_rm_watch 293
-# elif __arm__
+# elif defined(__arm__)
# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
# endif
#endif /* __NR_inotify_rm_watch */
#ifndef __NR_pipe2
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_pipe2 293
-# elif __i386__
+# elif defined(__i386__)
# define __NR_pipe2 331
-# elif __arm__
+# elif defined(__arm__)
# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
# endif
#endif /* __NR_pipe2 */
#ifndef __NR_recvmmsg
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_recvmmsg 299
-# elif __i386__
+# elif defined(__i386__)
# define __NR_recvmmsg 337
-# elif __arm__
+# elif defined(__arm__)
# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
# endif
#endif /* __NR_recvmsg */
#ifndef __NR_sendmmsg
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_sendmmsg 307
-# elif __i386__
+# elif defined(__i386__)
# define __NR_sendmmsg 345
-# elif __arm__
+# elif defined(__arm__)
# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
# endif
#endif /* __NR_sendmmsg */
#ifndef __NR_utimensat
-# if __x86_64__
+# if defined(__x86_64__)
# define __NR_utimensat 280
-# elif __i386__
+# elif defined(__i386__)
# define __NR_utimensat 320
-# elif __arm__
+# elif defined(__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__
+#if defined(__i386__)
unsigned long args[4];
int r;
errno = ENOSYS;
return r;
-#elif __NR_accept4
+#elif defined(__NR_accept4)
return syscall(__NR_accept4, fd, addr, addrlen, flags);
#else
return errno = ENOSYS, -1;
int uv__eventfd(unsigned int count) {
-#if __NR_eventfd
+#if defined(__NR_eventfd)
return syscall(__NR_eventfd, count);
#else
return errno = ENOSYS, -1;
int uv__eventfd2(unsigned int count, int flags) {
-#if __NR_eventfd2
+#if defined(__NR_eventfd2)
return syscall(__NR_eventfd2, count, flags);
#else
return errno = ENOSYS, -1;
int uv__epoll_create(int size) {
-#if __NR_epoll_create
+#if defined(__NR_epoll_create)
return syscall(__NR_epoll_create, size);
#else
return errno = ENOSYS, -1;
int uv__epoll_create1(int flags) {
-#if __NR_epoll_create1
+#if defined(__NR_epoll_create1)
return syscall(__NR_epoll_create1, flags);
#else
return errno = ENOSYS, -1;
int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) {
-#if __NR_epoll_ctl
+#if defined(__NR_epoll_ctl)
return syscall(__NR_epoll_ctl, epfd, op, fd, events);
#else
return errno = ENOSYS, -1;
struct uv__epoll_event* events,
int nevents,
int timeout) {
-#if __NR_epoll_wait
+#if defined(__NR_epoll_wait)
return syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
#else
return errno = ENOSYS, -1;
int nevents,
int timeout,
const sigset_t* sigmask) {
-#if __NR_epoll_pwait
+#if defined(__NR_epoll_pwait)
return syscall(__NR_epoll_pwait,
epfd,
events,
int uv__inotify_init(void) {
-#if __NR_inotify_init
+#if defined(__NR_inotify_init)
return syscall(__NR_inotify_init);
#else
return errno = ENOSYS, -1;
int uv__inotify_init1(int flags) {
-#if __NR_inotify_init1
+#if defined(__NR_inotify_init1)
return syscall(__NR_inotify_init1, flags);
#else
return errno = ENOSYS, -1;
int uv__inotify_add_watch(int fd, const char* path, __u32 mask) {
-#if __NR_inotify_add_watch
+#if defined(__NR_inotify_add_watch)
return syscall(__NR_inotify_add_watch, fd, path, mask);
#else
return errno = ENOSYS, -1;
int uv__inotify_rm_watch(int fd, __s32 wd) {
-#if __NR_inotify_rm_watch
+#if defined(__NR_inotify_rm_watch)
return syscall(__NR_inotify_rm_watch, fd, wd);
#else
return errno = ENOSYS, -1;
int uv__pipe2(int pipefd[2], int flags) {
-#if __NR_pipe2
+#if defined(__NR_pipe2)
return syscall(__NR_pipe2, pipefd, flags);
#else
return errno = ENOSYS, -1;
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags) {
-#if __NR_sendmmsg
+#if defined(__NR_sendmmsg)
return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
#else
return errno = ENOSYS, -1;
unsigned int vlen,
unsigned int flags,
struct timespec* timeout) {
-#if __NR_recvmmsg
+#if defined(__NR_recvmmsg)
return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
#else
return errno = ENOSYS, -1;
const struct timespec times[2],
int flags)
{
-#if __NR_utimensat
+#if defined(__NR_utimensat)
return syscall(__NR_utimensat, dirfd, path, times, flags);
#else
return errno = ENOSYS, -1;
\
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
if (uv__is_active(handle)) return 0; \
+ if (cb == NULL) \
+ return uv__set_artificial_error(handle->loop, UV_EINVAL); \
ngx_queue_insert_head(&handle->loop->name##_handles, &handle->queue); \
handle->name##_cb = cb; \
uv__handle_start(handle); \
ngx_queue_t* q; \
ngx_queue_foreach(q, &loop->name##_handles) { \
h = ngx_queue_data(q, uv_##name##_t, queue); \
- if (h->name##_cb) h->name##_cb(h, 0); \
+ h->name##_cb(h, 0); \
} \
} \
\
ngx_queue_init(&loop->watcher_queue);
loop->closing_handles = NULL;
- loop->time = uv_hrtime() / 1000000;
+ loop->time = uv__hrtime() / 1000000;
loop->async_pipefd[0] = -1;
loop->async_pipefd[1] = -1;
loop->signal_pipefd[0] = -1;
}
-uint64_t uv_hrtime(void) {
+uint64_t uv__hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
-uint64_t uv_hrtime(void) {
+uint64_t uv__hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
int uv__make_socketpair(int fds[2], int flags) {
-#if __linux__
+#if defined(__linux__)
static int no_cloexec;
if (no_cloexec)
int uv__make_pipe(int fds[2], int flags) {
-#if __linux__
+#if defined(__linux__)
static int no_pipe2;
if (no_pipe2)
* zero on success.
*/
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
- int fd = -1;
- switch (container->flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
- UV_INHERIT_STREAM)) {
- case UV_IGNORE:
- return 0;
- case UV_CREATE_PIPE:
- assert(container->data.stream != NULL);
-
- if (container->data.stream->type != UV_NAMED_PIPE) {
- errno = EINVAL;
- return -1;
- }
+ int mask;
+ int fd;
- return uv__make_socketpair(fds, 0);
- case UV_INHERIT_FD:
- case UV_INHERIT_STREAM:
- if (container->flags & UV_INHERIT_FD) {
- fd = container->data.fd;
- } else {
- fd = uv__stream_fd(container->data.stream);
- }
+ mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
- if (fd == -1) {
- errno = EINVAL;
- return -1;
- }
+ switch (container->flags & mask) {
+ case UV_IGNORE:
+ return 0;
+
+ case UV_CREATE_PIPE:
+ assert(container->data.stream != NULL);
+ if (container->data.stream->type != UV_NAMED_PIPE) {
+ errno = EINVAL;
+ return -1;
+ }
+ return uv__make_socketpair(fds, 0);
- fds[1] = fd;
+ case UV_INHERIT_FD:
+ case UV_INHERIT_STREAM:
+ if (container->flags & UV_INHERIT_FD)
+ fd = container->data.fd;
+ else
+ fd = uv__stream_fd(container->data.stream);
- return 0;
- default:
- assert(0 && "Unexpected flags");
+ if (fd == -1) {
+ errno = EINVAL;
return -1;
- }
-}
+ }
+ fds[1] = fd;
+ return 0;
-static int uv__process_stdio_flags(uv_stdio_container_t* container,
- int writable) {
- if (container->data.stream->type == UV_NAMED_PIPE &&
- ((uv_pipe_t*)container->data.stream)->ipc) {
- return UV_STREAM_READABLE | UV_STREAM_WRITABLE;
- } else if (writable) {
- return UV_STREAM_WRITABLE;
- } else {
- return UV_STREAM_READABLE;
+ default:
+ assert(0 && "Unexpected flags");
+ return -1;
}
}
static int uv__process_open_stream(uv_stdio_container_t* container,
- int fds[2],
+ int pipefds[2],
int writable) {
- int child_fd;
int flags;
- int fd;
-
- fd = fds[0];
- child_fd = fds[1];
- /* No need to create stream */
- if (!(container->flags & UV_CREATE_PIPE) || fd < 0)
+ if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
return 0;
- assert(child_fd >= 0);
- close(child_fd);
+ if (close(pipefds[1]))
+ if (errno != EINTR && errno != EINPROGRESS)
+ abort();
- uv__nonblock(fd, 1);
- flags = uv__process_stdio_flags(container, writable);
+ pipefds[1] = -1;
+ uv__nonblock(pipefds[0], 1);
- return uv__stream_open((uv_stream_t*)container->data.stream, fd, flags);
+ if (container->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*)container->data.stream)->ipc)
+ flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE;
+ else if (writable)
+ flags = UV_STREAM_WRITABLE;
+ else
+ flags = UV_STREAM_READABLE;
+
+ return uv__stream_open(container->data.stream, pipefds[0], flags);
}
if (uv__process_init_stdio(options.stdio + i, pipes[i]))
goto error;
- /* swap stdin file descriptors, it's the only writable stream */
- {
- int* p = pipes[0];
- int t = p[0];
- p[0] = p[1];
- p[1] = t;
- }
-
/* This pipe is used by the parent to wait until
* the child has called `execve()`. We need this
* to avoid the following race condition:
uv__signal_compare)
-static void uv__signal_global_init() {
+static void uv__signal_global_init(void) {
if (uv__make_pipe(uv__signal_lock_pipefd, 0))
abort();
-static int uv__signal_lock() {
+static int uv__signal_lock(void) {
int r;
char data;
}
-static int uv__signal_unlock() {
+static int uv__signal_unlock(void) {
int r;
char data = 42;
}
-void uv__signal_handler(int signum) {
+static void uv__signal_handler(int signum) {
uv__signal_msg_t msg;
uv_signal_t* handle;
void uv__stream_osx_select(void* arg) {
uv_stream_t* stream;
uv__stream_select_t* s;
- fd_set read;
- fd_set write;
- fd_set error;
- struct timeval timeout;
+ char buf[1024];
+ fd_set sread;
+ fd_set swrite;
+ fd_set serror;
int events;
int fd;
int r;
break;
/* Watch fd using select(2) */
- FD_ZERO(&read);
- FD_ZERO(&write);
- FD_ZERO(&error);
+ FD_ZERO(&sread);
+ FD_ZERO(&swrite);
+ FD_ZERO(&serror);
if (uv_is_readable(stream))
- FD_SET(fd, &read);
+ FD_SET(fd, &sread);
if (uv_is_writable(stream))
- FD_SET(fd, &write);
- FD_SET(fd, &error);
- FD_SET(s->int_fd, &read);
+ FD_SET(fd, &swrite);
+ FD_SET(fd, &serror);
+ FD_SET(s->int_fd, &sread);
- timeout.tv_sec = 0;
- timeout.tv_usec = 250000; /* 250 ms timeout */
- r = select(max_fd + 1, &read, &write, &error, &timeout);
+ /* Wait indefinitely for fd events */
+ r = select(max_fd + 1, &sread, &swrite, &serror, NULL);
if (r == -1) {
if (errno == EINTR)
continue;
if (r == 0)
continue;
+ /* Empty socketpair's buffer in case of interruption */
+ if (FD_ISSET(s->int_fd, &sread))
+ while (1) {
+ r = read(s->int_fd, buf, sizeof(buf));
+
+ if (r == sizeof(buf))
+ continue;
+
+ if (r != -1)
+ break;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ abort();
+ }
+
/* Handle events */
events = 0;
- if (FD_ISSET(fd, &read))
+ if (FD_ISSET(fd, &sread))
events |= UV__POLLIN;
- if (FD_ISSET(fd, &write))
+ if (FD_ISSET(fd, &swrite))
events |= UV__POLLOUT;
- if (FD_ISSET(fd, &error))
+ if (FD_ISSET(fd, &serror))
events |= UV__POLLERR;
uv_mutex_lock(&s->mutex);
}
-uv_write_t* uv_write_queue_head(uv_stream_t* stream) {
- ngx_queue_t* q;
- uv_write_t* req;
-
- if (ngx_queue_empty(&stream->write_queue)) {
- return NULL;
- }
-
- q = ngx_queue_head(&stream->write_queue);
- if (!q) {
- return NULL;
- }
-
- req = ngx_queue_data(q, struct uv_write_s, queue);
- assert(req);
-
- return req;
-}
-
-
static void uv__drain(uv_stream_t* stream) {
uv_shutdown_t* req;
- assert(!uv_write_queue_head(stream));
+ assert(ngx_queue_empty(&stream->write_queue));
assert(stream->write_queue_size == 0);
uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
}
-/* On success returns NULL. On error returns a pointer to the write request
- * which had the error.
- */
static void uv__write(uv_stream_t* stream) {
- uv_write_t* req;
struct iovec* iov;
+ ngx_queue_t* q;
+ uv_write_t* req;
int iovcnt;
ssize_t n;
- if (stream->flags & UV_CLOSING) {
- /* Handle was closed this tick. We've received a stale
- * 'is writable' callback from the event loop, ignore.
- */
- return;
- }
-
start:
assert(uv__stream_fd(stream) >= 0);
- /* Get the request at the head of the queue. */
- req = uv_write_queue_head(stream);
- if (!req) {
+ if (ngx_queue_empty(&stream->write_queue)) {
assert(stream->write_queue_size == 0);
return;
}
+ q = ngx_queue_head(&stream->write_queue);
+ req = ngx_queue_data(q, uv_write_t, queue);
assert(req->handle == stream);
/*
assert(ngx_queue_empty(&stream->write_completed_queue));
/* Write queue drained. */
- if (!uv_write_queue_head(stream)) {
+ if (ngx_queue_empty(&stream->write_queue))
uv__drain(stream);
- }
}
}
-int uv__read_start_common(uv_stream_t* stream, uv_alloc_cb alloc_cb,
- uv_read_cb read_cb, uv_read2_cb read2_cb) {
+static int uv__read_start_common(uv_stream_t* stream,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb,
+ uv_read2_cb read2_cb) {
assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
stream->type == UV_TTY);
#include <kstat.h>
#include <fcntl.h>
-#if HAVE_PORTS_FS
-# include <sys/port.h>
-# include <port.h>
-
-# define PORT_FIRED 0x69
-# define PORT_UNUSED 0x0
-# define PORT_LOADED 0x99
-# define PORT_DELETED -1
-#endif
+#include <sys/port.h>
+#include <port.h>
+
+#define PORT_FIRED 0x69
+#define PORT_UNUSED 0x0
+#define PORT_LOADED 0x99
+#define PORT_DELETED -1
#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
#define PROCFS_FILE_OFFSET_BITS_HACK 1
abort();
}
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
if (events[0].portev_source == 0) {
if (timeout == 0)
return;
update_timeout:
assert(timeout > 0);
- diff = uv_hrtime() / 1000000;
- assert(diff >= base);
- diff -= base;
-
+ diff = loop->time - base;
if (diff >= (uint64_t) timeout)
return;
}
-uint64_t uv_hrtime() {
- return (gethrtime());
+uint64_t uv__hrtime(void) {
+ return gethrtime();
}
}
-#if HAVE_PORTS_FS
+#if defined(PORT_SOURCE_FILE)
+
static void uv__fs_event_rearm(uv_fs_event_t *handle) {
if (handle->fd == -1)
return;
uv__handle_stop(handle);
}
-#else /* !HAVE_PORTS_FS */
+#else /* !defined(PORT_SOURCE_FILE) */
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
UNREACHABLE();
}
-#endif /* HAVE_PORTS_FS */
+#endif /* defined(PORT_SOURCE_FILE) */
char** uv_setup_args(int argc, char** argv) {
struct timespec ts;
uint64_t abstime;
- abstime = uv_hrtime() + timeout;
+ abstime = uv__hrtime() + timeout;
ts.tv_sec = abstime / NANOSEC;
ts.tv_nsec = abstime % NANOSEC;
r = pthread_cond_timedwait(cond, mutex, &ts);
}
-int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
+static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
int cancelled;
uv_mutex_lock(&mutex);
w->work = uv__cancelled;
uv_mutex_lock(&loop->wq_mutex);
ngx_queue_insert_tail(&loop->wq, &w->wq);
+ uv_async_send(&loop->wq_async);
uv_mutex_unlock(&loop->wq_mutex);
return 0;
}
-void uv_tty_reset_mode() {
+void uv_tty_reset_mode(void) {
if (orig_termios_fd >= 0) {
tcsetattr(orig_termios_fd, TCSANOW, &orig_termios);
}
static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) {
-#if __sun
+#if defined(__sun)
char arg = val;
#else
int arg = val;
!ngx_queue_empty(&(loop)->active_reqs) || \
(loop)->endgame_handles != NULL)
-#define UV_LOOP_ONCE(loop, poll) \
- do { \
- uv_update_time((loop)); \
- uv_process_timers((loop)); \
- \
- /* Call idle callbacks if nothing to do. */ \
- if ((loop)->pending_reqs_tail == NULL && \
- (loop)->endgame_handles == NULL) { \
- uv_idle_invoke((loop)); \
- } \
- \
- uv_process_reqs((loop)); \
- uv_process_endgames((loop)); \
- \
- if (!UV_LOOP_ALIVE((loop))) { \
- break; \
- } \
- \
- uv_prepare_invoke((loop)); \
- \
- poll((loop), (loop)->idle_handles == NULL && \
- (loop)->pending_reqs_tail == NULL && \
- (loop)->endgame_handles == NULL && \
- UV_LOOP_ALIVE((loop))); \
- \
- uv_check_invoke((loop)); \
- } while (0);
-
-#define UV_LOOP(loop, poll) \
- while (UV_LOOP_ALIVE((loop))) { \
- UV_LOOP_ONCE(loop, poll) \
- }
+int uv_run2(uv_loop_t *loop, uv_run_mode mode) {
+ int r;
+ void (*poll)(uv_loop_t* loop, int block);
+
+ if (pGetQueuedCompletionStatusEx)
+ poll = &uv_poll_ex;
+ else
+ poll = &uv_poll;
+
+ r = UV_LOOP_ALIVE(loop);
+ while (r) {
+ uv_update_time(loop);
+ uv_process_timers(loop);
+
+ /* Call idle callbacks if nothing to do. */
+ if (loop->pending_reqs_tail == NULL &&
+ loop->endgame_handles == NULL) {
+ uv_idle_invoke(loop);
+ }
+ uv_process_reqs(loop);
+ uv_process_endgames(loop);
-int uv_run_once(uv_loop_t* loop) {
- if (pGetQueuedCompletionStatusEx) {
- UV_LOOP_ONCE(loop, uv_poll_ex);
- } else {
- UV_LOOP_ONCE(loop, uv_poll);
+ uv_prepare_invoke(loop);
+
+ (*poll)(loop, loop->idle_handles == NULL &&
+ loop->pending_reqs_tail == NULL &&
+ loop->endgame_handles == NULL &&
+ UV_LOOP_ALIVE(loop) &&
+ !(mode & UV_RUN_NOWAIT));
+
+ uv_check_invoke(loop);
+ r = UV_LOOP_ALIVE(loop);
+
+ if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
+ break;
}
- return UV_LOOP_ALIVE(loop);
+ return r;
}
int uv_run(uv_loop_t* loop) {
- if (pGetQueuedCompletionStatusEx) {
- UV_LOOP(loop, uv_poll_ex);
- } else {
- UV_LOOP(loop, uv_poll);
- }
-
- assert(!UV_LOOP_ALIVE((loop)));
- return 0;
+ return uv_run2(loop, UV_RUN_DEFAULT);
}
if (handle->flags & UV_HANDLE_ACTIVE) \
return 0; \
\
+ if (cb == NULL) \
+ return uv__set_artificial_error(handle->loop, UV_EINVAL); \
+ \
old_head = loop->name##_handles; \
\
handle->name##_next = old_head; \
}
-void uv_tty_reset_mode() {
+void uv_tty_reset_mode(void) {
/* Not necessary to do anything. */
;
}
#define CONCURRENT_CALLS 10
#define TOTAL_CALLS 10000
-const char* name = "localhost";
+static const char* name = "localhost";
static uv_loop_t* loop;
BENCHMARK_DECLARE (async_pummel_8)
BENCHMARK_DECLARE (spawn)
BENCHMARK_DECLARE (thread_create)
+BENCHMARK_DECLARE (million_async)
BENCHMARK_DECLARE (million_timers)
HELPER_DECLARE (tcp4_blackhole_server)
HELPER_DECLARE (tcp_pump_server)
BENCHMARK_ENTRY (spawn)
BENCHMARK_ENTRY (thread_create)
+ BENCHMARK_ENTRY (million_async)
BENCHMARK_ENTRY (million_timers)
TASK_LIST_END
--- /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 "task.h"
+#include "uv.h"
+
+struct async_container {
+ unsigned async_events;
+ unsigned handles_seen;
+ uv_async_t async_handles[1024 * 1024];
+};
+
+static volatile int done;
+static uv_thread_t thread_id;
+static struct async_container* container;
+
+
+static unsigned fastrand(void) {
+ static unsigned g = 0;
+ g = g * 214013 + 2531011;
+ return g;
+}
+
+
+static void thread_cb(void* arg) {
+ unsigned i;
+
+ while (done == 0) {
+ i = fastrand() % ARRAY_SIZE(container->async_handles);
+ uv_async_send(container->async_handles + i);
+ }
+}
+
+
+static void async_cb(uv_async_t* handle, int status) {
+ container->async_events++;
+ handle->data = handle;
+}
+
+
+static void timer_cb(uv_timer_t* handle, int status) {
+ unsigned i;
+
+ done = 1;
+ ASSERT(0 == uv_thread_join(&thread_id));
+
+ for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) {
+ uv_async_t* handle = container->async_handles + i;
+
+ if (handle->data != NULL)
+ container->handles_seen++;
+
+ uv_close((uv_handle_t*) handle, NULL);
+ }
+
+ uv_close((uv_handle_t*) handle, NULL);
+}
+
+
+BENCHMARK_IMPL(million_async) {
+ uv_timer_t timer_handle;
+ uv_async_t* handle;
+ uv_loop_t* loop;
+ int timeout;
+ unsigned i;
+
+ loop = uv_default_loop();
+ timeout = 5000;
+
+ container = malloc(sizeof(*container));
+ ASSERT(container != NULL);
+ container->async_events = 0;
+ container->handles_seen = 0;
+
+ for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) {
+ handle = container->async_handles + i;
+ ASSERT(0 == uv_async_init(loop, handle, async_cb));
+ handle->data = NULL;
+ }
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, timeout, 0));
+ ASSERT(0 == uv_thread_create(&thread_id, thread_cb, NULL));
+ ASSERT(0 == uv_run(loop));
+ printf("%s async events in %.1f seconds (%s/s, %s unique handles seen)\n",
+ fmt(container->async_events),
+ timeout / 1000.,
+ fmt(container->async_events / (timeout / 1000.)),
+ fmt(container->handles_seen));
+ free(container);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
}
-static void pinger_new() {
+static void pinger_new(void) {
int r;
struct sockaddr_in client_addr = uv_ip4_addr("0.0.0.0", 0);
struct sockaddr_in server_addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
}
-static void read_show_stats() {
+static void read_show_stats(void) {
int64_t diff;
uv_update_time(loop);
-void write_sockets_close_cb(uv_handle_t* handle) {
- /* If any client closes, the process is done. */
- exit(0);
-}
-
-
-void read_sockets_close_cb(uv_handle_t* handle) {
+static void read_sockets_close_cb(uv_handle_t* handle) {
free(handle);
read_sockets--;
}
-static void start_stats_collection() {
+static void start_stats_collection(void) {
int r;
/* Show-stats timer */
}
-static void maybe_connect_some() {
+static void maybe_connect_some(void) {
uv_connect_t* req;
uv_tcp_t* tcp;
uv_pipe_t* pipe;
static req_list_t* req_freelist = NULL;
-static uv_req_t* req_alloc() {
+static uv_req_t* req_alloc(void) {
req_list_t* req;
req = req_freelist;
}
-void tcp_pump(int n) {
+static void tcp_pump(int n) {
ASSERT(n <= MAX_WRITE_HANDLES);
TARGET_CONNECTIONS = n;
type = TCP;
}
-void pipe_pump(int n) {
+static void pipe_pump(int n) {
ASSERT(n <= MAX_WRITE_HANDLES);
TARGET_CONNECTIONS = n;
type = PIPE;
static int pipe_open;
-static void spawn();
+static void spawn(void);
-void maybe_spawn() {
+static void maybe_spawn(void) {
if (process_open == 0 && pipe_open == 0) {
done++;
if (done < N) {
}
-uv_buf_t on_alloc(uv_handle_t* handle, size_t suggested_size) {
+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;
}
-void pipe_close_cb(uv_handle_t* pipe) {
+static void pipe_close_cb(uv_handle_t* pipe) {
ASSERT(pipe_open == 1);
pipe_open = 0;
maybe_spawn();
}
-void on_read(uv_stream_t* pipe, ssize_t nread, uv_buf_t buf) {
+static void on_read(uv_stream_t* pipe, ssize_t nread, uv_buf_t buf) {
uv_err_t err = uv_last_error(loop);
if (nread > 0) {
}
-static void spawn() {
+static void spawn(void) {
uv_stdio_container_t stdio[2];
int r;
#define LEN_OFFSET 0
#define QUERYID_OFFSET 2
-unsigned char DNSRsp[] = {0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0 };
-unsigned char qrecord[] = {5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1};
-unsigned char arecord[] = {0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1 };
+
+static unsigned char DNSRsp[] = {
+ 0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0
+};
+
+static unsigned char qrecord[] = {
+ 5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1
+};
+
+static unsigned char arecord[] = {
+ 0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1
+};
static void after_write(uv_write_t* req, int status) {
/* Move the console cursor one line up and back to the first column. */
-void rewind_cursor() {
+void rewind_cursor(void) {
fprintf(stderr, "\033[2K\r");
}
const char* fmt(double d) {
+ static char buf[1024];
+ static char* p;
uint64_t v;
- char* p;
- p = (char *) calloc(1, 32) + 31; /* leaks memory */
+ if (p == NULL)
+ p = buf;
+
+ p += 31;
+
+ if (p >= buf + sizeof(buf))
+ return "<buffer too small>";
+
v = (uint64_t) d;
#if 0 /* works but we don't care about fractional precision */
typedef struct {
char *task_name;
char *process_name;
- int (*main)();
+ int (*main)(void);
int is_helper;
int show_output;
} task_entry_t, bench_entry_t;
};
#define TEST_DECLARE(name) \
- int run_test_##name();
+ int run_test_##name(void);
#define TEST_ENTRY(name) \
{ #name, #name, &run_test_##name, 0, 0 },
{ #name, #name, &run_test_##name, 0, 1 },
#define BENCHMARK_DECLARE(name) \
- int run_benchmark_##name();
+ int run_benchmark_##name(void);
#define BENCHMARK_ENTRY(name) \
{ #name, #name, &run_benchmark_##name, 0, 0 },
#define HELPER_DECLARE(name) \
- int run_helper_##name();
+ int run_helper_##name(void);
#define HELPER_ENTRY(task_name, name) \
{ #task_name, #name, &run_helper_##name, 1, 0 },
*/
/* Do platform-specific initialization. */
-void platform_init();
+void platform_init(int argc, char** argv);
/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */
/* Make sure that all stdio output of the processes is buffered up. */
void process_cleanup(process_info_t *p);
/* Move the console cursor one line up and back to the first column. */
-void rewind_cursor();
+void rewind_cursor(void);
#endif /* RUNNER_H_ */
abort(); \
} while (0)
-
-
/* Have our own assert, so we are sure it does not get optimized away in
* a release build.
*/
uv_loop_delete(uv_default_loop())
/* Just sugar for wrapping the main() for a task or helper. */
-#define TEST_IMPL(name) \
- int run_test_##name()
-
-#define BENCHMARK_IMPL(name) \
- int run_benchmark_##name()
+#define TEST_IMPL(name) \
+ int run_test_##name(void); \
+ int run_test_##name(void)
-#define HELPER_IMPL(name) \
- int run_helper_##name()
+#define BENCHMARK_IMPL(name) \
+ int run_benchmark_##name(void); \
+ int run_benchmark_##name(void)
+#define HELPER_IMPL(name) \
+ int run_helper_##name(void); \
+ int run_helper_##name(void)
/* Pause the calling thread for a number of milliseconds. */
void uv_sleep(int msec);
static int close_cb_called;
-void thread_cb(void *arg) {
+static void thread_cb(void *arg) {
int n;
int r;
+++ /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 "task.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#define MAX_CONSUMERS 32
-#define MAX_LOOPS 1000
-
-struct buffer_s {
- ngx_queue_t queue;
- int data;
-};
-typedef struct buffer_s buffer_t;
-
-static ngx_queue_t queue;
-static uv_mutex_t mutex;
-static uv_cond_t empty;
-static uv_cond_t full;
-
-static volatile int finished_consumers = 0;
-
-
-static void produce(int value) {
- buffer_t* buf;
-
- buf = malloc(sizeof(*buf));
- ngx_queue_init(&buf->queue);
- buf->data = value;
- ngx_queue_insert_tail(&queue, &buf->queue);
-}
-
-
-static int consume(void) {
- ngx_queue_t* q;
- buffer_t* buf;
- int data;
-
- ASSERT(!ngx_queue_empty(&queue));
- q = ngx_queue_last(&queue);
- ngx_queue_remove(q);
-
- buf = ngx_queue_data(q, buffer_t, queue);
- data = buf->data;
- free(buf);
-
- return data;
-}
-
-
-static void producer(void* arg) {
- int i;
-
- (void) arg;
-
- for (i = 0; i < MAX_LOOPS * MAX_CONSUMERS; i++) {
- uv_mutex_lock(&mutex);
- while(!ngx_queue_empty(&queue))
- uv_cond_wait(&empty, &mutex);
- produce(i);
- uv_cond_signal(&full);
- uv_mutex_unlock(&mutex);
- }
-}
-
-
-static void consumer(void* arg) {
- int i;
- int value;
-
- (void) arg;
-
- for (i = 0; i < MAX_LOOPS; i++) {
- uv_mutex_lock(&mutex);
- while (ngx_queue_empty(&queue))
- uv_cond_wait(&full, &mutex);
- value = consume();
- ASSERT(value < MAX_LOOPS * MAX_CONSUMERS);
- uv_cond_signal(&empty);
- uv_mutex_unlock(&mutex);
- }
-
- finished_consumers++;
-}
-
-
-TEST_IMPL(consumer_producer) {
- int i;
- uv_thread_t cthreads[MAX_CONSUMERS];
- uv_thread_t pthread;
-
- ngx_queue_init(&queue);
- ASSERT(0 == uv_mutex_init(&mutex));
- ASSERT(0 == uv_cond_init(&empty));
- ASSERT(0 == uv_cond_init(&full));
-
- for (i = 0; i < MAX_CONSUMERS; i++) {
- ASSERT(0 == uv_thread_create(&cthreads[i], consumer, NULL));
- }
-
- ASSERT(0 == uv_thread_create(&pthread, producer, NULL));
-
- for (i = 0; i < MAX_CONSUMERS; i++) {
- ASSERT(0 == uv_thread_join(&cthreads[i]));
- }
-
- ASSERT(0 == uv_thread_join(&pthread));
-
- LOGF("finished_consumers: %d\n", finished_consumers);
- ASSERT(finished_consumers == MAX_CONSUMERS);
-
- uv_cond_destroy(&empty);
- uv_cond_destroy(&full);
- uv_mutex_destroy(&mutex);
-
- return 0;
-}
}
-void connection_fail(uv_connect_cb connect_cb) {
+static void connection_fail(uv_connect_cb connect_cb) {
struct sockaddr_in client_addr, server_addr;
int r;
}
-static void start_server() {
+static void start_server(void) {
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", TEST_PORT);
uv_tcp_t* server = (uv_tcp_t*)malloc(sizeof *server);
int r;
}
-static void client_connect() {
+static void client_connect(void) {
struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof *client);
uv_connect_t* connect_req = malloc(sizeof *connect_req);
#include <errno.h>
#ifndef HAVE_KQUEUE
-# if __APPLE__ || __DragonFly__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__
+# if defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
# define HAVE_KQUEUE 1
# endif
#endif
static void embed_cb(uv_async_t* async, int status) {
- uv_run_once(uv_default_loop());
+ uv_run2(uv_default_loop(), UV_RUN_ONCE);
uv_sem_post(&embed_sem);
}
#include <fcntl.h>
#ifndef HAVE_KQUEUE
-# if __APPLE__ || __DragonFly__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__
+# if defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
# define HAVE_KQUEUE 1
# endif
#endif
return 0;
}
-#if HAVE_KQUEUE
+#if defined(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
static char test_buf[] = "test-buffer\n";
-void check_permission(const char* filename, int mode) {
+static void check_permission(const char* filename, int mode) {
int r;
uv_fs_t req;
struct stat* s;
}
-static int tcp_listener() {
+static int tcp_listener(void) {
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", server_port);
struct sockaddr sockname, peername;
int namelen;
}
-static void tcp_connector() {
+static void tcp_connector(void) {
struct sockaddr_in server_addr = uv_ip4_addr("127.0.0.1", server_port);
struct sockaddr sockname;
int r, namelen;
}
-static int udp_listener() {
+static int udp_listener(void) {
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", server_port);
struct sockaddr sockname;
int namelen;
}
-static void make_many_connections() {
+static void make_many_connections(void) {
tcp_conn* conn;
struct sockaddr_in addr;
int r, i;
/* Everything here runs in a child process. */
-tcp_conn conn;
+static tcp_conn conn;
static void close_cb(uv_handle_t* handle) {
}
-int ipc_helper_tcp_connection() {
+int ipc_helper_tcp_connection(void) {
/*
* This is launched from test-ipc.c. stdin is a duplex channel that we
* over which a handle will be transmitted.
TEST_DECLARE (platform_output)
TEST_DECLARE (callback_order)
TEST_DECLARE (run_once)
+TEST_DECLARE (run_nowait)
TEST_DECLARE (barrier_1)
TEST_DECLARE (barrier_2)
TEST_DECLARE (barrier_3)
TEST_DECLARE (condvar_3)
TEST_DECLARE (condvar_4)
TEST_DECLARE (condvar_5)
-TEST_DECLARE (consumer_producer)
TEST_DECLARE (semaphore_1)
TEST_DECLARE (semaphore_2)
TEST_DECLARE (semaphore_3)
TEST_DECLARE (threadpool_cancel_getaddrinfo)
TEST_DECLARE (threadpool_cancel_work)
TEST_DECLARE (threadpool_cancel_fs)
+TEST_DECLARE (threadpool_cancel_single)
TEST_DECLARE (thread_mutex)
TEST_DECLARE (thread_rwlock)
TEST_DECLARE (thread_create)
TEST_ENTRY (callback_order)
#endif
TEST_ENTRY (run_once)
+ TEST_ENTRY (run_nowait)
TEST_ENTRY (barrier_1)
TEST_ENTRY (barrier_2)
TEST_ENTRY (barrier_3)
TEST_ENTRY (condvar_3)
TEST_ENTRY (condvar_4)
TEST_ENTRY (condvar_5)
- TEST_ENTRY (consumer_producer)
TEST_ENTRY (semaphore_1)
TEST_ENTRY (semaphore_2)
TEST_ENTRY (semaphore_3)
TEST_ENTRY (threadpool_cancel_getaddrinfo)
TEST_ENTRY (threadpool_cancel_work)
TEST_ENTRY (threadpool_cancel_fs)
+ TEST_ENTRY (threadpool_cancel_single)
TEST_ENTRY (thread_mutex)
TEST_ENTRY (thread_rwlock)
TEST_ENTRY (thread_create)
}
-static void start_server() {
+static void start_server(void) {
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", TEST_PORT);
int r;
}
-static void client_connect() {
+static void client_connect(void) {
struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
uv_connect_t* connect_req = malloc(sizeof *connect_req);
int r;
char read_buffer[BUFSIZE];
} pinger_t;
-void pinger_try_read(pinger_t* pinger);
-
static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) {
return uv_buf_init(malloc(size), size);
/* same ping-pong test, but using IPv6 connection */
-static void tcp_pinger_v6_new() {
+static void tcp_pinger_v6_new(void) {
int r;
struct sockaddr_in6 server_addr = uv_ip6_addr("::1", TEST_PORT);
pinger_t *pinger;
}
-static void tcp_pinger_new() {
+static void tcp_pinger_new(void) {
int r;
struct sockaddr_in server_addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
pinger_t *pinger;
}
-static void pipe_pinger_new() {
+static void pipe_pinger_new(void) {
int r;
pinger_t *pinger;
static int spurious_writable_wakeups = 0;
-static int got_eagain() {
+static int got_eagain(void) {
#ifdef _WIN32
return WSAGetLastError() == WSAEWOULDBLOCK;
#else
}
-static void start_server() {
+static void start_server(void) {
uv_os_sock_t sock;
server_context_t* context;
int r;
}
-static void start_client() {
+static void start_client(void) {
uv_os_sock_t sock;
connection_context_t* context;
struct sockaddr_in server_addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
}
-static void start_poll_test() {
+static void start_poll_test(void) {
int i, r;
#ifdef _WIN32
}
+static void fail_cb2(void) {
+ ASSERT(0 && "fail_cb2 should not have been called");
+}
+
+
static void req_cb(uv_handle_t* req, int status) {
req_cb_called++;
}
TEST_IMPL(idle_ref) {
uv_idle_t h;
uv_idle_init(uv_default_loop(), &h);
- uv_idle_start(&h, NULL);
+ uv_idle_start(&h, (uv_idle_cb) fail_cb2);
uv_unref((uv_handle_t*)&h);
uv_run(uv_default_loop());
do_close(&h);
TEST_IMPL(prepare_ref) {
uv_prepare_t h;
uv_prepare_init(uv_default_loop(), &h);
- uv_prepare_start(&h, NULL);
+ uv_prepare_start(&h, (uv_prepare_cb) fail_cb2);
uv_unref((uv_handle_t*)&h);
uv_run(uv_default_loop());
do_close(&h);
TEST_IMPL(check_ref) {
uv_check_t h;
uv_check_init(uv_default_loop(), &h);
- uv_check_start(&h, NULL);
+ uv_check_start(&h, (uv_check_cb) fail_cb2);
uv_unref((uv_handle_t*)&h);
uv_run(uv_default_loop());
do_close(&h);
}
-static void tcp_ref2b_close_cb(uv_handle_t* handle) {
- (*(int*) handle->data)++;
-}
-
-
TEST_IMPL(tcp_ref2b) {
- int close_cb_called = 0;
uv_tcp_t h;
- h.data = &close_cb_called;
uv_tcp_init(uv_default_loop(), &h);
uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
uv_unref((uv_handle_t*)&h);
- uv_close((uv_handle_t*)&h, tcp_ref2b_close_cb);
+ uv_close((uv_handle_t*)&h, close_cb);
uv_run(uv_default_loop());
ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
--- /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 "task.h"
+
+static uv_timer_t timer_handle;
+static int timer_called = 0;
+
+
+static void timer_cb(uv_timer_t* handle, int status) {
+ ASSERT(handle == &timer_handle);
+ ASSERT(status == 0);
+ timer_called = 1;
+}
+
+
+TEST_IMPL(run_nowait) {
+ int r;
+ uv_timer_init(uv_default_loop(), &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 100);
+
+ r = uv_run2(uv_default_loop(), UV_RUN_NOWAIT);
+ ASSERT(r != 0);
+ ASSERT(timer_called == 0);
+
+ return 0;
+}
uv_idle_init(uv_default_loop(), &idle_handle);
uv_idle_start(&idle_handle, idle_cb);
- while (uv_run_once(uv_default_loop()));
+ while (uv_run2(uv_default_loop(), UV_RUN_ONCE));
ASSERT(idle_counter == NUM_TICKS);
MAKE_VALGRIND_HAPPY();
}
-void tcp_close_cb(uv_handle_t* handle) {
+static void tcp_close_cb(uv_handle_t* handle) {
ASSERT(handle == (uv_handle_t*) &tcp);
ASSERT(called_connect_cb == 1);
}
-void timer_close_cb(uv_handle_t* handle) {
+static void timer_close_cb(uv_handle_t* handle) {
ASSERT(handle == (uv_handle_t*) &timer);
called_timer_close_cb++;
}
-void timer_cb(uv_timer_t* handle, int status) {
+static void timer_cb(uv_timer_t* handle, int status) {
ASSERT(handle == &timer);
uv_close((uv_handle_t*) handle, timer_close_cb);
}
-void on_read(uv_stream_t* tcp, ssize_t nread, uv_buf_t buf) {
+static void on_read(uv_stream_t* tcp, ssize_t nread, uv_buf_t buf) {
uv_err_t err = uv_last_error(uv_default_loop());
if (nread > 0) {
}
-void write_cb(uv_write_t* req, int status) {
+static void write_cb(uv_write_t* req, int status) {
ASSERT(status == 0);
uv_close((uv_handle_t*)req->handle, close_cb);
}
static int exit_cb_called;
static int on_read_cb_called;
static int after_write_cb_called;
-uv_pipe_t out, in;
+static uv_pipe_t in;
+static uv_pipe_t out;
static uv_loop_t* loop;
#define OUTPUT_SIZE 1024
static char output[OUTPUT_SIZE];
}
-int stdio_over_pipes_helper() {
+int stdio_over_pipes_helper(void) {
/* Write several buffers to test that the write order is preserved. */
char* buffers[] = {
"he",
}
+static void nop_work_cb(uv_work_t* req) {
+}
+
+
+static void nop_done_cb(uv_work_t* req, int status) {
+ req->data = "OK";
+}
+
+
TEST_IMPL(threadpool_cancel_getaddrinfo) {
uv_getaddrinfo_t reqs[4];
struct cancel_info ci;
return 0;
}
+
+
+TEST_IMPL(threadpool_cancel_single) {
+ uv_loop_t* loop;
+ uv_work_t req;
+ int cancelled;
+ int i;
+
+ loop = uv_default_loop();
+ for (i = 0; i < 5000; i++) {
+ req.data = NULL;
+ ASSERT(0 == uv_queue_work(loop, &req, nop_work_cb, nop_done_cb));
+
+ cancelled = uv_cancel((uv_req_t*) &req);
+ if (cancelled == 0)
+ break;
+
+ ASSERT(0 == uv_run(loop));
+ }
+
+ if (cancelled != 0) {
+ fputs("Failed to cancel a work req in 5,000 iterations, giving up.\n",
+ stderr);
+ return 1;
+ }
+
+ ASSERT(req.data == NULL);
+ ASSERT(0 == uv_run(loop));
+ ASSERT(req.data != NULL); /* Should have been updated by nop_done_cb(). */
+
+ return 0;
+}
'include_dirs': [ 'include' ],
'conditions': [
['OS != "win"', {
- 'defines': [ '_LARGEFILE_SOURCE', '_FILE_OFFSET_BITS=64' ],
+ 'defines': [
+ '_LARGEFILE_SOURCE',
+ '_FILE_OFFSET_BITS=64',
+ '_POSIX_C_SOURCE=200112',
+ ],
}],
['OS == "mac"', {
- 'defines': [ '_DARWIN_USE_64_BIT_INODE=1' ],
+ 'defines': [
+ '_DARWIN_USE_64_BIT_INODE=1',
+ '_DARWIN_C_SOURCE', # _POSIX_C_SOURCE hides SysV definitions.
+ ],
}],
],
},
'test/test-poll-close.c',
'test/test-process-title.c',
'test/test-ref.c',
+ 'test/test-run-nowait.c',
'test/test-run-once.c',
'test/test-semaphore.c',
'test/test-shutdown-close.c',
'test/test-thread.c',
'test/test-barrier.c',
'test/test-condvar.c',
- 'test/test-condvar-consumer-producer.c',
'test/test-timer-again.c',
'test/test-timer.c',
'test/test-tty.c',
'test/benchmark-getaddrinfo.c',
'test/benchmark-list.h',
'test/benchmark-loop-count.c',
+ 'test/benchmark-million-async.c',
'test/benchmark-million-timers.c',
'test/benchmark-multi-accept.c',
'test/benchmark-ping-pongs.c',