Compare commits

...

10 Commits
v1.x ... v0.6

Author SHA1 Message Date
Bert Belder
2db009368a windows: fix uninitialized memory access in uv_update_time()
uv_update_time does not overwrite the high 32 bits of uv_loop_t.time.
It merely increments it by one when the low 32 bits have wrapped. That
means that `time` needs to be initialized to zero before
uv_update_time() is called for the first time.
2012-08-21 01:19:42 +02:00
Bert Belder
0233b92eac unix: fix integer overflow in uv_hrtime
Conversion to nanoseconds was overflowing with 32-bit builds.
2012-08-18 04:00:30 +02:00
Ben Noordhuis
d6a96de4e3 sunos: workaround OS bug to prevent fs.watch() from spinning
This is a back-port of commit cfb06db from the master branch.

Fixes joyent/node#3768.
2012-07-31 15:12:34 +00:00
Ben Noordhuis
06e03193d5 unix: fix loop starvation under high network load
uv__read() and uv__udp_recvmsg() read incoming data in a loop. If data comes
in at high speeds, the kernel receive buffer never drains and said functions
never terminate, stalling the event loop indefinitely. Limit the number of
consecutive reads to 32 to stop that from happening.

The number 32 was chosen at random. Empirically, it seems to maintain a high
throughput while still making the event loop move forward at a reasonable pace.

This is a back-port of commit 738b31e from the master branch.

Conflicts:
	src/unix/stream.c
2012-06-05 17:02:21 +02:00
Bert Belder
dbe681ed2f windows/tty: never report error after forcibly aborting line-buffered read 2012-06-02 03:10:56 +02:00
Ben Noordhuis
cd69ea9105 test: silence compiler warning 2012-05-25 00:31:12 +02:00
Ben Noordhuis
aeb580ddb9 unix: remove abort() in ev_unref() 2012-05-25 00:31:11 +02:00
Bert Belder
bc4126bfaa Windows: skip GetFileAttributes call when opening a file
It wasn't working, and everything seemed to work fine nonetheless. Removing it just saves a syscall.
2012-05-10 16:38:36 +02:00
Ben Noordhuis
cb58a5634d sunos: remove unused uv_fs_event_t field 2012-05-05 21:23:01 +00:00
Ira Cooper
7326962ec3 sunos: make fs.watch scale better
Instead of using one port per watch, use one port for all the watches.
2012-05-05 00:44:30 +00:00
15 changed files with 104 additions and 42 deletions

View File

@ -36,6 +36,11 @@
#include <pwd.h>
#include <termios.h>
#if __sun
# include <sys/port.h>
# include <port.h>
#endif
/* Note: May be cast to struct iovec. See writev(2). */
typedef struct {
char* base;
@ -52,6 +57,14 @@ typedef uid_t uv_uid_t;
typedef void* uv_lib_t;
#define UV_DYNAMIC /* empty */
#if defined(PORT_SOURCE_FILE)
# define UV_LOOP_PRIVATE_PLATFORM_FIELDS \
ev_io fs_event_watcher; \
int fs_fd;
#else
# define UV_LOOP_PRIVATE_PLATFORM_FIELDS
#endif
#define UV_LOOP_PRIVATE_FIELDS \
ares_channel channel; \
/* \
@ -60,7 +73,8 @@ typedef void* uv_lib_t;
* definition of ares_timeout(). \
*/ \
ev_timer timer; \
struct ev_loop* ev;
struct ev_loop* ev; \
UV_LOOP_PRIVATE_PLATFORM_FIELDS
#define UV_REQ_BUFSML_SIZE (4)
@ -206,12 +220,8 @@ typedef void* uv_lib_t;
#elif defined(__sun)
#include <sys/port.h>
#include <port.h>
#ifdef PORT_SOURCE_FILE
# define UV_FS_EVENT_PRIVATE_FIELDS \
ev_io event_watcher; \
uv_fs_event_cb cb; \
file_obj_t fo;
#else /* !PORT_SOURCE_FILE */

View File

@ -19,7 +19,7 @@
*/
#include "uv.h"
#include "unix/internal.h"
#include "internal.h"
#include <stddef.h> /* NULL */
#include <stdio.h> /* printf */
@ -151,6 +151,9 @@ uv_loop_t* uv_loop_new(void) {
uv_loop_t* loop = calloc(1, sizeof(uv_loop_t));
loop->ev = ev_loop_new(0);
ev_set_userdata(loop->ev, loop);
#if HAVE_PORTS_FS
loop->fs_fd = -1;
#endif
return loop;
}
@ -163,6 +166,12 @@ void uv_loop_delete(uv_loop_t* loop) {
memset(loop, 0, sizeof *loop);
#endif
#if HAVE_PORTS_FS
if (loop->fs_fd != -1) {
uv__close(loop->fs_fd);
}
#endif
if (loop == default_loop_ptr)
default_loop_ptr = NULL;
else
@ -182,6 +191,9 @@ uv_loop_t* uv_default_loop(void) {
default_loop_struct.ev = ev_default_loop(EVBACKEND_KQUEUE);
#else
default_loop_struct.ev = ev_default_loop(EVFLAG_AUTO);
#endif
#if HAVE_PORTS_FS
default_loop_struct.fs_fd = -1;
#endif
ev_set_userdata(default_loop_struct.ev, default_loop_ptr);
}

View File

@ -34,7 +34,7 @@
uint64_t uv_hrtime() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
void uv_loadavg(double avg[3]) {

View File

@ -2554,7 +2554,6 @@ void
ev_unref (EV_P)
{
--activecnt;
if (activecnt < 0) abort();
}
void

View File

@ -38,7 +38,7 @@
uint64_t uv_hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}

View File

@ -134,7 +134,7 @@ static char* basename_r(const char* path) {
uint64_t uv_hrtime() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
void uv_loadavg(double avg[3]) {

View File

@ -38,7 +38,7 @@
uint64_t uv_hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
void uv_loadavg(double avg[3]) {

View File

@ -36,7 +36,7 @@
uint64_t uv_hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
void uv_loadavg(double avg[3]) {

View File

@ -523,12 +523,19 @@ static void uv__read(uv_stream_t* stream) {
struct cmsghdr* cmsg;
char cmsg_space[64];
struct ev_loop* ev = stream->loop->ev;
int count;
/* Prevent loop starvation when the data comes in as fast as (or faster than)
* we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
*/
count = 32;
/* XXX: Maybe instead of having UV_READING we just test if
* tcp->read_cb is NULL or not?
*/
while ((stream->read_cb || stream->read2_cb) &&
stream->flags & UV_READING) {
while ((stream->read_cb || stream->read2_cb)
&& (stream->flags & UV_READING)
&& (count-- > 0)) {
assert(stream->alloc_cb);
buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024);

View File

@ -36,6 +36,11 @@
#if HAVE_PORTS_FS
# include <sys/port.h>
# include <port.h>
# define PORT_FIRED 0x69
# define PORT_UNUSED 0x0
# define PORT_LOADED 0x99
# define PORT_DELETED -1
#endif
@ -90,36 +95,51 @@ void uv_loadavg(double avg[3]) {
#if HAVE_PORTS_FS
static void uv__fs_event_rearm(uv_fs_event_t *handle) {
if (port_associate(handle->fd,
if (handle->fd == -1)
return;
if (port_associate(handle->loop->fs_fd,
PORT_SOURCE_FILE,
(uintptr_t) &handle->fo,
FILE_ATTRIB | FILE_MODIFIED,
NULL) == -1) {
handle) == -1) {
uv__set_sys_error(handle->loop, errno);
}
handle->fd = PORT_LOADED;
}
static void uv__fs_event_read(EV_P_ ev_io* w, int revents) {
uv_fs_event_t *handle;
uv_fs_event_t *handle = NULL;
uv_loop_t *loop_;
timespec_t timeout;
port_event_t pe;
int events;
int r;
handle = container_of(w, uv_fs_event_t, event_watcher);
loop_ = container_of(w, uv_loop_t, fs_event_watcher);
do {
/* TODO use port_getn() */
uint_t n = 1;
/*
* Note that our use of port_getn() here (and not port_get()) is deliberate:
* there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
* causes port_get() to return success instead of ETIME when there aren't
* actually any events (!); by using port_getn() in lieu of port_get(),
* we can at least workaround the bug by checking for zero returned events
* and treating it as we would ETIME.
*/
do {
memset(&timeout, 0, sizeof timeout);
r = port_get(handle->fd, &pe, &timeout);
r = port_getn(loop_->fs_fd, &pe, 1, &n, &timeout);
}
while (r == -1 && errno == EINTR);
if (r == -1 && errno == ETIME)
if ((r == -1 && errno == ETIME) || n == 0)
break;
handle = (uv_fs_event_t *)pe.portev_user;
assert((r == 0) && "unexpected port_get() error");
events = 0;
@ -128,12 +148,12 @@ static void uv__fs_event_read(EV_P_ ev_io* w, int revents) {
if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
events |= UV_RENAME;
assert(events != 0);
handle->fd = PORT_FIRED;
handle->cb(handle, NULL, events, 0);
}
while (handle->fd != -1);
while (handle->fd != PORT_DELETED);
if (handle->fd != -1)
if (handle != NULL && handle->fd != PORT_DELETED)
uv__fs_event_rearm(handle);
}
@ -144,39 +164,45 @@ int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_cb cb,
int flags) {
int portfd;
int first_run = 0;
loop->counters.fs_event_init++;
/* We don't support any flags yet. */
assert(!flags);
if ((portfd = port_create()) == -1) {
uv__set_sys_error(loop, errno);
return -1;
if (loop->fs_fd == -1) {
if ((portfd = port_create()) == -1) {
uv__set_sys_error(loop, errno);
return -1;
}
loop->fs_fd = portfd;
first_run = 1;
}
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
handle->filename = strdup(filename);
handle->fd = portfd;
handle->fd = PORT_UNUSED;
handle->cb = cb;
memset(&handle->fo, 0, sizeof handle->fo);
handle->fo.fo_name = handle->filename;
uv__fs_event_rearm(handle);
ev_io_init(&handle->event_watcher, uv__fs_event_read, portfd, EV_READ);
ev_io_start(loop->ev, &handle->event_watcher);
ev_unref(loop->ev);
if (first_run) {
ev_io_init(&loop->fs_event_watcher, uv__fs_event_read, portfd, EV_READ);
ev_io_start(loop->ev, &loop->fs_event_watcher);
ev_unref(loop->ev);
}
return 0;
}
void uv__fs_event_destroy(uv_fs_event_t* handle) {
ev_ref(handle->loop->ev);
ev_io_stop(handle->loop->ev, &handle->event_watcher);
uv__close(handle->fd);
handle->fd = -1;
if (handle->fd == PORT_FIRED) {
port_dissociate(handle->loop->fs_fd, PORT_SOURCE_FILE, (uintptr_t)&handle->fo);
}
handle->fd = PORT_DELETED;
free(handle->filename);
handle->filename = NULL;
handle->fo.fo_name = NULL;

View File

@ -208,12 +208,17 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
ssize_t nread;
uv_buf_t buf;
int flags;
int count;
assert(handle->recv_cb != NULL);
assert(handle->alloc_cb != NULL);
/* Prevent loop starvation when the data comes in as fast as (or faster than)
* we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
*/
count = 32;
do {
/* FIXME: hoist alloc_cb out the loop but for now follow uv__read() */
buf = handle->alloc_cb((uv_handle_t*)handle, 64 * 1024);
assert(buf.len > 0);
assert(buf.base != NULL);
@ -254,6 +259,7 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
}
/* recv_cb callback may decide to pause or close the handle */
while (nread != -1
&& count-- > 0
&& handle->fd != -1
&& handle->recv_cb != NULL);
}

View File

@ -67,6 +67,9 @@ static void uv_loop_init(uv_loop_t* loop) {
loop->refs = 0;
/* To prevent uninitialized memory access, loop->time must be intialized */
/* to zero before calling uv_update_time for the first time. */
loop->time = 0;
uv_update_time(loop);
loop->pending_reqs_tail = NULL;

View File

@ -248,10 +248,8 @@ void fs__open(uv_fs_t* req, const wchar_t* path, int flags, int mode) {
goto end;
}
/* Figure out whether path is a file or a directory. */
if (GetFileAttributesW(path) & FILE_ATTRIBUTE_DIRECTORY) {
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
}
/* Setting this flag makes it possible to open a directory. */
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
file = CreateFileW(path,
access,

View File

@ -688,7 +688,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
if (!REQ_SUCCESS(req)) {
/* Read was not successful */
if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_TTY_RAW)) {
handle->read_line_handle != NULL) {
/* Real error */
handle->flags &= ~UV_HANDLE_READING;
uv__set_sys_error(loop, GET_REQ_ERROR(req));

View File

@ -86,6 +86,7 @@ int run_test(const char* test, int timeout, int benchmark_output) {
int i;
status = 255;
main_proc = NULL;
process_count = 0;
/* If it's a helper the user asks for, start it directly. */