From 5f411405356cd184560507ce870a664e4ef5417f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 6 Jun 2012 05:21:07 +0200 Subject: [PATCH] deps: upgrade libuv to 649ad50 --- deps/uv/include/uv-private/ev.h | 2 +- deps/uv/src/unix/core.c | 39 ++++-------- deps/uv/src/unix/ev/ev.c | 103 ++++++++++++++++++++++++++++++-- deps/uv/src/uv-common.c | 45 ++++++++++++++ deps/uv/src/win/util.c | 91 ++++++++++++++++++++-------- 5 files changed, 219 insertions(+), 61 deletions(-) diff --git a/deps/uv/include/uv-private/ev.h b/deps/uv/include/uv-private/ev.h index 7709bc3493..11e81cda5e 100644 --- a/deps/uv/include/uv-private/ev.h +++ b/deps/uv/include/uv-private/ev.h @@ -623,7 +623,7 @@ enum { }; #if EV_PROTOTYPES -void ev_run (EV_P_ ev_tstamp waittime); +void ev_run (EV_P_ int flags EV_CPP (= 0)); void ev_break (EV_P_ int how EV_CPP (= EVBREAK_ONE)); /* break out of the loop */ /* diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 37d03d3ebd..b33a6f74c7 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -226,16 +226,6 @@ void uv_loop_delete(uv_loop_t* loop) { } -static void uv__poll(uv_loop_t* loop, unsigned int timeout) { - /* bump the loop's refcount, otherwise libev does - * a zero timeout poll and we end up busy looping - */ - ev_ref(loop->ev); - ev_run(loop->ev, timeout / 1000.); - ev_unref(loop->ev); -} - - static unsigned int uv__poll_timeout(uv_loop_t* loop) { if (!uv__has_active_handles(loop)) return 0; @@ -247,22 +237,22 @@ static unsigned int uv__poll_timeout(uv_loop_t* loop) { } +static void uv__poll(uv_loop_t* loop) { + void ev__run(EV_P_ ev_tstamp waittime); + ev_invoke_pending(loop->ev); + ev__run(loop->ev, uv__poll_timeout(loop) / 1000.); + ev_invoke_pending(loop->ev); +} + + static int uv__run(uv_loop_t* loop) { uv_update_time(loop); uv__run_timers(loop); uv__run_idle(loop); - - if (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) { - uv__run_prepare(loop); - /* Need to poll even if there are no active handles left, otherwise - * uv_work_t reqs won't complete... - */ - uv__poll(loop, uv__poll_timeout(loop)); - uv__run_check(loop); - } - + uv__run_prepare(loop); + uv__poll(loop); + uv__run_check(loop); uv__run_closing_handles(loop); - return uv__has_active_handles(loop) || uv__has_active_reqs(loop); } @@ -604,13 +594,6 @@ static void uv__io_rw(struct ev_loop* ev, ev_io* w, int events) { uv__io_t* handle = container_of(w, uv__io_t, io_watcher); u.data = handle->io_watcher.data; u.cb(loop, handle, events & (EV_READ|EV_WRITE|EV_ERROR)); - - /* The callback may have closed all active handles. Stop libev from entering - * the epoll_wait/kevent/port_getn/etc. syscall if that's the case, it would - * hang indefinitely. - */ - if (loop->active_handles == 0) - ev_break(loop->ev, EVBREAK_ONE); } diff --git a/deps/uv/src/unix/ev/ev.c b/deps/uv/src/unix/ev/ev.c index a722981bfe..9888277b81 100644 --- a/deps/uv/src/unix/ev/ev.c +++ b/deps/uv/src/unix/ev/ev.c @@ -2389,7 +2389,7 @@ time_update (EV_P_ ev_tstamp max_block) } void -ev_run (EV_P_ ev_tstamp waittime) +ev_run (EV_P_ int flags) { #if EV_FEATURE_API ++loop_depth; @@ -2426,6 +2426,15 @@ ev_run (EV_P_ ev_tstamp waittime) } #endif +#if EV_PREPARE_ENABLE + /* queue prepare watchers (and execute them) */ + if (expect_false (preparecnt)) + { + queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE); + EV_INVOKE_PENDING; + } +#endif + if (expect_false (loop_done)) break; @@ -2436,16 +2445,90 @@ ev_run (EV_P_ ev_tstamp waittime) /* update fd-related kernel structures */ fd_reify (EV_A); + /* calculate blocking time */ + { + ev_tstamp waittime = 0.; + ev_tstamp sleeptime = 0.; + + /* remember old timestamp for io_blocktime calculation */ + ev_tstamp prev_mn_now = mn_now; + + /* update time to cancel out callback processing overhead */ + time_update (EV_A_ 1e100); + + if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt))) + { + waittime = MAX_BLOCKTIME; + + if (timercnt) + { + ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now + backend_fudge; + if (waittime > to) waittime = to; + } + +#if EV_PERIODIC_ENABLE + if (periodiccnt) + { + ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now + backend_fudge; + if (waittime > to) waittime = to; + } +#endif + + /* don't let timeouts decrease the waittime below timeout_blocktime */ + if (expect_false (waittime < timeout_blocktime)) + waittime = timeout_blocktime; + + /* extra check because io_blocktime is commonly 0 */ + if (expect_false (io_blocktime)) + { + sleeptime = io_blocktime - (mn_now - prev_mn_now); + + if (sleeptime > waittime - backend_fudge) + sleeptime = waittime - backend_fudge; + + if (expect_true (sleeptime > 0.)) + { + ev_sleep (sleeptime); + waittime -= sleeptime; + } + } + } + #if EV_FEATURE_API - ++loop_count; + ++loop_count; +#endif + assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */ + backend_poll (EV_A_ waittime); + assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */ + + /* update ev_rt_now, do magic */ + time_update (EV_A_ waittime + sleeptime); + } + + /* queue pending timers and reschedule them */ + timers_reify (EV_A); /* relative timers called last */ +#if EV_PERIODIC_ENABLE + periodics_reify (EV_A); /* absolute timers called first */ +#endif + +#if EV_IDLE_ENABLE + /* queue idle watchers unless other events are pending */ + idle_reify (EV_A); +#endif + +#if EV_CHECK_ENABLE + /* queue check watchers, to be executed first */ + if (expect_false (checkcnt)) + queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK); #endif - assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */ - backend_poll (EV_A_ waittime); - assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */ EV_INVOKE_PENDING; } - while (0); + while (expect_true ( + activecnt + && !loop_done + && !(flags & (EVRUN_ONCE | EVRUN_NOWAIT)) + )); if (loop_done == EVBREAK_ONE) loop_done = EVBREAK_CANCEL; @@ -2455,6 +2538,14 @@ ev_run (EV_P_ ev_tstamp waittime) #endif } +/* libuv special */ +void +ev__run (EV_P_ ev_tstamp waittime) +{ + fd_reify (EV_A); + backend_poll (EV_A_ waittime); +} + void ev_break (EV_P_ int how) { diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 48f850c738..9639634a1d 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -22,6 +22,7 @@ #include "uv.h" #include "uv-common.h" +#include #include #include /* NULL */ #include /* malloc */ @@ -329,6 +330,50 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { } +#ifndef NDEBUG +static void uv__print_handles(uv_loop_t* loop, int only_active) { + const char* type; + ngx_queue_t* q; + uv_handle_t* h; + + if (loop == NULL) + loop = uv_default_loop(); + + ngx_queue_foreach(q, &loop->handle_queue) { + h = ngx_queue_data(q, uv_handle_t, handle_queue); + + if (only_active && !uv__is_active(h)) + continue; + + switch (h->type) { +#define X(uc, lc) case UV_##uc: type = #lc; break; + UV_HANDLE_TYPE_MAP(X) +#undef X + default: type = ""; + } + + fprintf(stderr, + "[%c%c%c] %-8s %p\n", + "R-"[!(h->flags & UV__HANDLE_REF)], + "A-"[!(h->flags & UV__HANDLE_ACTIVE)], + "I-"[!(h->flags & UV__HANDLE_INTERNAL)], + type, + (void*)h); + } +} + + +void uv_print_all_handles(uv_loop_t* loop) { + uv__print_handles(loop, 0); +} + + +void uv_print_active_handles(uv_loop_t* loop) { + uv__print_handles(loop, 1); +} +#endif + + void uv_ref(uv_handle_t* handle) { uv__handle_ref(handle); } diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 87a999ff5e..be43d50d20 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -154,7 +154,7 @@ int uv_exepath(char* buffer, size_t* size_ptr) { uv_err_t uv_cwd(char* buffer, size_t size) { DWORD utf16_len; - WCHAR utf16_buffer[MAX_PATH + 1]; + WCHAR utf16_buffer[MAX_PATH]; int r; if (buffer == NULL || size == 0) { @@ -164,6 +164,10 @@ uv_err_t uv_cwd(char* buffer, size_t size) { utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); if (utf16_len == 0) { return uv__new_sys_error(GetLastError()); + } else if (utf16_len > MAX_PATH) { + /* This should be impossible; however the CRT has a code path to deal */ + /* with this scenario, so I added a check anyway. */ + return uv__new_artificial_error(UV_EIO); } /* utf16_len contains the length, *not* including the terminating null. */ @@ -195,45 +199,80 @@ uv_err_t uv_cwd(char* buffer, size_t size) { uv_err_t uv_chdir(const char* dir) { - uv_err_t err; - wchar_t* utf16Buffer = NULL; - size_t utf16Size; + WCHAR utf16_buffer[MAX_PATH]; + size_t utf16_len; + WCHAR drive_letter, env_var[4]; - if (!dir) { - err.code = UV_EINVAL; - goto done; + if (dir == NULL) { + return uv__new_artificial_error(UV_EINVAL); } - utf16Size = uv_utf8_to_utf16(dir, NULL, 0); - if (!utf16Size) { - err = uv__new_sys_error(GetLastError()); - goto done; + if (MultiByteToWideChar(CP_UTF8, + 0, + dir, + -1, + utf16_buffer, + MAX_PATH) == 0) { + DWORD error = GetLastError(); + /* The maximum length of the current working directory is 260 chars, */ + /* including terminating null. If it doesn't fit, the path name must be */ + /* too long. */ + if (error == ERROR_INSUFFICIENT_BUFFER) { + return uv__new_artificial_error(UV_ENAMETOOLONG); + } else { + return uv__new_sys_error(error); + } } - utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * utf16Size); - if (!utf16Buffer) { - err.code = UV_ENOMEM; - goto done; + if (!SetCurrentDirectoryW(utf16_buffer)) { + return uv__new_sys_error(GetLastError()); } - if (!uv_utf8_to_utf16(dir, utf16Buffer, utf16Size)) { - err = uv__new_sys_error(GetLastError()); - goto done; + /* Windows stores the drive-local path in an "hidden" environment variable, */ + /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */ + /* update this, so we'll have to do it. */ + utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + if (utf16_len == 0) { + return uv__new_sys_error(GetLastError()); + } else if (utf16_len > MAX_PATH) { + return uv__new_artificial_error(UV_EIO); } - if (_wchdir(utf16Buffer) == -1) { - err = uv__new_sys_error(_doserrno); - goto done; + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed. */ + if (utf16_buffer[utf16_len - 1] == L'\\' && + !(utf16_len == 3 && utf16_buffer[1] == L':')) { + utf16_len--; + utf16_buffer[utf16_len] = L'\0'; } - err = uv_ok_; + if (utf16_len < 2 || utf16_buffer[1] != L':') { + /* Doesn't look like a drive letter could be there - probably an UNC */ + /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */ + drive_letter = 0; + } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') { + drive_letter = utf16_buffer[0]; + } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') { + /* Convert to uppercase. */ + drive_letter = utf16_buffer[0] - L'a' + L'A'; + } else { + /* Not valid. */ + drive_letter = 0; + } -done: - if (utf16Buffer) { - free(utf16Buffer); + if (drive_letter != 0) { + /* Construct the environment variable name and set it. */ + env_var[0] = L'='; + env_var[1] = drive_letter; + env_var[2] = L':'; + env_var[3] = L'\0'; + + if (!SetEnvironmentVariableW(env_var, utf16_buffer)) { + return uv__new_sys_error(GetLastError()); + } } - return err; + return uv_ok_; }