diff --git a/src/unix/linux.c b/src/unix/linux.c index d841c49a..b5e9ac7f 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -30,15 +30,99 @@ #include #include -#include #include #include #include +#include #include #undef NANOSEC #define NANOSEC 1000000000 +#undef HAVE_INOTIFY_INIT +#undef HAVE_INOTIFY_INIT1 +#undef HAVE_INOTIFY_ADD_WATCH +#undef HAVE_INOTIFY_RM_WATCH + +#if __NR_inotify_init +# define HAVE_INOTIFY_INIT 1 +#endif +#if __NR_inotify_init1 +# define HAVE_INOTIFY_INIT1 1 +#endif +#if __NR_inotify_add_watch +# define HAVE_INOTIFY_ADD_WATCH 1 +#endif +#if __NR_inotify_rm_watch +# define HAVE_INOTIFY_RM_WATCH 1 +#endif + +#if HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1 +# undef IN_ACCESS +# undef IN_MODIFY +# undef IN_ATTRIB +# undef IN_CLOSE_WRITE +# undef IN_CLOSE_NOWRITE +# undef IN_OPEN +# undef IN_MOVED_FROM +# undef IN_MOVED_TO +# undef IN_CREATE +# undef IN_DELETE +# undef IN_DELETE_SELF +# undef IN_MOVE_SELF +# define IN_ACCESS 0x001 +# define IN_MODIFY 0x002 +# define IN_ATTRIB 0x004 +# define IN_CLOSE_WRITE 0x008 +# define IN_CLOSE_NOWRITE 0x010 +# define IN_OPEN 0x020 +# define IN_MOVED_FROM 0x040 +# define IN_MOVED_TO 0x080 +# define IN_CREATE 0x100 +# define IN_DELETE 0x200 +# define IN_DELETE_SELF 0x400 +# define IN_MOVE_SELF 0x800 +struct inotify_event { + int32_t wd; + uint32_t mask; + uint32_t cookie; + uint32_t len; + /* char name[0]; */ +}; +#endif /* HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1 */ + +#undef IN_CLOEXEC +#undef IN_NONBLOCK + +#if HAVE_INOTIFY_INIT1 +# define IN_CLOEXEC O_CLOEXEC +# define IN_NONBLOCK O_NONBLOCK +#endif /* HAVE_INOTIFY_INIT1 */ + +#if HAVE_INOTIFY_INIT +inline static int inotify_init(void) { + return syscall(__NR_inotify_init); +} +#endif /* HAVE_INOTIFY_INIT */ + +#if HAVE_INOTIFY_INIT1 +inline static int inotify_init1(int flags) { + return syscall(__NR_inotify_init1, flags); +} +#endif /* HAVE_INOTIFY_INIT1 */ + +#if HAVE_INOTIFY_ADD_WATCH +inline static int inotify_add_watch(int fd, const char* path, uint32_t mask) { + return syscall(__NR_inotify_add_watch, fd, path, mask); +} +#endif /* HAVE_INOTIFY_ADD_WATCH */ + +#if HAVE_INOTIFY_RM_WATCH +inline static int inotify_rm_watch(int fd, uint32_t wd) { + return syscall(__NR_inotify_rm_watch, fd, wd); +} +#endif /* HAVE_INOTIFY_RM_WATCH */ + static char buf[MAXPATHLEN + 1]; @@ -65,6 +149,7 @@ uint64_t uv_hrtime() { return (ts.tv_sec * NANOSEC + ts.tv_nsec); } + void uv_loadavg(double avg[3]) { struct sysinfo info; @@ -87,141 +172,16 @@ int uv_exepath(char* buffer, size_t* size) { return 0; } + uint64_t uv_get_free_memory(void) { return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES); } + uint64_t uv_get_total_memory(void) { return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES); } -static int new_inotify_fd(void) { -#if defined(IN_NONBLOCK) && defined(IN_CLOEXEC) - return inotify_init1(IN_NONBLOCK | IN_CLOEXEC); -#else - int fd; - - if ((fd = inotify_init()) == -1) - return -1; - - if (uv__cloexec(fd, 1) || uv__nonblock(fd, 1)) { - SAVE_ERRNO(uv__close(fd)); - fd = -1; - } - - return fd; -#endif -} - - -static void uv__inotify_read(EV_P_ ev_io* w, int revents) { - struct inotify_event* e; - uv_fs_event_t* handle; - const char* filename; - ssize_t size; - int events; - char *p; - /* needs to be large enough for sizeof(inotify_event) + strlen(filename) */ - char buf[4096]; - - handle = container_of(w, uv_fs_event_t, read_watcher); - - do { - do { - size = read(handle->fd, buf, sizeof buf); - } - while (size == -1 && errno == EINTR); - - if (size == -1) { - assert(errno == EAGAIN || errno == EWOULDBLOCK); - break; - } - - assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */ - - /* Now we have one or more inotify_event structs. */ - for (p = buf; p < buf + size; p += sizeof(*e) + e->len) { - e = (void*)p; - - events = 0; - if (e->mask & (IN_ATTRIB|IN_MODIFY)) - events |= UV_CHANGE; - if (e->mask & ~(IN_ATTRIB|IN_MODIFY)) - events |= UV_RENAME; - - /* inotify does not return the filename when monitoring a single file - * for modifications. Repurpose the filename for API compatibility. - * I'm not convinced this is a good thing, maybe it should go. - */ - filename = e->len ? e->name : basename_r(handle->filename); - - handle->cb(handle, filename, events, 0); - - if (handle->fd == -1) - break; - } - } - while (handle->fd != -1); /* handle might've been closed by callback */ -} - - -int uv_fs_event_init(uv_loop_t* loop, - uv_fs_event_t* handle, - const char* filename, - uv_fs_event_cb cb, - int flags) { - int events; - int fd; - - loop->counters.fs_event_init++; - - /* We don't support any flags yet. */ - assert(!flags); - - /* - * TODO share a single inotify fd across the event loop? - * We'll run into fs.inotify.max_user_instances if we - * keep creating new inotify fds. - */ - if ((fd = new_inotify_fd()) == -1) { - uv__set_sys_error(loop, errno); - return -1; - } - - events = IN_ATTRIB - | IN_CREATE - | IN_MODIFY - | IN_DELETE - | IN_DELETE_SELF - | IN_MOVED_FROM - | IN_MOVED_TO; - - if (inotify_add_watch(fd, filename, events) == -1) { - uv__set_sys_error(loop, errno); - uv__close(fd); - return -1; - } - - uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); - handle->filename = strdup(filename); /* this should go! */ - handle->cb = cb; - handle->fd = fd; - - ev_io_init(&handle->read_watcher, uv__inotify_read, fd, EV_READ); - ev_io_start(loop->ev, &handle->read_watcher); - - return 0; -} - - -void uv__fs_event_destroy(uv_fs_event_t* handle) { - ev_io_stop(handle->loop->ev, &handle->read_watcher); - uv__close(handle->fd); - handle->fd = -1; - free(handle->filename); - handle->filename = NULL; -} - char** uv_setup_args(int argc, char** argv) { char **new_argv; @@ -572,3 +532,152 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, free(addresses); } + +#if HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1 + +static int new_inotify_fd(void) { +#if HAVE_INOTIFY_INIT1 + return inotify_init1(IN_NONBLOCK | IN_CLOEXEC); +#else + int fd; + + if ((fd = inotify_init()) == -1) + return -1; + + if (uv__cloexec(fd, 1) || uv__nonblock(fd, 1)) { + SAVE_ERRNO(uv__close(fd)); + fd = -1; + } + + return fd; +#endif +} + + +static void uv__inotify_read(EV_P_ ev_io* w, int revents) { + struct inotify_event* e; + uv_fs_event_t* handle; + const char* filename; + ssize_t size; + int events; + char *p; + /* needs to be large enough for sizeof(inotify_event) + strlen(filename) */ + char buf[4096]; + + handle = container_of(w, uv_fs_event_t, read_watcher); + + do { + do { + size = read(handle->fd, buf, sizeof buf); + } + while (size == -1 && errno == EINTR); + + if (size == -1) { + assert(errno == EAGAIN || errno == EWOULDBLOCK); + break; + } + + assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */ + + /* Now we have one or more inotify_event structs. */ + for (p = buf; p < buf + size; p += sizeof(*e) + e->len) { + e = (void*)p; + + events = 0; + if (e->mask & (IN_ATTRIB|IN_MODIFY)) + events |= UV_CHANGE; + if (e->mask & ~(IN_ATTRIB|IN_MODIFY)) + events |= UV_RENAME; + + /* inotify does not return the filename when monitoring a single file + * for modifications. Repurpose the filename for API compatibility. + * I'm not convinced this is a good thing, maybe it should go. + */ + filename = e->len ? (const char*) (e + 1) : basename_r(handle->filename); + + handle->cb(handle, filename, events, 0); + + if (handle->fd == -1) + break; + } + } + while (handle->fd != -1); /* handle might've been closed by callback */ +} + + +int uv_fs_event_init(uv_loop_t* loop, + uv_fs_event_t* handle, + const char* filename, + uv_fs_event_cb cb, + int flags) { + int events; + int fd; + + loop->counters.fs_event_init++; + + /* We don't support any flags yet. */ + assert(!flags); + + /* + * TODO share a single inotify fd across the event loop? + * We'll run into fs.inotify.max_user_instances if we + * keep creating new inotify fds. + */ + if ((fd = new_inotify_fd()) == -1) { + uv__set_sys_error(loop, errno); + return -1; + } + + events = IN_ATTRIB + | IN_CREATE + | IN_MODIFY + | IN_DELETE + | IN_DELETE_SELF + | IN_MOVED_FROM + | IN_MOVED_TO; + + if (inotify_add_watch(fd, filename, events) == -1) { + uv__set_sys_error(loop, errno); + uv__close(fd); + return -1; + } + + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + handle->filename = strdup(filename); /* this should go! */ + handle->cb = cb; + handle->fd = fd; + + ev_io_init(&handle->read_watcher, uv__inotify_read, fd, EV_READ); + ev_io_start(loop->ev, &handle->read_watcher); + + return 0; +} + + +void uv__fs_event_destroy(uv_fs_event_t* handle) { + ev_io_stop(handle->loop->ev, &handle->read_watcher); + uv__close(handle->fd); + handle->fd = -1; + free(handle->filename); + handle->filename = NULL; +} + +#else /* !HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1 */ + +int uv_fs_event_init(uv_loop_t* loop, + uv_fs_event_t* handle, + const char* filename, + uv_fs_event_cb cb, + int flags) { + loop->counters.fs_event_init++; + uv__set_sys_error(loop, ENOSYS); + return -1; +} + + +void uv__fs_event_destroy(uv_fs_event_t* handle) { + assert(0 && "unreachable"); + abort(); +} + +#endif /* HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1 */ diff --git a/src/win/pipe.c b/src/win/pipe.c index 3bbfa833..5c20fe48 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1047,7 +1047,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req, ipc_header_req = (uv_write_t*)&handle->ipc_header_write_req; } else { ipc_header_req = (uv_write_t*)malloc(sizeof(uv_write_t)); - if (!handle->accept_reqs) { + if (!ipc_header_req) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } } diff --git a/src/win/tcp.c b/src/win/tcp.c index dee77875..7965f73a 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -822,7 +822,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, if (!REQ_SUCCESS(req)) { /* An error occurred doing the read. */ - if ((handle->flags & UV_HANDLE_READING)) { + if ((handle->flags & UV_HANDLE_READING) || + !(handle->flags & UV_HANDLE_ZERO_READ)) { handle->flags &= ~UV_HANDLE_READING; buf = (handle->flags & UV_HANDLE_ZERO_READ) ? uv_buf_init(NULL, 0) : handle->read_buffer;