From 33bcb6359613361b60565f280375edeb672514c8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 7 Sep 2012 15:08:43 +0200 Subject: [PATCH 01/13] build: make gyp_uv understand '-f ninja' --- gyp_uv | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gyp_uv b/gyp_uv index 00da3aed..d861cbc7 100755 --- a/gyp_uv +++ b/gyp_uv @@ -58,9 +58,11 @@ if __name__ == '__main__': # There's a bug with windows which doesn't allow this feature. if sys.platform != 'win32': - args.extend(['--generator-output', output_dir]) - args.extend(['-Goutput_dir=' + output_dir]) - args.extend('-f make'.split()) + if '-f' not in args: + args.extend('-f make'.split()) + if 'ninja' not in args: + args.extend(['-Goutput_dir=' + output_dir]) + args.extend(['--generator-output', output_dir]) (major, minor), is_clang = compiler_version() args.append('-Dgcc_version=%d' % (10 * major + minor)) args.append('-Dclang=%d' % int(is_clang)) From 12c25e1027e26ffb16f54d17a69a88450e9a23df Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 10 Sep 2012 15:01:50 +0200 Subject: [PATCH 02/13] unix: fix EMFILE busy loop Don't spin in epoll_wait() / kevent() / port_getn() / etc. when we can't accept() a new connection due to having reached the file descriptor limit. Pass the error to the connection_cb and let the libuv user deal with it. --- src/unix/stream.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 284643e4..ce8a1c18 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -186,9 +186,6 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, int events) { if (errno == EAGAIN || errno == EWOULDBLOCK) { /* No problem. */ return; - } else if (errno == EMFILE) { - /* TODO special trick. unlock reserved socket, accept, close. */ - return; } else if (errno == ECONNABORTED) { /* ignore */ continue; From b5028c5b542f34f77ab9e0dcf172898d7f2028a0 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 12 Sep 2012 01:33:16 +0200 Subject: [PATCH 03/13] unix: code cleanup, rename variable --- src/unix/process.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 4d54e043..a0eb01ad 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -205,26 +205,26 @@ static void uv__process_close_stream(uv_stdio_container_t* container) { static void uv__process_child_init(uv_process_options_t options, int stdio_count, int* pipes) { - int i; + int fd; if (options.flags & UV_PROCESS_DETACHED) { setsid(); } /* Dup fds */ - for (i = 0; i < stdio_count; i++) { + for (fd = 0; fd < stdio_count; fd++) { /* * stdin has swapped ends of pipe * (it's the only one readable stream) */ - int close_fd = i == 0 ? pipes[i * 2 + 1] : pipes[i * 2]; - int use_fd = i == 0 ? pipes[i * 2] : pipes[i * 2 + 1]; + int close_fd = fd == 0 ? pipes[fd * 2 + 1] : pipes[fd * 2]; + int use_fd = fd == 0 ? pipes[fd * 2] : pipes[fd * 2 + 1]; if (use_fd >= 0) { close(close_fd); - } else if (i < 3) { + } else if (fd < 3) { /* `/dev/null` stdin, stdout, stderr even if they've flag UV_IGNORE */ - use_fd = open("/dev/null", i == 0 ? O_RDONLY : O_RDWR); + use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); if (use_fd < 0) { perror("failed to open stdio"); @@ -234,8 +234,8 @@ static void uv__process_child_init(uv_process_options_t options, continue; } - if (i != use_fd) { - dup2(use_fd, i); + if (fd != use_fd) { + dup2(use_fd, fd); close(use_fd); } else { uv__cloexec(use_fd, 0); From 1988f5e581e4cadb20d8e69ddee9be8a26ff2646 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 12 Sep 2012 01:44:46 +0200 Subject: [PATCH 04/13] unix: put child process stdio fds in blocking mode Remove the O_NONBLOCK flag from file descriptors 0-2, most applications don't expect EAGAIN errors when dealing with stdio. --- src/unix/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/unix/process.c b/src/unix/process.c index a0eb01ad..40330640 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -240,6 +240,9 @@ static void uv__process_child_init(uv_process_options_t options, } else { uv__cloexec(use_fd, 0); } + + if (fd <= 2) + uv__nonblock(fd, 0); } if (options.cwd && chdir(options.cwd)) { From b2dc1e6d64874182d460b81c10ec6165baad3780 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 14 Sep 2012 17:50:45 +0200 Subject: [PATCH 05/13] win/tty: reset background brightness when color is set to default --- src/win/tty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/tty.c b/src/win/tty.c index 340bcdcb..d290ce2e 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -1113,6 +1113,7 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { } else if (arg == 49) { /* Default background color */ bg_color = 0; + bg_bright = 0; } else if (arg >= 90 && arg <= 97) { /* Set bold foreground color */ From 9a4838110d5b625356d6df537931617a5987ece4 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 14 Aug 2012 17:00:25 +0200 Subject: [PATCH 06/13] linux: improve /proc/cpuinfo parser Make uv_cpu_info() understand the ARM and MIPS versions of /proc/cpuinfo, it only knew how to deal with the x86 version This commit also fixes a buglet where uv_cpu_info() reported the maximum CPU frequency instead of the actual CPU frequency. That is, before this commit `out/Debug/run-tests platform_output | grep speed | sort | uniq -c` on my system always reported: 8 speed: 3400 Now it reports (for example): 2 speed: 3400 6 speed: 1600 In other words, two CPUs are running at full speed while the others have been scaled back because they're mostly idle. This is a back-port of commit 54bfb66 from the master branch. Fixes #526. --- src/unix/linux/linux-core.c | 225 +++++++++++++++++++++++++----------- 1 file changed, 156 insertions(+), 69 deletions(-) diff --git a/src/unix/linux/linux-core.c b/src/unix/linux/linux-core.c index c77c81cc..bf6efd85 100644 --- a/src/unix/linux/linux-core.c +++ b/src/unix/linux/linux-core.c @@ -63,6 +63,11 @@ static struct { size_t len; } process_title; +static void read_models(unsigned int numcpus, uv_cpu_info_t* ci); +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); +static void read_times(unsigned int numcpus, uv_cpu_info_t* ci); +static unsigned long read_cpufreq(unsigned int cpunum); + /* * There's probably some way to get time from Linux than gettimeofday(). What @@ -301,84 +306,166 @@ uv_err_t uv_uptime(double* uptime) { uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { - unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), - multiplier = ((uint64_t)1000L / ticks), cpuspeed; - int numcpus = 0, i = 0; - unsigned long ticks_user, ticks_sys, ticks_idle, ticks_nice, ticks_intr; - char line[512], speedPath[256], model[512]; - FILE *fpStat = fopen("/proc/stat", "r"); - FILE *fpModel = fopen("/proc/cpuinfo", "r"); - FILE *fpSpeed; - uv_cpu_info_t* cpu_info; + unsigned int numcpus; + uv_cpu_info_t* ci; - if (fpModel) { - while (fgets(line, 511, fpModel) != NULL) { - if (strncmp(line, "model name", 10) == 0) { - numcpus++; - if (numcpus == 1) { - char *p = strchr(line, ':') + 2; - strcpy(model, p); - model[strlen(model)-1] = 0; - } - } else if (strncmp(line, "cpu MHz", 7) == 0) { - if (numcpus == 1) { - sscanf(line, "%*s %*s : %u", &cpuspeed); - } - } - } - fclose(fpModel); - } + *cpu_infos = NULL; + *count = 0; - *cpu_infos = (uv_cpu_info_t*)malloc(numcpus * sizeof(uv_cpu_info_t)); - if (!(*cpu_infos)) { - return uv__new_artificial_error(UV_ENOMEM); - } + numcpus = sysconf(_SC_NPROCESSORS_ONLN); + assert(numcpus != (unsigned int) -1); + assert(numcpus != 0); + ci = calloc(numcpus, sizeof(*ci)); + if (ci == NULL) + return uv__new_sys_error(ENOMEM); + + read_speeds(numcpus, ci); + read_models(numcpus, ci); + read_times(numcpus, ci); + + *cpu_infos = ci; *count = numcpus; - cpu_info = *cpu_infos; - - if (fpStat) { - while (fgets(line, 511, fpStat) != NULL) { - if (strncmp(line, "cpu ", 4) == 0) { - continue; - } else if (strncmp(line, "cpu", 3) != 0) { - break; - } - - sscanf(line, "%*s %lu %lu %lu %lu %*s %lu", - &ticks_user, &ticks_nice, &ticks_sys, &ticks_idle, &ticks_intr); - snprintf(speedPath, sizeof(speedPath), - "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq", i); - - fpSpeed = fopen(speedPath, "r"); - - if (fpSpeed) { - if (fgets(line, 511, fpSpeed) != NULL) { - sscanf(line, "%u", &cpuspeed); - cpuspeed /= 1000; - } - fclose(fpSpeed); - } - - cpu_info->cpu_times.user = ticks_user * multiplier; - cpu_info->cpu_times.nice = ticks_nice * multiplier; - cpu_info->cpu_times.sys = ticks_sys * multiplier; - cpu_info->cpu_times.idle = ticks_idle * multiplier; - cpu_info->cpu_times.irq = ticks_intr * multiplier; - - cpu_info->model = strdup(model); - cpu_info->speed = cpuspeed; - - cpu_info++; - } - fclose(fpStat); - } - return uv_ok_; } +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) { + unsigned int num; + + for (num = 0; num < numcpus; num++) + ci[num].speed = read_cpufreq(num) / 1000; +} + + +static void read_models(unsigned int numcpus, uv_cpu_info_t* ci) { +#if defined(__i386__) || defined(__x86_64__) + static const char marker[] = "model name\t: "; +#elif defined(__arm__) + static const char marker[] = "Processor\t: "; +#elif defined(__mips__) + static const char marker[] = "cpu model\t\t: "; +#else +# warning uv_cpu_info() is not supported on this architecture. + static const char marker[] = "(dummy)"; +#endif + unsigned int num; + char buf[1024]; + char* model; + FILE* fp; + + fp = fopen("/proc/cpuinfo", "r"); + if (fp == NULL) + return; + + num = 0; + + while (fgets(buf, sizeof(buf), fp)) { + if (num >= numcpus) + break; + + if (strncmp(buf, marker, sizeof(marker) - 1)) + continue; + + model = buf + sizeof(marker) - 1; + model = strndup(model, strlen(model) - 1); /* strip newline */ + ci[num++].model = model; + } + fclose(fp); +} + + +static void read_times(unsigned int numcpus, uv_cpu_info_t* ci) { + unsigned long clock_ticks; + struct uv_cpu_times_s ts; + unsigned long user; + unsigned long nice; + unsigned long sys; + unsigned long idle; + unsigned long dummy; + unsigned long irq; + unsigned int num; + unsigned int len; + char buf[1024]; + FILE* fp; + + clock_ticks = sysconf(_SC_CLK_TCK); + assert(clock_ticks != (unsigned long) -1); + assert(clock_ticks != 0); + + fp = fopen("/proc/stat", "r"); + if (fp == NULL) + return; + + if (!fgets(buf, sizeof(buf), fp)) + abort(); + + num = 0; + + while (fgets(buf, sizeof(buf), fp)) { + if (num >= numcpus) + break; + + if (strncmp(buf, "cpu", 3)) + break; + + /* skip "cpu " marker */ + { + unsigned int n = num; + for (len = sizeof("cpu0"); n /= 10; len++); + assert(sscanf(buf, "cpu%u ", &n) == 1 && n == num); + } + + /* Line contains user, nice, system, idle, iowait, irq, softirq, steal, + * guest, guest_nice but we're only interested in the first four + irq. + * + * Don't use %*s to skip fields or %ll to read straight into the uint64_t + * fields, they're not allowed in C89 mode. + */ + if (6 != sscanf(buf + len, + "%lu %lu %lu %lu %lu %lu", + &user, + &nice, + &sys, + &idle, + &dummy, + &irq)) + abort(); + + ts.user = clock_ticks * user; + ts.nice = clock_ticks * nice; + ts.sys = clock_ticks * sys; + ts.idle = clock_ticks * idle; + ts.irq = clock_ticks * irq; + ci[num++].cpu_times = ts; + } + fclose(fp); +} + + +static unsigned long read_cpufreq(unsigned int cpunum) { + unsigned long val; + char buf[1024]; + FILE* fp; + + snprintf(buf, + sizeof(buf), + "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", + cpunum); + + fp = fopen(buf, "r"); + if (fp == NULL) + return 0; + + val = 0; + fscanf(fp, "%lu", &val); + fclose(fp); + + return val; +} + + void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { int i; From b877db93cec5664a9603ca94c172b06952382468 Mon Sep 17 00:00:00 2001 From: Charlie McConnell Date: Wed, 19 Sep 2012 10:49:20 -0700 Subject: [PATCH 07/13] unix: map EDQUOT to UV_ENOSPC --- src/unix/error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/unix/error.c b/src/unix/error.c index b2add994..e5ef3a01 100644 --- a/src/unix/error.c +++ b/src/unix/error.c @@ -100,6 +100,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case ENOSPC: return UV_ENOSPC; case EROFS: return UV_EROFS; case ENOMEM: return UV_ENOMEM; + case EDQUOT: return UV_ENOSPC; default: return UV_UNKNOWN; } UNREACHABLE(); From 39ca621987e1d1542cec76b8785aa15ea26e225d Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sat, 22 Sep 2012 03:49:52 +0200 Subject: [PATCH 08/13] windows: don't blow up when an invalid FD is used --- src/win/core.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/win/core.c b/src/win/core.c index 79fb655c..5b47c202 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "uv.h" @@ -40,10 +41,21 @@ static uv_once_t uv_init_guard_ = UV_ONCE_INIT; static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT; +static void uv__crt_invalid_parameter_handler(const wchar_t* expression, + const wchar_t* function, const wchar_t * file, unsigned int line, + uintptr_t reserved) { + /* No-op. */ +} + + static void uv_init(void) { /* Tell Windows that we will handle critical errors. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | - SEM_NOOPENFILEERRORBOX); + SEM_NOOPENFILEERRORBOX); + + /* Tell the CRT to not exit the application when an invalid parameter is */ + /* passed. The main issue is that invalid FDs will trigger this behavior. */ + _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler); /* Fetch winapi function pointers. This must be done first because other */ /* intialization code might need these function pointers to be loaded. */ From 4900912d44f3738f50e2a211882d558d6ad0523a Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Wed, 10 Oct 2012 17:15:08 +0200 Subject: [PATCH 09/13] windows: fix application crashed popup in debug version This is a backport of 2 patches by Ting-Yu Lin and Hiroaki Nakamura. --- test/runner-win.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/runner-win.c b/test/runner-win.c index ad36719c..0a9690e7 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -25,6 +25,10 @@ #include #include #include +#if !defined(__MINGW32__) +#include +#endif + #include "task.h" #include "runner.h" @@ -44,6 +48,10 @@ void platform_init(int argc, char **argv) { /* Disable the "application crashed" popup. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +#if !defined(__MINGW32__) + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); +#endif _setmode(0, _O_BINARY); _setmode(1, _O_BINARY); From b0c1a3803ab93c93404fd0c00d809ae678a4f43a Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Wed, 10 Oct 2012 17:09:20 +0200 Subject: [PATCH 10/13] windows: fix handle leak in uv_fs_utime --- src/win/fs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/win/fs.c b/src/win/fs.c index 4a2d9362..9b920c81 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1137,9 +1137,12 @@ static void fs__utime(uv_fs_t* req) { if (fs__utime_handle(handle, req->atime, req->mtime) != 0) { SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); return; } + CloseHandle(handle); + req->result = 0; } From 9a6f496985823a07f808bac7df95343051c29d1b Mon Sep 17 00:00:00 2001 From: saghul Date: Thu, 11 Oct 2012 00:53:50 +0200 Subject: [PATCH 11/13] win: fix compilation with MSVCRT < 8.0 --- src/win/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/win/core.c b/src/win/core.c index 5b47c202..d29a1300 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -55,7 +55,9 @@ static void uv_init(void) { /* Tell the CRT to not exit the application when an invalid parameter is */ /* passed. The main issue is that invalid FDs will trigger this behavior. */ +#ifdef _WRITE_ABORT_MSG _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler); +#endif /* Fetch winapi function pointers. This must be done first because other */ /* intialization code might need these function pointers to be loaded. */ From c2478b26692363a4495c3d72e72977bbf90120fe Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 22 Oct 2012 13:35:53 +0200 Subject: [PATCH 12/13] linux: update comm field in uv_set_process_title() Makes the new process name visible in both `ps` and `ps a`, with the caveat that `ps` will only print the first 16 characters. Before this commit, `ps` kept reporting the old process name. --- src/unix/linux/linux-core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/unix/linux/linux-core.c b/src/unix/linux/linux-core.c index bf6efd85..e26656e1 100644 --- a/src/unix/linux/linux-core.c +++ b/src/unix/linux/linux-core.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -167,6 +168,10 @@ uv_err_t uv_set_process_title(const char* title) { if (process_title.len) strncpy(process_title.str, title, process_title.len - 1); +#if defined(PR_SET_NAME) + prctl(PR_SET_NAME, title); +#endif + return uv_ok_; } From f43ad85eddf708bb1c1d87cd6a1e7e60a9191dd6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 25 Oct 2012 04:26:56 +0200 Subject: [PATCH 13/13] include: fix ngx_queue_foreach() macro Guard against the possibility that the queue is emptied while we're iterating over it. Simple test case: #include "ngx-queue.h" #include int main(void) { ngx_queue_t h; ngx_queue_t v[2]; ngx_queue_t* q; unsigned n = 0; ngx_queue_init(&h); ngx_queue_insert_tail(&h, v + 0); ngx_queue_insert_tail(&h, v + 1); ngx_queue_foreach(q, &h) { ngx_queue_remove(v + 0); ngx_queue_remove(v + 1); n++; } assert(n == 1); // *not* 2 return 0; } Fixes #605. --- include/uv-private/ngx-queue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uv-private/ngx-queue.h b/include/uv-private/ngx-queue.h index 6fd0071f..08fd655a 100644 --- a/include/uv-private/ngx-queue.h +++ b/include/uv-private/ngx-queue.h @@ -101,7 +101,7 @@ struct ngx_queue_s { #define ngx_queue_foreach(q, h) \ for ((q) = ngx_queue_head(h); \ - (q) != ngx_queue_sentinel(h); \ + (q) != ngx_queue_sentinel(h) && !ngx_queue_empty(h); \ (q) = ngx_queue_next(q))