From 1314c4aeeb96f59b010ca8fef2e8e86bbc1f398c Mon Sep 17 00:00:00 2001 From: isaacs Date: Fri, 24 May 2013 14:41:00 -0700 Subject: [PATCH] uv: upgrade to 0.10.8 --- deps/uv/ChangeLog | 25 ++++++++++++++++++++- deps/uv/src/unix/darwin.c | 46 ++++++++++++++++++++++----------------- deps/uv/src/unix/error.c | 1 + deps/uv/src/unix/signal.c | 2 +- deps/uv/src/unix/stream.c | 43 ++++++++++++++++++++++++++++++++---- deps/uv/src/version.c | 2 +- deps/uv/src/win/process.c | 45 +++++++++++++++++++++++++++++++++++--- deps/uv/src/win/stream.c | 4 ++-- 8 files changed, 136 insertions(+), 32 deletions(-) diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 3eed9f1652..356a5b10b1 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,27 @@ -2013.05.15, Version 0.10.7 (Stable) +2013.05.25, Version 0.10.8 (Stable) + +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.15, Version 0.10.7 (Stable), 028baaf0846b686a81e992cb2f2f5a9b8e841fcf Changes since version 0.10.6: diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c index cfbfed23ff..77e662f4e1 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -38,8 +38,8 @@ #include /* 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; ngx_queue_t* item; ngx_queue_t split_head; @@ -145,7 +144,12 @@ void uv__cf_loop_cb(void* arg) { item = ngx_queue_head(&split_head); s = ngx_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); ngx_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/signal.c b/deps/uv/src/unix/signal.c index f7fd2e5e4f..22c7783b9f 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -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 fda2f02f57..aeefa2c419 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 = ngx_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); @@ -652,6 +661,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); @@ -665,10 +675,18 @@ static void uv__write_req_finish(uv_write_t* req) { /* Pop the req off tcp->write_queue. */ ngx_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. @@ -778,7 +796,6 @@ start: if (errno != EAGAIN && errno != EWOULDBLOCK) { /* Error */ req->error = errno; - stream->write_queue_size -= uv__write_req_size(req); uv__write_req_finish(req); return; } else if (stream->flags & UV_STREAM_BLOCKING) { @@ -855,6 +872,13 @@ static void uv__write_callbacks(uv_stream_t* stream) { ngx_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); @@ -1136,6 +1160,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); @@ -1283,6 +1308,16 @@ int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, int uv_read_stop(uv_stream_t* 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) || + !ngx_queue_empty(&stream->write_completed_queue) || + !ngx_queue_empty(&stream->write_queue) || + stream->shutdown_req != NULL || + stream->connect_req != NULL); + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); uv__handle_stop(stream); stream->flags &= ~UV_STREAM_READING; diff --git a/deps/uv/src/version.c b/deps/uv/src/version.c index cb77c176fb..98765533db 100644 --- a/deps/uv/src/version.c +++ b/deps/uv/src/version.c @@ -34,7 +34,7 @@ #define UV_VERSION_MAJOR 0 #define UV_VERSION_MINOR 10 -#define UV_VERSION_PATCH 7 +#define UV_VERSION_PATCH 8 #define UV_VERSION_IS_RELEASE 1 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; }