test/test-ipc.o \
test/test-ipc-send-recv.o \
test/test-loop-handles.o \
+ test/test-loop-stop.o \
test/test-multiple-listen.o \
test/test-mutexes.o \
test/test-pass-always.o \
},
'Release': {
'defines': [ 'NDEBUG' ],
- 'cflags': [ '-O3', '-fomit-frame-pointer', '-fdata-sections', '-ffunction-sections' ],
+ 'cflags': [
+ '-O3',
+ '-fstrict-aliasing',
+ '-fomit-frame-pointer',
+ '-fdata-sections',
+ '-ffunction-sections',
+ ],
'msvs_settings': {
'VCCLCompilerTool': {
'target_conditions': [
'PREBINDING': 'NO', # No -Wl,-prebind
'USE_HEADERMAP': 'NO',
'OTHER_CFLAGS': [
- '-fno-strict-aliasing',
+ '-fstrict-aliasing',
],
'WARNING_CFLAGS': [
'-Wall',
# include "uv-bsd.h"
#endif
-struct uv__io_s;
-struct uv_loop_s;
-
#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS
# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */
#endif
#define UV_IO_PRIVATE_FIELDS \
UV_IO_PRIVATE_PLATFORM_FIELDS \
+struct uv__io_s;
+struct uv__async;
+struct uv_loop_s;
+
typedef void (*uv__io_cb)(struct uv_loop_s* loop,
struct uv__io_s* w,
unsigned int events);
UV_IO_PRIVATE_FIELDS
};
+typedef void (*uv__async_cb)(struct uv_loop_s* loop,
+ struct uv__async* w,
+ unsigned int nevents);
+
+struct uv__async {
+ uv__async_cb cb;
+ uv__io_t io_watcher;
+ int wfd;
+};
+
struct uv__work {
void (*work)(struct uv__work *w);
void (*done)(struct uv__work *w, int status);
ngx_queue_t check_handles; \
ngx_queue_t idle_handles; \
ngx_queue_t async_handles; \
- uv__io_t async_watcher; \
- int async_pipefd[2]; \
+ struct uv__async async_watcher; \
/* RB_HEAD(uv__timers, uv_timer_s) */ \
struct uv__timers { \
struct uv_timer_s* rbh_root; \
ngx_queue_t queue;
#define UV_ASYNC_PRIVATE_FIELDS \
- volatile sig_atomic_t pending; \
uv_async_cb async_cb; \
- ngx_queue_t queue;
+ ngx_queue_t queue; \
+ int pending; \
#define UV_TIMER_PRIVATE_FIELDS \
/* RB_ENTRY(uv_timer_s) tree_entry; */ \
*/
UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
+/*
+ * This function will stop the event loop by forcing uv_run to end
+ * as soon as possible, but not sooner than the next loop iteration.
+ * If this function was called before blocking for i/o, the loop won't
+ * block for i/o on this iteration.
+ */
+UV_EXTERN void uv_stop(uv_loop_t*);
+
/*
* Manually modify the event loop's reference count. Useful if the user wants
* to have a handle or timeout that doesn't keep the loop alive.
unsigned int active_handles;
ngx_queue_t handle_queue;
ngx_queue_t active_reqs;
+ /* Internal flag to signal loop stop */
+ unsigned int stop_flag;
UV_LOOP_PRIVATE_FIELDS
};
* IN THE SOFTWARE.
*/
+/* This file contains both the uv__async internal infrastructure and the
+ * user-facing uv_async_t functions.
+ */
+
#include "uv.h"
#include "internal.h"
#include <errno.h>
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-static int uv__async_init(uv_loop_t* loop);
-static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+static void uv__async_event(uv_loop_t* loop,
+ struct uv__async* w,
+ unsigned int nevents);
+static int uv__async_make_pending(int* pending);
+static int uv__async_eventfd(void);
+
+
+int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
+ if (uv__async_start(loop, &loop->async_watcher, uv__async_event))
+ return uv__set_sys_error(loop, errno);
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
+ handle->async_cb = async_cb;
+ handle->pending = 0;
+
+ ngx_queue_insert_tail(&loop->async_handles, &handle->queue);
+ uv__handle_start(handle);
+
+ return 0;
+}
-static int uv__async_make_pending(volatile sig_atomic_t* ptr) {
+
+int uv_async_send(uv_async_t* handle) {
+ if (uv__async_make_pending(&handle->pending) == 0)
+ uv__async_send(&handle->loop->async_watcher);
+
+ return 0;
+}
+
+
+void uv__async_close(uv_async_t* handle) {
+ ngx_queue_remove(&handle->queue);
+ uv__handle_stop(handle);
+}
+
+
+static void uv__async_event(uv_loop_t* loop,
+ struct uv__async* w,
+ unsigned int nevents) {
+ ngx_queue_t* q;
+ uv_async_t* h;
+
+ ngx_queue_foreach(q, &loop->async_handles) {
+ h = ngx_queue_data(q, uv_async_t, queue);
+ if (!h->pending) continue;
+ h->pending = 0;
+ h->async_cb(h, 0);
+ }
+}
+
+
+static int uv__async_make_pending(int* pending) {
/* Do a cheap read first. */
- if (*ptr)
+ if (ACCESS_ONCE(int, *pending) != 0)
return 1;
/* Micro-optimization: use atomic memory operations to detect if we've been
#if defined(__i386__) || defined(__x86_64__)
{
unsigned int val = 1;
- __asm__ __volatile__("xchgl %0, %1" : "+r" (val) : "m" (*ptr));
+ __asm__ __volatile__ ("xchgl %0, %1"
+ : "+r" (val)
+ : "m" (*pending));
return val != 0;
}
#elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 0)
- return __sync_val_compare_and_swap(ptr, 0, 1) != 0;
+ return __sync_val_compare_and_swap(pending, 0, 1) != 0;
#else
- *ptr = 1;
+ ACCESS_ONCE(int, *pending) = 1;
return 0;
#endif
}
-int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
- if (uv__async_init(loop))
- return uv__set_sys_error(loop, errno);
+static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ struct uv__async* wa;
+ char buf[1024];
+ unsigned n;
+ ssize_t r;
- uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
- handle->async_cb = async_cb;
- handle->pending = 0;
+ n = 0;
+ for (;;) {
+ r = read(w->fd, buf, sizeof(buf));
- ngx_queue_insert_tail(&loop->async_handles, &handle->queue);
- uv__handle_start(handle);
+ if (r > 0)
+ n += r;
- return 0;
+ if (r == sizeof(buf))
+ continue;
+
+ if (r != -1)
+ break;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ abort();
+ }
+
+ wa = container_of(w, struct uv__async, io_watcher);
+
+#if defined(__linux__)
+ if (wa->wfd == -1) {
+ uint64_t val;
+ assert(n == sizeof(val));
+ memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */
+ wa->cb(loop, wa, val);
+ return;
+ }
+#endif
+
+ wa->cb(loop, wa, n);
}
-int uv_async_send(uv_async_t* handle) {
+void uv__async_send(struct uv__async* wa) {
+ const void* buf;
+ ssize_t len;
+ int fd;
int r;
- if (uv__async_make_pending(&handle->pending))
- return 0; /* already pending */
+ buf = "";
+ len = 1;
+ fd = wa->wfd;
+
+#if defined(__linux__)
+ if (fd == -1) {
+ static const uint64_t val = 1;
+ buf = &val;
+ len = sizeof(val);
+ fd = wa->io_watcher.fd; /* eventfd */
+ }
+#endif
do
- r = write(handle->loop->async_pipefd[1], "x", 1);
+ r = write(fd, buf, len);
while (r == -1 && errno == EINTR);
- assert(r == -1 || r == 1);
+ if (r == len)
+ return;
- if (r == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
- return uv__set_sys_error(handle->loop, errno);
+ if (r == -1)
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return;
- return 0;
+ abort();
}
-void uv__async_close(uv_async_t* handle) {
- ngx_queue_remove(&handle->queue);
- uv__handle_stop(handle);
+void uv__async_init(struct uv__async* wa) {
+ wa->io_watcher.fd = -1;
+ wa->wfd = -1;
}
-static int uv__async_init(uv_loop_t* loop) {
- if (loop->async_pipefd[0] != -1)
+int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) {
+ int pipefd[2];
+ int fd;
+
+ if (wa->io_watcher.fd != -1)
return 0;
- if (uv__make_pipe(loop->async_pipefd, UV__F_NONBLOCK))
+ fd = uv__async_eventfd();
+ if (fd >= 0) {
+ pipefd[0] = fd;
+ pipefd[1] = -1;
+ }
+ else if (fd != -ENOSYS)
+ return -1;
+ else if (uv__make_pipe(pipefd, UV__F_NONBLOCK))
return -1;
- uv__io_init(&loop->async_watcher, uv__async_io, loop->async_pipefd[0]);
- uv__io_start(loop, &loop->async_watcher, UV__POLLIN);
+ uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]);
+ uv__io_start(loop, &wa->io_watcher, UV__POLLIN);
+ wa->wfd = pipefd[1];
+ wa->cb = cb;
return 0;
}
-static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- char buf[1024];
- ngx_queue_t* q;
- uv_async_t* h;
- ssize_t r;
+void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) {
+ if (wa->io_watcher.fd == -1)
+ return;
- while (1) {
- r = read(loop->async_pipefd[0], buf, sizeof(buf));
+ uv__io_stop(loop, &wa->io_watcher, UV__POLLIN);
+ close(wa->io_watcher.fd);
+ wa->io_watcher.fd = -1;
- if (r == sizeof(buf))
- continue;
+ if (wa->wfd != -1) {
+ close(wa->wfd);
+ wa->wfd = -1;
+ }
+}
- if (r != -1)
- break;
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- break;
+static int uv__async_eventfd() {
+#if defined(__linux__)
+ static int no_eventfd2;
+ static int no_eventfd;
+ int fd;
- if (errno == EINTR)
- continue;
+ if (no_eventfd2)
+ goto skip_eventfd2;
- abort();
- }
+ fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
+ if (fd != -1)
+ return fd;
- ngx_queue_foreach(q, &loop->async_handles) {
- h = ngx_queue_data(q, uv_async_t, queue);
- if (!h->pending) continue;
- h->pending = 0;
- h->async_cb(h, 0);
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_eventfd2 = 1;
+
+skip_eventfd2:
+
+ if (no_eventfd)
+ goto skip_eventfd;
+
+ fd = uv__eventfd(0);
+ if (fd != -1) {
+ uv__cloexec(fd, 1);
+ uv__nonblock(fd, 1);
+ return fd;
}
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_eventfd = 1;
+
+skip_eventfd:
+
+#endif
+
+ return -ENOSYS;
}
int uv_backend_timeout(const uv_loop_t* loop) {
+ if (loop->stop_flag != 0)
+ return 0;
+
if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
return 0;
int uv_run(uv_loop_t* loop, uv_run_mode mode) {
+ int timeout;
int r;
- if (!uv__loop_alive(loop))
- return 0;
-
- do {
+ r = uv__loop_alive(loop);
+ while (r != 0 && loop->stop_flag == 0) {
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)));
+
+ timeout = 0;
+ if ((mode & UV_RUN_NOWAIT) == 0)
+ timeout = uv_backend_timeout(loop);
+
+ uv__io_poll(loop, timeout);
uv__run_check(loop);
uv__run_closing_handles(loop);
r = uv__loop_alive(loop);
- } while (r && !(mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)));
+
+ if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
+ break;
+ }
+
+ /* The if statement lets gcc compile it to a conditional store. Avoids
+ * dirtying a cache line.
+ */
+ if (loop->stop_flag != 0)
+ loop->stop_flag = 0;
return r;
}
while (n == -1 && errno == EINTR);
if (n == -1 || (pfd.revents & ~POLLOUT) != 0) {
+ errno = EIO;
nsent = -1;
goto out;
}
# include <CoreServices/CoreServices.h>
#endif
+#define ACCESS_ONCE(type, var) \
+ (*(volatile type*) &(var))
+
#define UNREACHABLE() \
do { \
assert(0 && "unreachable code"); \
int uv__cloexec(int fd, int set);
int uv__socket(int domain, int type, int protocol);
int uv__dup(int fd);
-int uv_async_stop(uv_async_t* handle);
void uv__make_close_pending(uv_handle_t* handle);
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
int uv__io_active(const uv__io_t* w, unsigned int events);
void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
+/* async */
+void uv__async_send(struct uv__async* wa);
+void uv__async_init(struct uv__async* wa);
+int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb);
+void uv__async_stop(uv_loop_t* loop, struct uv__async* wa);
+
/* loop */
int uv__loop_init(uv_loop_t* loop, int default_loop);
void uv__loop_delete(uv_loop_t* loop);
loop->closing_handles = NULL;
loop->time = uv__hrtime() / 1000000;
- loop->async_pipefd[0] = -1;
- loop->async_pipefd[1] = -1;
+ uv__async_init(&loop->async_watcher);
loop->signal_pipefd[0] = -1;
loop->signal_pipefd[1] = -1;
loop->backend_fd = -1;
loop->emfile_fd = -1;
loop->timer_counter = 0;
+ loop->stop_flag = 0;
if (uv__platform_loop_init(loop, default_loop))
return -1;
void uv__loop_delete(uv_loop_t* loop) {
uv__signal_loop_cleanup(loop);
uv__platform_loop_delete(loop);
-
- if (loop->async_pipefd[0] != -1) {
- close(loop->async_pipefd[0]);
- loop->async_pipefd[0] = -1;
- }
-
- if (loop->async_pipefd[1] != -1) {
- close(loop->async_pipefd[1]);
- loop->async_pipefd[1] = -1;
- }
+ uv__async_stop(loop, &loop->async_watcher);
if (loop->emfile_fd != -1) {
close(loop->emfile_fd);
static struct {
char* str;
- int len;
+ size_t len;
} process_title;
char** uv_setup_args(int argc, char** argv) {
char** new_argv;
- char** new_env;
size_t size;
- int envc;
char* s;
int i;
-#if defined(__APPLE__)
- char*** _NSGetArgv(void);
- char*** _NSGetEnviron(void);
- char** environ = *_NSGetEnviron();
-#else
- extern char** environ;
-#endif
-
- for (envc = 0; environ[envc]; envc++);
+ if (argc <= 0)
+ return argv;
- if (envc == 0)
- s = argv[argc - 1];
- else
- s = environ[envc - 1];
+ /* Calculate how much memory we need for the argv strings. */
+ size = 0;
+ for (i = 0; i < argc; i++)
+ size += strlen(argv[i]) + 1;
process_title.str = argv[0];
- process_title.len = s + strlen(s) + 1 - argv[0];
+ process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
+ assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
- size = process_title.len;
- size += (argc + 1) * sizeof(char**);
- size += (envc + 1) * sizeof(char**);
- s = args_mem = malloc(size);
+ /* Add space for the argv pointers. */
+ size += (argc + 1) * sizeof(char*);
- if (s == NULL) {
- process_title.str = NULL;
- process_title.len = 0;
+ new_argv = malloc(size);
+ if (new_argv == NULL)
return argv;
+ args_mem = new_argv;
+
+ /* Copy over the strings and set up the pointer table. */
+ s = (char*) &new_argv[argc + 1];
+ for (i = 0; i < argc; i++) {
+ size = strlen(argv[i]) + 1;
+ memcpy(s, argv[i], size);
+ new_argv[i] = s;
+ s += size;
}
-
- new_argv = (char**) s;
- new_env = new_argv + argc + 1;
- s = (char*) (new_env + envc + 1);
- memcpy(s, process_title.str, process_title.len);
-
- for (i = 0; i < argc; i++)
- new_argv[i] = s + (argv[i] - argv[0]);
- new_argv[argc] = NULL;
-
- s += environ[0] - argv[0];
-
- for (i = 0; i < envc; i++)
- new_env[i] = s + (environ[i] - environ[0]);
- new_env[envc] = NULL;
-
-#if defined(__APPLE__)
- *_NSGetArgv() = new_argv;
- *_NSGetEnviron() = new_env;
-#else
- environ = new_env;
-#endif
+ new_argv[i] = NULL;
return new_argv;
}
if (process_title.len == 0)
return uv_ok_;
- /* No need to terminate, last char is always '\0'. */
- strncpy(process_title.str, title, process_title.len - 1);
+ /* No need to terminate, byte after is always '\0'. */
+ strncpy(process_title.str, title, process_title.len);
uv__set_process_title(title);
return uv_ok_;
static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
static void uv__udp_sendmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain);
-static int uv__udp_send(uv_udp_send_t* req,
- uv_udp_t* handle,
- uv_buf_t bufs[],
- int bufcnt,
- struct sockaddr* addr,
- socklen_t addrlen,
- uv_udp_send_cb send_cb);
+static int uv__send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr* addr,
+ socklen_t addrlen,
+ uv_udp_send_cb send_cb);
void uv__udp_close(uv_udp_t* handle) {
}
-static int uv__udp_send(uv_udp_send_t* req,
- uv_udp_t* handle,
- uv_buf_t bufs[],
- int bufcnt,
- struct sockaddr* addr,
- socklen_t addrlen,
- uv_udp_send_cb send_cb) {
+static int uv__send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr* addr,
+ socklen_t addrlen,
+ uv_udp_send_cb send_cb) {
assert(bufcnt > 0);
if (uv__udp_maybe_deferred_bind(handle, addr->sa_family))
}
-int uv_udp_send(uv_udp_send_t* req,
- uv_udp_t* handle,
- uv_buf_t bufs[],
- int bufcnt,
- struct sockaddr_in addr,
- uv_udp_send_cb send_cb) {
- return uv__udp_send(req,
- handle,
- bufs,
- bufcnt,
- (struct sockaddr*)&addr,
- sizeof addr,
- send_cb);
-}
-
-
-int uv_udp_send6(uv_udp_send_t* req,
+int uv__udp_send(uv_udp_send_t* req,
uv_udp_t* handle,
uv_buf_t bufs[],
int bufcnt,
- struct sockaddr_in6 addr,
+ struct sockaddr_in addr,
uv_udp_send_cb send_cb) {
- return uv__udp_send(req,
- handle,
- bufs,
- bufcnt,
- (struct sockaddr*)&addr,
- sizeof addr,
- send_cb);
+ return uv__send(req,
+ handle,
+ bufs,
+ bufcnt,
+ (struct sockaddr*)&addr,
+ sizeof addr,
+ send_cb);
+}
+
+
+int uv__udp_send6(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr_in6 addr,
+ uv_udp_send_cb send_cb) {
+ return uv__send(req,
+ handle,
+ bufs,
+ bufcnt,
+ (struct sockaddr*)&addr,
+ sizeof addr,
+ send_cb);
}
-int uv_udp_recv_start(uv_udp_t* handle,
- uv_alloc_cb alloc_cb,
- uv_udp_recv_cb recv_cb) {
+int uv__udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
if (alloc_cb == NULL || recv_cb == NULL) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
return -1;
}
-int uv_udp_recv_stop(uv_udp_t* handle) {
+int uv__udp_recv_stop(uv_udp_t* handle) {
uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN);
if (!uv__io_active(&handle->io_watcher, UV__POLLOUT))
}
+int uv_udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr_in addr,
+ uv_udp_send_cb send_cb) {
+ if (handle->type != UV_UDP || addr.sin_family != AF_INET) {
+ return uv__set_artificial_error(handle->loop, UV_EINVAL);
+ }
+
+ return uv__udp_send(req, handle, bufs, bufcnt, addr, send_cb);
+}
+
+
+int uv_udp_send6(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr_in6 addr,
+ uv_udp_send_cb send_cb) {
+ if (handle->type != UV_UDP || addr.sin6_family != AF_INET6) {
+ return uv__set_artificial_error(handle->loop, UV_EINVAL);
+ }
+
+ return uv__udp_send6(req, handle, bufs, bufcnt, addr, send_cb);
+}
+
+
+int uv_udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL) {
+ return uv__set_artificial_error(handle->loop, UV_EINVAL);
+ }
+
+ return uv__udp_recv_start(handle, alloc_cb, recv_cb);
+}
+
+
+int uv_udp_recv_stop(uv_udp_t* handle) {
+ if (handle->type != UV_UDP) {
+ return uv__set_artificial_error(handle->loop, UV_EINVAL);
+ }
+
+ return uv__udp_recv_stop(handle);
+}
+
#ifdef _WIN32
static UINT __stdcall uv__thread_start(void *ctx_v)
#else
void uv_unref(uv_handle_t* handle) {
uv__handle_unref(handle);
}
+
+
+void uv_stop(uv_loop_t* loop) {
+ loop->stop_flag = 1;
+}
struct sockaddr_in6 address,
uv_connect_cb cb);
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr_in addr,
+ uv_udp_send_cb send_cb);
+
+int uv__udp_send6(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ uv_buf_t bufs[],
+ int bufcnt,
+ struct sockaddr_in6 addr,
+ uv_udp_send_cb send_cb);
+
+int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
+ uv_udp_recv_cb recv_cb);
+
+int uv__udp_recv_stop(uv_udp_t* handle);
+
void uv__fs_poll_close(uv_fs_poll_t* handle);
loop->active_udp_streams = 0;
loop->timer_counter = 0;
+ loop->stop_flag = 0;
loop->last_err = uv_ok_;
}
}
}
-#define UV_LOOP_ALIVE(loop) \
- ((loop)->active_handles > 0 || \
- !ngx_queue_empty(&(loop)->active_reqs) || \
- (loop)->endgame_handles != NULL)
+
+static int uv__loop_alive(uv_loop_t* loop) {
+ return loop->active_handles > 0 ||
+ !ngx_queue_empty(&loop->active_reqs) ||
+ loop->endgame_handles != NULL;
+}
+
int uv_run(uv_loop_t *loop, uv_run_mode mode) {
int r;
else
poll = &uv_poll;
- r = UV_LOOP_ALIVE(loop);
- while (r) {
+ if (!uv__loop_alive(loop))
+ return 0;
+
+ r = uv__loop_alive(loop);
+ while (r != 0 && loop->stop_flag == 0) {
uv_update_time(loop);
uv_process_timers(loop);
(*poll)(loop, loop->idle_handles == NULL &&
loop->pending_reqs_tail == NULL &&
loop->endgame_handles == NULL &&
- UV_LOOP_ALIVE(loop) &&
+ !loop->stop_flag &&
+ (loop->active_handles > 0 ||
+ !ngx_queue_empty(&loop->active_reqs)) &&
!(mode & UV_RUN_NOWAIT));
uv_check_invoke(loop);
- r = UV_LOOP_ALIVE(loop);
-
+ r = uv__loop_alive(loop);
if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
break;
}
+
+ /* The if statement lets the compiler compile it to a conditional store.
+ * Avoids dirtying a cache line.
+ */
+ if (loop->stop_flag != 0)
+ loop->stop_flag = 0;
+
return r;
}
}
-int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
+int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
uv_udp_recv_cb recv_cb) {
uv_loop_t* loop = handle->loop;
}
-int uv_udp_recv_stop(uv_udp_t* handle) {
+int uv__udp_recv_stop(uv_udp_t* handle) {
if (handle->flags & UV_HANDLE_READING) {
handle->flags &= ~UV_HANDLE_READING;
handle->loop->active_udp_streams--;
}
-static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
+static int uv__send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
int bufcnt, struct sockaddr* addr, int addr_len, uv_udp_send_cb cb) {
uv_loop_t* loop = handle->loop;
DWORD result, bytes;
}
-int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
+int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
int bufcnt, struct sockaddr_in addr, uv_udp_send_cb cb) {
if (!(handle->flags & UV_HANDLE_BOUND) &&
return -1;
}
- return uv__udp_send(req,
- handle,
- bufs,
- bufcnt,
- (struct sockaddr*) &addr,
- sizeof addr,
- cb);
+ return uv__send(req,
+ handle,
+ bufs,
+ bufcnt,
+ (struct sockaddr*) &addr,
+ sizeof addr,
+ cb);
}
-int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
+int uv__udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
int bufcnt, struct sockaddr_in6 addr, uv_udp_send_cb cb) {
if (!(handle->flags & UV_HANDLE_BOUND) &&
return -1;
}
- return uv__udp_send(req,
- handle,
- bufs,
- bufcnt,
- (struct sockaddr*) &addr,
- sizeof addr,
- cb);
+ return uv__send(req,
+ handle,
+ bufs,
+ bufcnt,
+ (struct sockaddr*) &addr,
+ sizeof addr,
+ cb);
}
continue;
}
- rewind_cursor();
+ if (!tap_output)
+ rewind_cursor();
+
if (!benchmark_output && !tap_output) {
log_progress(total, passed, failed, task->task_name);
}
current++;
}
- rewind_cursor();
+ if (!tap_output)
+ rewind_cursor();
if (!benchmark_output && !tap_output) {
log_progress(total, passed, failed, "Done.\n");
TEST_DECLARE (callback_order)
TEST_DECLARE (run_once)
TEST_DECLARE (run_nowait)
+TEST_DECLARE (loop_stop)
TEST_DECLARE (barrier_1)
TEST_DECLARE (barrier_2)
TEST_DECLARE (barrier_3)
#endif
TEST_ENTRY (run_once)
TEST_ENTRY (run_nowait)
+ TEST_ENTRY (loop_stop)
TEST_ENTRY (barrier_1)
TEST_ENTRY (barrier_2)
TEST_ENTRY (barrier_3)
--- /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_prepare_t prepare_handle;
+static uv_timer_t timer_handle;
+static int prepare_called = 0;
+static int timer_called = 0;
+static int num_ticks = 10;
+
+
+static void prepare_cb(uv_prepare_t* handle, int status) {
+ ASSERT(handle == &prepare_handle);
+ ASSERT(status == 0);
+ prepare_called++;
+ if (prepare_called == num_ticks)
+ uv_prepare_stop(handle);
+}
+
+
+static void timer_cb(uv_timer_t* handle, int status) {
+ ASSERT(handle == &timer_handle);
+ ASSERT(status == 0);
+ timer_called++;
+ if (timer_called == 1)
+ uv_stop(uv_default_loop());
+ else if (timer_called == num_ticks)
+ uv_timer_stop(handle);
+}
+
+
+TEST_IMPL(loop_stop) {
+ int r;
+ uv_prepare_init(uv_default_loop(), &prepare_handle);
+ uv_prepare_start(&prepare_handle, prepare_cb);
+ uv_timer_init(uv_default_loop(), &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 100);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r != 0);
+ ASSERT(timer_called == 1);
+
+ r = uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+ ASSERT(r != 0);
+ ASSERT(prepare_called == 3);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(timer_called == 10);
+ ASSERT(prepare_called == 10);
+
+ return 0;
+}
'-pedantic',
'-Wall',
'-Wextra',
- '-Wno-unused-parameter'
+ '-Wstrict-aliasing',
+ '-Wno-unused-parameter',
],
'sources': [
'include/uv-private/uv-unix.h',
'test/test-ipc-send-recv.c',
'test/test-list.h',
'test/test-loop-handles.c',
+ 'test/test-loop-stop.c',
'test/test-walk-handles.c',
'test/test-multiple-listen.c',
'test/test-pass-always.c',
goto have_gyp
:gyp_install_failed
-echo Failed to download gyp. Make sure you have subversion installed, or
+echo Failed to download gyp. Make sure you have git installed, or
echo manually install gyp into %~dp0build\gyp.
goto exit