summaryrefslogtreecommitdiff
path: root/deps/uv
diff options
context:
space:
mode:
authorBert Belder <bertbelder@gmail.com>2013-05-30 01:09:54 +0200
committerBert Belder <bertbelder@gmail.com>2013-05-30 01:09:54 +0200
commit6b654c0b13f5399137ca71b177081ee6d0beb22e (patch)
tree81362751c0eca87a4f29c7f01f93408798a857f9 /deps/uv
parentc188a7510317bfdaa19e87c6870c5ee7d965a6b9 (diff)
downloadandroid-node-v8-6b654c0b13f5399137ca71b177081ee6d0beb22e.tar.gz
android-node-v8-6b654c0b13f5399137ca71b177081ee6d0beb22e.tar.bz2
android-node-v8-6b654c0b13f5399137ca71b177081ee6d0beb22e.zip
uv: upgrade to v0.11.4
Diffstat (limited to 'deps/uv')
-rw-r--r--deps/uv/AUTHORS2
-rw-r--r--deps/uv/ChangeLog99
-rw-r--r--deps/uv/include/uv.h21
-rw-r--r--deps/uv/src/unix/core.c29
-rw-r--r--deps/uv/src/unix/darwin.c46
-rw-r--r--deps/uv/src/unix/error.c1
-rw-r--r--deps/uv/src/unix/fs.c7
-rw-r--r--deps/uv/src/unix/linux-core.c111
-rw-r--r--deps/uv/src/unix/signal.c4
-rw-r--r--deps/uv/src/unix/stream.c68
-rw-r--r--deps/uv/src/uv-common.c5
-rw-r--r--deps/uv/src/uv-common.h3
-rw-r--r--deps/uv/src/version.c2
-rw-r--r--deps/uv/src/win/core.c22
-rw-r--r--deps/uv/src/win/process.c45
-rw-r--r--deps/uv/src/win/stream.c4
-rw-r--r--deps/uv/src/win/timer.c5
-rw-r--r--deps/uv/test/test-idle.c21
-rw-r--r--deps/uv/test/test-list.h2
-rw-r--r--deps/uv/test/test-osx-select.c2
-rw-r--r--deps/uv/test/test-timer.c28
21 files changed, 414 insertions, 113 deletions
diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS
index 90b3235bb2..4c36faeb9e 100644
--- a/deps/uv/AUTHORS
+++ b/deps/uv/AUTHORS
@@ -86,3 +86,5 @@ Nils Maier <maierman@web.de>
Nicholas Vavilov <vvnicholas@gmail.com>
Miroslav Bajtoš <miro.bajtos@gmail.com>
Elliot Saba <staticfloat@gmail.com>
+Sean Silva <chisophugis@gmail.com>
+Wynn Wilkes <wynnw@movenetworks.com>
diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog
index 9b29dc2cd9..113d170693 100644
--- a/deps/uv/ChangeLog
+++ b/deps/uv/ChangeLog
@@ -1,4 +1,101 @@
-2013.05.16, Version 0.11.3 (Unstable)
+2013.05.30, Version 0.11.4 (Unstable)
+
+Changes since version 0.11.3:
+
+* windows: make uv_spawn not fail when the libuv embedding application is run
+ under external job control (Bert Belder)
+
+* darwin: assume CFRunLoopStop() isn't thread-safe, fixing a race condition
+ when stopping the 'stdin select hack' thread (Fedor Indutny)
+
+* win: fix UV_EALREADY not being reported correctly to the libuv user in some
+ cases (Bert Belder)
+
+* darwin: make the uv__cf_loop_runner and uv__cf_loop_cb functions static (Ben
+ Noordhuis)
+
+* darwin: task_info() cannot fail (Ben Noordhuis)
+
+* unix: add error mapping for ENETDOWN (Ben Noordhuis)
+
+* unix: implicitly signal write errors to the libuv user (Ben Noordhuis)
+
+* unix: fix assertion error on signal pipe overflow (Bert Belder)
+
+* unix: turn off POLLOUT after stream connect (Ben Noordhuis)
+
+* unix: fix stream refcounting buglet (Ben Noordhuis)
+
+* unix: remove assert statements that are no longer correct (Ben Noordhuis)
+
+* unix: appease warning about non-standard `inline` (Sean Silva)
+
+* unix: add uv__is_closing() macro (Ben Noordhuis)
+
+* unix: stop stream POLLOUT watcher on write error (Ben Noordhuis)
+
+* include: document uv_update_time() and uv_now() (Ben Noordhuis)
+
+* linux: fix cpu model parsing on newer arm kernels (Ben Noordhuis)
+
+* linux: fix a memory leak in uv_cpu_info() error path (Ben Noordhuis)
+
+* linux: don't ignore out-of-memory errors in uv_cpu_info() (Ben Noordhuis)
+
+* unix, windows: move uv_now() to uv-common.c (Ben Noordhuis)
+
+* test: fix a compilation problem in test-osx-select.c that was caused by the
+ use of c-style comments (Bert Belder)
+
+* darwin: use uv_fs_sendfile() use the sendfile api correctly (Wynn Wilkes)
+
+* windows: call idle handles on every loop iteration, something the unix
+ implementation already did (Bert Belder)
+
+* test: update the idle-starvation test to verify that idle handles are called
+ in every loop iteration (Bert Belder)
+
+* unix, windows: ensure that uv_run() in RUN_ONCE mode calls timers that expire
+ after blocking (Ben Noordhuis)
+
+
+2013.05.29, Version 0.10.9 (Stable), a195f9ace23d92345baf57582678bfc3017e6632
+
+Changes since version 0.10.8:
+
+* unix: fix stream refcounting buglet (Ben Noordhuis)
+
+* unix: remove erroneous asserts (Ben Noordhuis)
+
+* unix: add uv__is_closing() macro (Ben Noordhuis)
+
+* unix: stop stream POLLOUT watcher on write error (Ben Noordhuis)
+
+
+2013.05.25, Version 0.10.8 (Stable), 0f39be12926fe2d8766a9f025797a473003e6504
+
+Changes since version 0.10.7:
+
+* windows: make uv_spawn not fail under job control (Bert Belder)
+
+* darwin: assume CFRunLoopStop() isn't thread-safe (Fedor Indutny)
+
+* win: fix UV_EALREADY incorrectly set (Bert Belder)
+
+* darwin: make two uv__cf_*() functions static (Ben Noordhuis)
+
+* darwin: task_info() cannot fail (Ben Noordhuis)
+
+* unix: add mapping for ENETDOWN (Ben Noordhuis)
+
+* unix: implicitly signal write errors to libuv user (Ben Noordhuis)
+
+* unix: fix assert on signal pipe overflow (Bert Belder)
+
+* unix: turn off POLLOUT after stream connect (Ben Noordhuis)
+
+
+2013.05.16, Version 0.11.3 (Unstable), 0a48c05b5988aea84c605751900926fa25443b34
Changes since version 0.11.2:
diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h
index a3ebaa40b5..f51aea60f2 100644
--- a/deps/uv/include/uv.h
+++ b/deps/uv/include/uv.h
@@ -283,7 +283,28 @@ UV_EXTERN void uv_ref(uv_handle_t*);
UV_EXTERN void uv_unref(uv_handle_t*);
UV_EXTERN int uv_has_ref(const uv_handle_t*);
+/*
+ * Update the event loop's concept of "now". Libuv caches the current time
+ * at the start of the event loop tick in order to reduce the number of
+ * time-related system calls.
+ *
+ * You won't normally need to call this function unless you have callbacks
+ * that block the event loop for longer periods of time, where "longer" is
+ * somewhat subjective but probably on the order of a millisecond or more.
+ */
UV_EXTERN void uv_update_time(uv_loop_t*);
+
+/*
+ * Return the current timestamp in milliseconds. The timestamp is cached at
+ * the start of the event loop tick, see |uv_update_time()| for details and
+ * rationale.
+ *
+ * The timestamp increases monotonically from some arbitrary point in time.
+ * Don't make assumptions about the starting point, you will only get
+ * disappointed.
+ *
+ * Use uv_hrtime() if you need sub-milliseond granularity.
+ */
UV_EXTERN uint64_t uv_now(uv_loop_t*);
/*
diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c
index 98b48989a7..3eb45da477 100644
--- a/deps/uv/src/unix/core.c
+++ b/deps/uv/src/unix/core.c
@@ -162,7 +162,12 @@ void uv__make_close_pending(uv_handle_t* handle) {
static void uv__finish_close(uv_handle_t* handle) {
- assert(!uv__is_active(handle));
+ /* Note: while the handle is in the UV_CLOSING state now, it's still possible
+ * for it to be active in the sense that uv__is_active() returns true.
+ * A good example is when the user calls uv_shutdown(), immediately followed
+ * by uv_close(). The handle is considered active at this point because the
+ * completion of the shutdown req is still pending.
+ */
assert(handle->flags & UV_CLOSING);
assert(!(handle->flags & UV_CLOSED));
handle->flags |= UV_CLOSED;
@@ -220,7 +225,7 @@ static void uv__run_closing_handles(uv_loop_t* loop) {
int uv_is_closing(const uv_handle_t* handle) {
- return handle->flags & (UV_CLOSING | UV_CLOSED);
+ return uv__is_closing(handle);
}
@@ -312,8 +317,21 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
uv__io_poll(loop, timeout);
uv__run_check(loop);
uv__run_closing_handles(loop);
- r = uv__loop_alive(loop);
+ if (mode == UV_RUN_ONCE) {
+ /* UV_RUN_ONCE implies forward progess: at least one callback must have
+ * been invoked when it returns. uv__io_poll() can return without doing
+ * I/O (meaning: no callbacks) when its timeout expires - which means we
+ * have pending timers that satisfy the forward progress constraint.
+ *
+ * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
+ * the check.
+ */
+ uv__update_time(loop);
+ uv__run_timers(loop);
+ }
+
+ r = uv__loop_alive(loop);
UV_TICK_STOP(loop, mode);
if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
@@ -335,11 +353,6 @@ void uv_update_time(uv_loop_t* loop) {
}
-uint64_t uv_now(uv_loop_t* loop) {
- return loop->time;
-}
-
-
int uv_is_active(const uv_handle_t* handle) {
return uv__is_active(handle);
}
diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c
index 77301722fc..f57b12c471 100644
--- a/deps/uv/src/unix/darwin.c
+++ b/deps/uv/src/unix/darwin.c
@@ -38,8 +38,8 @@
#include <unistd.h> /* sysconf */
/* Forward declarations */
-void uv__cf_loop_runner(void* arg);
-void uv__cf_loop_cb(void* arg);
+static void uv__cf_loop_runner(void* arg);
+static void uv__cf_loop_cb(void* arg);
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
struct uv__cf_loop_signal_s {
@@ -84,9 +84,8 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
uv__cf_loop_signal_t* s;
assert(loop->cf_loop != NULL);
- CFRunLoopStop(loop->cf_loop);
+ uv__cf_loop_signal(loop, NULL, NULL);
uv_thread_join(&loop->cf_thread);
- loop->cf_loop = NULL;
uv_sem_destroy(&loop->cf_sem);
uv_mutex_destroy(&loop->cf_mutex);
@@ -103,7 +102,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
-void uv__cf_loop_runner(void* arg) {
+static void uv__cf_loop_runner(void* arg) {
uv_loop_t* loop;
loop = arg;
@@ -125,7 +124,7 @@ void uv__cf_loop_runner(void* arg) {
}
-void uv__cf_loop_cb(void* arg) {
+static void uv__cf_loop_cb(void* arg) {
uv_loop_t* loop;
QUEUE* item;
QUEUE split_head;
@@ -145,7 +144,12 @@ void uv__cf_loop_cb(void* arg) {
item = QUEUE_HEAD(&split_head);
s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
- s->cb(s->arg);
+
+ /* This was a termination signal */
+ if (s->cb == NULL)
+ CFRunLoopStop(loop->cf_loop);
+ else
+ s->cb(s->arg);
QUEUE_REMOVE(item);
free(s);
@@ -253,19 +257,21 @@ void uv_loadavg(double avg[3]) {
uv_err_t uv_resident_set_memory(size_t* rss) {
- struct task_basic_info t_info;
- mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
-
- int r = task_info(mach_task_self(),
- TASK_BASIC_INFO,
- (task_info_t)&t_info,
- &t_info_count);
-
- if (r != KERN_SUCCESS) {
- return uv__new_sys_error(errno);
- }
-
- *rss = t_info.resident_size;
+ mach_msg_type_number_t count;
+ task_basic_info_data_t info;
+ kern_return_t err;
+
+ count = TASK_BASIC_INFO_COUNT;
+ err = task_info(mach_task_self(),
+ TASK_BASIC_INFO,
+ (task_info_t) &info,
+ &count);
+ (void) &err;
+ /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
+ * KERN_SUCCESS implies a libuv bug.
+ */
+ assert(err == KERN_SUCCESS);
+ *rss = info.resident_size;
return uv_ok_;
}
diff --git a/deps/uv/src/unix/error.c b/deps/uv/src/unix/error.c
index 9e3e84ad9a..05ab482025 100644
--- a/deps/uv/src/unix/error.c
+++ b/deps/uv/src/unix/error.c
@@ -79,6 +79,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case EMSGSIZE: return UV_EMSGSIZE;
case ENAMETOOLONG: return UV_ENAMETOOLONG;
case EINVAL: return UV_EINVAL;
+ case ENETDOWN: return UV_ENETDOWN;
case ENETUNREACH: return UV_ENETUNREACH;
case ECONNABORTED: return UV_ECONNABORTED;
case ELOOP: return UV_ELOOP;
diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c
index fb8cdb25b1..7fb2763c4b 100644
--- a/deps/uv/src/unix/fs.c
+++ b/deps/uv/src/unix/fs.c
@@ -436,11 +436,14 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
* non-blocking mode and not all data could be written. If a non-zero
* number of bytes have been sent, we don't consider it an error.
*/
- len = 0;
#if defined(__FreeBSD__)
+ len = 0;
r = sendfile(in_fd, out_fd, req->off, req->len, NULL, &len, 0);
#else
+ /* The darwin sendfile takes len as an input for the length to send,
+ * so make sure to initialize it with the caller's value. */
+ len = req->len;
r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
#endif
@@ -497,7 +500,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
return r;
}
-static inline void uv__to_stat(struct stat* src, uv_stat_t* dst) {
+static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_dev = src->st_dev;
dst->st_mode = src->st_mode;
dst->st_nlink = src->st_nlink;
diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c
index 7bb05b5d32..23af7891e1 100644
--- a/deps/uv/src/unix/linux-core.c
+++ b/deps/uv/src/unix/linux-core.c
@@ -382,12 +382,12 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
return uv__new_sys_error(ENOMEM);
if (read_models(numcpus, ci)) {
- SAVE_ERRNO(free(ci));
+ SAVE_ERRNO(uv_free_cpu_info(ci, numcpus));
return uv__new_sys_error(errno);
}
if (read_times(numcpus, ci)) {
- SAVE_ERRNO(free(ci));
+ SAVE_ERRNO(uv_free_cpu_info(ci, numcpus));
return uv__new_sys_error(errno);
}
@@ -414,76 +414,89 @@ static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
/* Also reads the CPU frequency on x86. The other architectures only have
* a BogoMIPS field, which may not be very accurate.
+ *
+ * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
*/
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
-#if defined(__i386__) || defined(__x86_64__)
static const char model_marker[] = "model name\t: ";
static const char speed_marker[] = "cpu MHz\t\t: ";
-#elif defined(__arm__)
- static const char model_marker[] = "Processor\t: ";
- static const char speed_marker[] = "";
-#elif defined(__mips__)
- static const char model_marker[] = "cpu model\t\t: ";
- static const char speed_marker[] = "";
-#else
-# warning uv_cpu_info() is not supported on this architecture.
- static const char model_marker[] = "";
- static const char speed_marker[] = "";
-#endif
- static const char bogus_model[] = "unknown";
+ const char* inferred_model;
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)
- return -1;
+ /* Most are unused on non-ARM and non-x86 architectures. */
+ (void) &model_marker;
+ (void) &speed_marker;
+ (void) &speed_idx;
+ (void) &model;
+ (void) &buf;
+ (void) &fp;
model_idx = 0;
speed_idx = 0;
+#if defined(__arm__) || defined(__i386__) || defined(__x86_64__)
+ fp = fopen("/proc/cpuinfo", "r");
+ if (fp == NULL)
+ return -1;
+
while (fgets(buf, sizeof(buf), fp)) {
- if (model_marker[0] != '\0' &&
- model_idx < numcpus &&
- strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0)
- {
- model = buf + sizeof(model_marker) - 1;
- model = strndup(model, strlen(model) - 1); /* strip newline */
- ci[model_idx++].model = model;
- continue;
+ if (model_idx < numcpus) {
+ if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
+ model = buf + sizeof(model_marker) - 1;
+ model = strndup(model, strlen(model) - 1); /* Strip newline. */
+ if (model == NULL) {
+ fclose(fp);
+ return -1;
+ }
+ ci[model_idx++].model = model;
+ continue;
+ }
}
-
- if (speed_marker[0] != '\0' &&
- speed_idx < numcpus &&
- strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0)
- {
- ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
- continue;
+#if defined(__arm__)
+ /* Fallback for pre-3.8 kernels. */
+ if (model_idx < numcpus) {
+ static const char model_marker[] = "Processor\t: ";
+ if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
+ model = buf + sizeof(model_marker) - 1;
+ model = strndup(model, strlen(model) - 1); /* Strip newline. */
+ if (model == NULL) {
+ fclose(fp);
+ return -1;
+ }
+ ci[model_idx++].model = model;
+ continue;
+ }
}
+#else /* !__arm____ */
+ if (speed_idx < numcpus) {
+ if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
+ ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
+ continue;
+ }
+ }
+#endif /* __arm__ */
}
- 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;
- }
+ fclose(fp);
+#endif /* __arm__ || __i386__ || __x86_64__ */
- /* 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.
+ /* Now we want to make sure that all the models contain *something* because
+ * it's not safe to leave them as null. Copy the last entry unless there
+ * isn't one, in that case we simply put "unknown" into everything.
*/
- inferred_model = ci[model_idx - 1].model;
+ inferred_model = "unknown";
+ if (model_idx > 0)
+ inferred_model = ci[model_idx - 1].model;
while (model_idx < numcpus) {
- ci[model_idx].model = strndup(inferred_model, strlen(inferred_model));
- model_idx++;
+ model = strndup(inferred_model, strlen(inferred_model));
+ if (model == NULL)
+ return -1;
+ ci[model_idx++].model = model;
}
return 0;
diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c
index 78a631825c..db277caf3a 100644
--- a/deps/uv/src/unix/signal.c
+++ b/deps/uv/src/unix/signal.c
@@ -116,7 +116,7 @@ static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
}
-inline static uv_signal_t* uv__signal_first_handle(int signum) {
+static uv_signal_t* uv__signal_first_handle(int signum) {
/* This function must be called with the signal lock held. */
uv_signal_t lookup;
uv_signal_t* handle;
@@ -160,7 +160,7 @@ static void uv__signal_handler(int signum) {
} while (r == -1 && errno == EINTR);
assert(r == sizeof msg ||
- (r == -1 && errno != EAGAIN && errno != EWOULDBLOCK));
+ (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));
if (r != -1)
handle->caught_signals++;
diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c
index 1e97625eb2..7936380a2f 100644
--- a/deps/uv/src/unix/stream.c
+++ b/deps/uv/src/unix/stream.c
@@ -60,6 +60,7 @@ static void uv__stream_connect(uv_stream_t*);
static void uv__write(uv_stream_t* stream);
static void uv__read(uv_stream_t* stream);
static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+static size_t uv__write_req_size(uv_write_t* req);
/* Used by the accept() EMFILE party trick. */
@@ -399,6 +400,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
if (req->bufs != req->bufsml)
free(req->bufs);
+ req->bufs = NULL;
if (req->cb) {
uv__set_artificial_error(req->handle->loop, UV_ECANCELED);
@@ -413,6 +415,13 @@ void uv__stream_destroy(uv_stream_t* stream) {
req = QUEUE_DATA(q, uv_write_t, queue);
uv__req_unregister(stream->loop, req);
+ if (req->bufs != NULL) {
+ stream->write_queue_size -= uv__write_req_size(req);
+ if (req->bufs != req->bufsml)
+ free(req->bufs);
+ req->bufs = NULL;
+ }
+
if (req->cb) {
uv__set_sys_error(stream->loop, req->error);
req->cb(req, req->error ? -1 : 0);
@@ -420,6 +429,11 @@ void uv__stream_destroy(uv_stream_t* stream) {
}
if (stream->shutdown_req) {
+ /* The UV_ECANCELED error code is a lie, the shutdown(2) syscall is a
+ * fait accompli at this point. Maybe we should revisit this in v0.11.
+ * A possible reason for leaving it unchanged is that it informs the
+ * callee that the handle has been destroyed.
+ */
uv__req_unregister(stream->loop, stream->shutdown_req);
uv__set_artificial_error(stream->loop, UV_ECANCELED);
stream->shutdown_req->cb(stream->shutdown_req, -1);
@@ -601,8 +615,6 @@ static void uv__drain(uv_stream_t* stream) {
uv_shutdown_t* req;
assert(QUEUE_EMPTY(&stream->write_queue));
- assert(stream->write_queue_size == 0);
-
uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
/* Shutdown? */
@@ -635,6 +647,7 @@ static void uv__drain(uv_stream_t* stream) {
static size_t uv__write_req_size(uv_write_t* req) {
size_t size;
+ assert(req->bufs != NULL);
size = uv__buf_count(req->bufs + req->write_index,
req->bufcnt - req->write_index);
assert(req->handle->write_queue_size >= size);
@@ -648,10 +661,18 @@ static void uv__write_req_finish(uv_write_t* req) {
/* Pop the req off tcp->write_queue. */
QUEUE_REMOVE(&req->queue);
- if (req->bufs != req->bufsml) {
- free(req->bufs);
+
+ /* Only free when there was no error. On error, we touch up write_queue_size
+ * right before making the callback. The reason we don't do that right away
+ * is that a write_queue_size > 0 is our only way to signal to the user that
+ * he should stop writing - which he should if we got an error. Something to
+ * revisit in future revisions of the libuv API.
+ */
+ if (req->error == 0) {
+ if (req->bufs != req->bufsml)
+ free(req->bufs);
+ req->bufs = NULL;
}
- req->bufs = NULL;
/* Add it to the write_completed_queue where it will have its
* callback called in the near future.
@@ -687,10 +708,8 @@ start:
assert(uv__stream_fd(stream) >= 0);
- if (QUEUE_EMPTY(&stream->write_queue)) {
- assert(stream->write_queue_size == 0);
+ if (QUEUE_EMPTY(&stream->write_queue))
return;
- }
q = QUEUE_HEAD(&stream->write_queue);
req = QUEUE_DATA(q, uv_write_t, queue);
@@ -761,8 +780,10 @@ start:
if (errno != EAGAIN && errno != EWOULDBLOCK) {
/* Error */
req->error = errno;
- stream->write_queue_size -= uv__write_req_size(req);
uv__write_req_finish(req);
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLIN))
+ uv__handle_stop(stream);
return;
} else if (stream->flags & UV_STREAM_BLOCKING) {
/* If this is a blocking stream, try again. */
@@ -838,6 +859,13 @@ static void uv__write_callbacks(uv_stream_t* stream) {
QUEUE_REMOVE(q);
uv__req_unregister(stream->loop, req);
+ if (req->bufs != NULL) {
+ stream->write_queue_size -= uv__write_req_size(req);
+ if (req->bufs != req->bufsml)
+ free(req->bufs);
+ req->bufs = NULL;
+ }
+
/* NOTE: call callback AFTER freeing the request data. */
if (req->cb) {
uv__set_sys_error(stream->loop, req->error);
@@ -1119,6 +1147,7 @@ static void uv__stream_connect(uv_stream_t* stream) {
stream->connect_req = NULL;
uv__req_unregister(stream->loop, req);
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
if (req->cb) {
uv__set_sys_error(stream->loop, error);
@@ -1158,6 +1187,12 @@ int uv_write2(uv_write_t* req,
return uv__set_artificial_error(stream->loop, UV_EBADF);
}
+ /* It's legal for write_queue_size > 0 even when the write_queue is empty;
+ * it means there are error-state requests in the write_completed_queue that
+ * will touch up write_queue_size later, see also uv__write_req_finish().
+ * We chould check that write_queue is empty instead but that implies making
+ * a write() syscall when we know that the handle is in error mode.
+ */
empty_queue = (stream->write_queue_size == 0);
/* Initialize the req */
@@ -1266,9 +1301,20 @@ int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb,
int uv_read_stop(uv_stream_t* stream) {
- uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
- uv__handle_stop(stream);
+ /* Sanity check. We're going to stop the handle unless it's primed for
+ * writing but that means there should be some kind of write action in
+ * progress.
+ */
+ assert(!uv__io_active(&stream->io_watcher, UV__POLLOUT) ||
+ !QUEUE_EMPTY(&stream->write_completed_queue) ||
+ !QUEUE_EMPTY(&stream->write_queue) ||
+ stream->shutdown_req != NULL ||
+ stream->connect_req != NULL);
+
stream->flags &= ~UV_STREAM_READING;
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ uv__handle_stop(stream);
#if defined(__APPLE__)
/* Notify select() thread about state change */
diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c
index fc8831fd97..3956e0bc22 100644
--- a/deps/uv/src/uv-common.c
+++ b/deps/uv/src/uv-common.c
@@ -434,3 +434,8 @@ int uv_has_ref(const uv_handle_t* handle) {
void uv_stop(uv_loop_t* loop) {
loop->stop_flag = 1;
}
+
+
+uint64_t uv_now(uv_loop_t* loop) {
+ return loop->time;
+}
diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h
index 6a47513be3..bbd3e17b6a 100644
--- a/deps/uv/src/uv-common.h
+++ b/deps/uv/src/uv-common.h
@@ -150,6 +150,9 @@ void uv__fs_poll_close(uv_fs_poll_t* handle);
#define uv__is_active(h) \
(((h)->flags & UV__HANDLE_ACTIVE) != 0)
+#define uv__is_closing(h) \
+ (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0)
+
#define uv__handle_start(h) \
do { \
assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
diff --git a/deps/uv/src/version.c b/deps/uv/src/version.c
index e92126ffad..9114afb2cd 100644
--- a/deps/uv/src/version.c
+++ b/deps/uv/src/version.c
@@ -31,7 +31,7 @@
#define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 11
-#define UV_VERSION_PATCH 3
+#define UV_VERSION_PATCH 4
#define UV_VERSION_IS_RELEASE 1
diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c
index 3ba3203803..9b77746482 100644
--- a/deps/uv/src/win/core.c
+++ b/deps/uv/src/win/core.c
@@ -282,15 +282,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
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);
+ uv_idle_invoke(loop);
+
uv_prepare_invoke(loop);
(*poll)(loop, loop->idle_handles == NULL &&
@@ -302,6 +298,20 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
!(mode & UV_RUN_NOWAIT));
uv_check_invoke(loop);
+
+ if (mode == UV_RUN_ONCE) {
+ /* UV_RUN_ONCE implies forward progess: at least one callback must have
+ * been invoked when it returns. uv__io_poll() can return without doing
+ * I/O (meaning: no callbacks) when its timeout expires - which means we
+ * have pending timers that satisfy the forward progress constraint.
+ *
+ * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
+ * the check.
+ */
+ uv_update_time(loop);
+ uv_process_timers(loop);
+ }
+
r = uv__loop_alive(loop);
if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
break;
diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c
index 8ef420e67b..f98767a428 100644
--- a/deps/uv/src/win/process.c
+++ b/deps/uv/src/win/process.c
@@ -49,7 +49,22 @@ static HANDLE uv_global_job_handle_;
static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT;
-static void uv__init_global_job_handle() {
+static void uv__init_global_job_handle(void) {
+ /* Create a job object and set it up to kill all contained processes when
+ * it's closed. Since this handle is made non-inheritable and we're not
+ * giving it to anyone, we're the only process holding a reference to it.
+ * That means that if this process exits it is closed and all the processes
+ * it contains are killed. All processes created with uv_spawn that are not
+ * spawned with the UV_PROCESS_DETACHED flag are assigned to this job.
+ *
+ * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the
+ * processes that we explicitly add are affected, and *their* subprocesses
+ * are not. This ensures that our child processes are not limited in their
+ * ability to use job control on Windows versions that don't deal with
+ * nested jobs (prior to Windows 8 / Server 2012). It also lets our child
+ * processes created detached processes without explicitly breaking away
+ * from job control (which uv_spawn doesn't, either).
+ */
SECURITY_ATTRIBUTES attr;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
@@ -920,7 +935,18 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
}
process_flags = CREATE_UNICODE_ENVIRONMENT;
+
if (options.flags & UV_PROCESS_DETACHED) {
+ /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
+ * means that libuv might not let you create a fully deamonized process
+ * when run under job control. However the type of job control that libuv
+ * itself creates doesn't trickle down to subprocesses so they can still
+ * daemonize.
+ *
+ * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
+ * CreateProcess call fail if we're under job control that doesn't allow
+ * breakaway.
+ */
process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
}
@@ -943,8 +969,21 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
if (!(options.flags & UV_PROCESS_DETACHED)) {
uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
- if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess))
- uv_fatal_error(GetLastError(), "AssignProcessToJobObject");
+ if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
+ /* AssignProcessToJobObject might fail if this process is under job
+ * control and the job doesn't have the
+ * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
+ * that doesn't support nested jobs.
+ *
+ * When that happens we just swallow the error and continue without
+ * establishing a kill-child-on-parent-exit relationship, otherwise
+ * there would be no way for libuv applications run under job control
+ * to spawn processes at all.
+ */
+ DWORD err = GetLastError();
+ if (err != ERROR_ACCESS_DENIED)
+ uv_fatal_error(err, "AssignProcessToJobObject");
+ }
}
/* Set IPC pid to all IPC pipes. */
diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c
index 097f349794..edc5407cf5 100644
--- a/deps/uv/src/win/stream.c
+++ b/deps/uv/src/win/stream.c
@@ -56,7 +56,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) {
if (handle->flags & UV_HANDLE_READING) {
- uv__set_sys_error(handle->loop, UV_EALREADY);
+ uv__set_artificial_error(handle->loop, UV_EALREADY);
return -1;
}
@@ -82,7 +82,7 @@ int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
uv_read2_cb read_cb) {
if (handle->flags & UV_HANDLE_READING) {
- uv__set_sys_error(handle->loop, UV_EALREADY);
+ uv__set_artificial_error(handle->loop, UV_EALREADY);
return -1;
}
diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c
index 52c124e892..9c0dbef297 100644
--- a/deps/uv/src/win/timer.c
+++ b/deps/uv/src/win/timer.c
@@ -64,11 +64,6 @@ void uv__time_forward(uv_loop_t* loop, uint64_t msecs) {
}
-uint64_t uv_now(uv_loop_t* loop) {
- return loop->time;
-}
-
-
static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
if (a->due < b->due)
return -1;
diff --git a/deps/uv/test/test-idle.c b/deps/uv/test/test-idle.c
index 4f0294cfa2..7eea1b83b1 100644
--- a/deps/uv/test/test-idle.c
+++ b/deps/uv/test/test-idle.c
@@ -23,10 +23,12 @@
#include "task.h"
-static uv_timer_t timer_handle;
static uv_idle_t idle_handle;
+static uv_check_t check_handle;
+static uv_timer_t timer_handle;
static int idle_cb_called = 0;
+static int check_cb_called = 0;
static int timer_cb_called = 0;
static int close_cb_called = 0;
@@ -41,6 +43,7 @@ static void timer_cb(uv_timer_t* handle, int status) {
ASSERT(status == 0);
uv_close((uv_handle_t*) &idle_handle, close_cb);
+ uv_close((uv_handle_t*) &check_handle, close_cb);
uv_close((uv_handle_t*) &timer_handle, close_cb);
timer_cb_called++;
@@ -57,6 +60,15 @@ static void idle_cb(uv_idle_t* handle, int status) {
}
+static void check_cb(uv_check_t* handle, int status) {
+ ASSERT(handle == &check_handle);
+ ASSERT(status == 0);
+
+ check_cb_called++;
+ LOGF("check_cb %d\n", check_cb_called);
+}
+
+
TEST_IMPL(idle_starvation) {
int r;
@@ -65,6 +77,11 @@ TEST_IMPL(idle_starvation) {
r = uv_idle_start(&idle_handle, idle_cb);
ASSERT(r == 0);
+ r = uv_check_init(uv_default_loop(), &check_handle);
+ ASSERT(r == 0);
+ r = uv_check_start(&check_handle, check_cb);
+ ASSERT(r == 0);
+
r = uv_timer_init(uv_default_loop(), &timer_handle);
ASSERT(r == 0);
r = uv_timer_start(&timer_handle, timer_cb, 50, 0);
@@ -75,7 +92,7 @@ TEST_IMPL(idle_starvation) {
ASSERT(idle_cb_called > 0);
ASSERT(timer_cb_called == 1);
- ASSERT(close_cb_called == 2);
+ ASSERT(close_cb_called == 3);
MAKE_VALGRIND_HAPPY();
return 0;
diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h
index 0822d7f151..156266d6c3 100644
--- a/deps/uv/test/test-list.h
+++ b/deps/uv/test/test-list.h
@@ -101,6 +101,7 @@ TEST_DECLARE (timer_start_twice)
TEST_DECLARE (timer_order)
TEST_DECLARE (timer_huge_timeout)
TEST_DECLARE (timer_huge_repeat)
+TEST_DECLARE (timer_run_once)
TEST_DECLARE (idle_starvation)
TEST_DECLARE (loop_handles)
TEST_DECLARE (get_loadavg)
@@ -350,6 +351,7 @@ TASK_LIST_START
TEST_ENTRY (timer_order)
TEST_ENTRY (timer_huge_timeout)
TEST_ENTRY (timer_huge_repeat)
+ TEST_ENTRY (timer_run_once)
TEST_ENTRY (idle_starvation)
diff --git a/deps/uv/test/test-osx-select.c b/deps/uv/test/test-osx-select.c
index 5c2cbd4d93..bf4c3952b7 100644
--- a/deps/uv/test/test-osx-select.c
+++ b/deps/uv/test/test-osx-select.c
@@ -62,7 +62,7 @@ TEST_IMPL(osx_select) {
uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb);
- // Emulate user-input
+ /* Emulate user-input */
str = "got some input\n"
"with a couple of lines\n"
"feel pretty happy\n";
diff --git a/deps/uv/test/test-timer.c b/deps/uv/test/test-timer.c
index 6aa2889782..3954957295 100644
--- a/deps/uv/test/test-timer.c
+++ b/deps/uv/test/test-timer.c
@@ -264,3 +264,31 @@ TEST_IMPL(timer_huge_repeat) {
MAKE_VALGRIND_HAPPY();
return 0;
}
+
+
+static unsigned int timer_run_once_timer_cb_called;
+
+
+static void timer_run_once_timer_cb(uv_timer_t* handle, int status) {
+ timer_run_once_timer_cb_called++;
+}
+
+
+TEST_IMPL(timer_run_once) {
+ uv_timer_t timer_handle;
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 0, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+ ASSERT(1 == timer_run_once_timer_cb_called);
+
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 1, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+ ASSERT(2 == timer_run_once_timer_cb_called);
+
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}