From 6dcce92d446311d740203fecfe35fbb8a7dd260a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 9 Mar 2012 09:15:43 -0800 Subject: [PATCH 01/10] unix: replace C99/C++ comments, fix build --- test/test-ref.c | 4 ++-- test/test-tty.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test-ref.c b/test/test-ref.c index 9a474b56..cab3a703 100644 --- a/test/test-ref.c +++ b/test/test-ref.c @@ -45,7 +45,7 @@ static void write_unref_cb(uv_connect_t* req, int status) { ASSERT(status == 0); uv_write(&write_req, req->handle, &buf, 1, (uv_write_cb) fail_cb); - uv_unref(uv_default_loop()); // uv_write refs the loop + uv_unref(uv_default_loop()); /* uv_write refs the loop */ } @@ -55,7 +55,7 @@ static void shutdown_unref_cb(uv_connect_t* req, int status) { ASSERT(status == 0); uv_shutdown(&shutdown_req, req->handle, (uv_shutdown_cb) fail_cb); - uv_unref(uv_default_loop()); // uv_shutdown refs the loop + uv_unref(uv_default_loop()); /* uv_shutdown refs the loop */ } diff --git a/test/test-tty.c b/test/test-tty.c index 24f0def6..ded59c9f 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -25,7 +25,7 @@ #ifdef _WIN32 # include # include -#else // Unix +#else /* Unix */ # include # include #endif @@ -37,7 +37,7 @@ TEST_IMPL(tty) { uv_tty_t tty_in, tty_out; uv_loop_t* loop = uv_default_loop(); - // Make sure we have an FD that refers to a tty + /* Make sure we have an FD that refers to a tty */ #ifdef _WIN32 HANDLE handle; handle = CreateFileA("conin$", From 66a959c405222da90765dbcc28c8d0d0bbe4d3cf Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 15 Mar 2012 01:01:19 +0100 Subject: [PATCH 02/10] linux: try inotify_init if inotify_init1 returns ENOSYS The kernel may be older than the kernel headers that libuv is compiled against. --- src/unix/linux.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 3ed65653..809e644d 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -170,11 +170,16 @@ uint64_t uv_get_total_memory(void) { #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 HAVE_INOTIFY_INIT1 + fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (fd != -1) + return fd; + if (errno != ENOSYS) + return -1; +#endif + if ((fd = inotify_init()) == -1) return -1; @@ -184,7 +189,6 @@ static int new_inotify_fd(void) { } return fd; -#endif } From 163d8de392df7bc8b2f87ccb62a3e8c1a49eef92 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 16 Mar 2012 02:28:26 +0100 Subject: [PATCH 03/10] Add UV_ENOSPC and mappings to it Closes GH-337 --- include/uv.h | 3 ++- src/unix/error.c | 1 + src/win/error.c | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index fa9812cd..49ce47a9 100644 --- a/include/uv.h +++ b/include/uv.h @@ -120,7 +120,8 @@ typedef intptr_t ssize_t; XX( 50, EPERM, "operation not permitted") \ XX( 51, ELOOP, "too many symbolic links encountered") \ XX( 52, EXDEV, "cross-device link not permitted") \ - XX( 53, ENOTEMPTY, "directory not empty") + XX( 53, ENOTEMPTY, "directory not empty") \ + XX( 54, ENOSPC, "no space left on device") #define UV_ERRNO_GEN(val, name, s) UV_##name = val, diff --git a/src/unix/error.c b/src/unix/error.c index 071b03af..d99d4112 100644 --- a/src/unix/error.c +++ b/src/unix/error.c @@ -90,6 +90,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case EXDEV: return UV_EXDEV; case EBUSY: return UV_EBUSY; case ENOTEMPTY: return UV_ENOTEMPTY; + case ENOSPC: return UV_ENOSPC; default: return UV_UNKNOWN; } diff --git a/src/win/error.c b/src/win/error.c index 5d695696..dccd2e71 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -104,6 +104,11 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case WSAENETUNREACH: return UV_ENETUNREACH; case WSAENOBUFS: return UV_ENOBUFS; case ERROR_OUTOFMEMORY: return UV_ENOMEM; + case ERROR_CANNOT_MAKE: return UV_ENOSPC; + case ERROR_DISK_FULL: return UV_ENOSPC; + case ERROR_EA_TABLE_FULL: return UV_ENOSPC; + case ERROR_END_OF_MEDIA: return UV_ENOSPC; + case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC; case ERROR_NOT_CONNECTED: return UV_ENOTCONN; case WSAENOTCONN: return UV_ENOTCONN; case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY; From 4ae316bcc93d137d2ece2bcf6a8a85fca983a41b Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 16 Mar 2012 02:38:37 +0100 Subject: [PATCH 04/10] Windows: fix compiler warnings --- src/win/winapi.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/win/winapi.h b/src/win/winapi.h index b65ef0d0..a98806ae 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4323,10 +4323,17 @@ typedef NTSTATUS (NTAPI *sNtSetInformationFile) /* * Kernel32 headers */ -#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1 -#define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 +#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS +# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1 +#endif -#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#ifndef FILE_SKIP_SET_EVENT_ON_HANDLE +# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 +#endif + +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#endif #ifdef __MINGW32__ typedef struct _OVERLAPPED_ENTRY { From 8409a6765bbda8d68cb3f2e48a1ce0a3d4814096 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 21 Mar 2012 07:07:18 -0700 Subject: [PATCH 05/10] unix: ignore ECONNABORTED errors from accept() ECONNABORTED means that the connection was torn down by the peer before the TCP handshake completed. Ignore it, there's nothing we can do and it simplifies error handling for libuv users. --- src/unix/stream.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/unix/stream.c b/src/unix/stream.c index 111bbc2d..eee4199f 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -182,6 +182,9 @@ void uv__server_io(EV_P_ ev_io* watcher, int revents) { } else if (errno == EMFILE) { /* TODO special trick. unlock reserved socket, accept, close. */ return; + } else if (errno == ECONNABORTED) { + /* ignore */ + continue; } else { uv__set_sys_error(stream->loop, errno); stream->connection_cb((uv_stream_t*)stream, -1); From 7e8fe3ece7392a36a283ba6ff4e57bc8cb617d34 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 27 Mar 2012 22:56:51 +0200 Subject: [PATCH 06/10] test-fs-event.c: style --- test/test-fs-event.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 7f02e68a..f09daa3f 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -27,10 +27,10 @@ static uv_fs_event_t fs_event; static uv_timer_t timer; -static int timer_cb_called; -static int close_cb_called; -static int fs_event_cb_called; -static int timer_cb_touch_called; +static int timer_cb_called = 0; +static int close_cb_called = 0; +static int fs_event_cb_called = 0; +static int timer_cb_touch_called = 0; static void create_dir(uv_loop_t* loop, const char* name) { int r; @@ -117,7 +117,7 @@ static void timer_cb_dir(uv_timer_t* handle, int status) { static void timer_cb_file(uv_timer_t* handle, int status) { ++timer_cb_called; - + if (timer_cb_called == 1) { touch_file(handle->loop, "watch_dir/file1"); } else { @@ -271,7 +271,7 @@ TEST_IMPL(fs_event_no_callback_on_close) { static void fs_event_fail(uv_fs_event_t* handle, const char* filename, - int events, int status) { + int events, int status) { ASSERT(0 && "should never be called"); } From 89303f365e85bff909a821e2a552e7e2e35c255a Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 27 Mar 2012 22:50:52 +0200 Subject: [PATCH 07/10] Fs event tests: don't fail if a previously failed test left stray files --- test/test-fs-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index f09daa3f..dfbdea32 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -36,7 +36,7 @@ static void create_dir(uv_loop_t* loop, const char* name) { int r; uv_fs_t req; r = uv_fs_mkdir(loop, &req, name, 0755, NULL); - ASSERT(r == 0); + ASSERT(r == 0 || uv_last_error(loop).code == UV_EEXIST); uv_fs_req_cleanup(&req); } From 732cf91d6d0d6a711183985c1796a31565708bb2 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 27 Mar 2012 22:56:34 +0200 Subject: [PATCH 08/10] Test: verify that no callbacks are made after closing an fs event watcher --- test/test-fs-event.c | 32 ++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 2 files changed, 34 insertions(+) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index dfbdea32..70c4d507 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -308,3 +308,35 @@ TEST_IMPL(fs_event_immediate_close) { return 0; } + + +TEST_IMPL(fs_event_close_with_pending_event) { + uv_loop_t* loop; + uv_fs_t fs_req; + int r; + + loop = uv_default_loop(); + + create_dir(loop, "watch_dir"); + create_file(loop, "watch_dir/file"); + + r = uv_fs_event_init(loop, &fs_event, "watch_dir", fs_event_fail, 0); + ASSERT(r == 0); + + /* Generate an fs event. */ + touch_file(loop, "watch_dir/file"); + + uv_close((uv_handle_t*)&fs_event, close_cb); + + uv_run(loop); + + ASSERT(close_cb_called == 1); + + /* Clean up */ + r = uv_fs_unlink(loop, &fs_req, "watch_dir/file", NULL); + ASSERT(r == 0); + r = uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL); + ASSERT(r == 0); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 9e5309c1..2a8416ce 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -131,6 +131,7 @@ TEST_DECLARE (fs_event_watch_file) TEST_DECLARE (fs_event_watch_file_current_dir) TEST_DECLARE (fs_event_no_callback_on_close) TEST_DECLARE (fs_event_immediate_close) +TEST_DECLARE (fs_event_close_with_pending_event) TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (fs_readdir_file) TEST_DECLARE (fs_open_dir) @@ -315,6 +316,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_watch_file_current_dir) TEST_ENTRY (fs_event_no_callback_on_close) TEST_ENTRY (fs_event_immediate_close) + TEST_ENTRY (fs_event_close_with_pending_event) TEST_ENTRY (fs_readdir_empty_dir) TEST_ENTRY (fs_readdir_file) TEST_ENTRY (fs_open_dir) From aff078390ff45077f12ea31d00516bf9a8e2f08e Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 27 Mar 2012 22:52:53 +0200 Subject: [PATCH 09/10] Test: verify that uv_close from an fs event callback works properly --- test/test-fs-event.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 2 files changed, 62 insertions(+) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 70c4d507..f59a928f 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -340,3 +340,63 @@ TEST_IMPL(fs_event_close_with_pending_event) { return 0; } + + +static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, + int events, int status) { + ASSERT(status == 0); + + ASSERT(fs_event_cb_called < 3); + ++fs_event_cb_called; + + if (fs_event_cb_called == 3) { + uv_close((uv_handle_t*) handle, close_cb); + } +} + + +TEST_IMPL(fs_event_close_in_callback) { + uv_loop_t* loop; + uv_fs_t fs_req; + int r; + + loop = uv_default_loop(); + + create_dir(loop, "watch_dir"); + create_file(loop, "watch_dir/file1"); + create_file(loop, "watch_dir/file2"); + create_file(loop, "watch_dir/file3"); + create_file(loop, "watch_dir/file4"); + create_file(loop, "watch_dir/file5"); + + r = uv_fs_event_init(loop, &fs_event, "watch_dir", fs_event_cb_close, 0); + ASSERT(r == 0); + + /* Generate a couple of fs events. */ + touch_file(loop, "watch_dir/file1"); + touch_file(loop, "watch_dir/file2"); + touch_file(loop, "watch_dir/file3"); + touch_file(loop, "watch_dir/file4"); + touch_file(loop, "watch_dir/file5"); + + uv_run(loop); + + ASSERT(close_cb_called == 1); + ASSERT(fs_event_cb_called == 3); + + /* Clean up */ + r = uv_fs_unlink(loop, &fs_req, "watch_dir/file1", NULL); + ASSERT(r == 0); + r = uv_fs_unlink(loop, &fs_req, "watch_dir/file2", NULL); + ASSERT(r == 0); + r = uv_fs_unlink(loop, &fs_req, "watch_dir/file3", NULL); + ASSERT(r == 0); + r = uv_fs_unlink(loop, &fs_req, "watch_dir/file4", NULL); + ASSERT(r == 0); + r = uv_fs_unlink(loop, &fs_req, "watch_dir/file5", NULL); + ASSERT(r == 0); + r = uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL); + ASSERT(r == 0); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 2a8416ce..4c5e9f22 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -132,6 +132,7 @@ TEST_DECLARE (fs_event_watch_file_current_dir) TEST_DECLARE (fs_event_no_callback_on_close) TEST_DECLARE (fs_event_immediate_close) TEST_DECLARE (fs_event_close_with_pending_event) +TEST_DECLARE (fs_event_close_in_callback); TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (fs_readdir_file) TEST_DECLARE (fs_open_dir) @@ -317,6 +318,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_no_callback_on_close) TEST_ENTRY (fs_event_immediate_close) TEST_ENTRY (fs_event_close_with_pending_event) + TEST_ENTRY (fs_event_close_in_callback) TEST_ENTRY (fs_readdir_empty_dir) TEST_ENTRY (fs_readdir_file) TEST_ENTRY (fs_open_dir) From 1795427ab0d885cae3aa9bbcecb423c4bf863749 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 27 Mar 2012 22:53:30 +0200 Subject: [PATCH 10/10] Windows: never call fs event callbacks after closing the watcher --- src/win/fs-event.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 5a25e9d6..3b37c752 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -301,6 +301,13 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, assert(handle->req_pending); handle->req_pending = 0; + /* If we're closing, don't report any callbacks, and just push the handle */ + /* onto the endgame queue. */ + if (handle->flags & UV_HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*) handle); + return; + }; + file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset); if (REQ_SUCCESS(req)) { @@ -438,11 +445,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } offset = file_info->NextEntryOffset; - } while(offset); + } while (offset && !(handle->flags & UV_HANDLE_CLOSING)); } else { - if (!(handle->flags & UV_HANDLE_CLOSING)) { - handle->cb(handle, NULL, UV_CHANGE, 0); - } + handle->cb(handle, NULL, UV_CHANGE, 0); } } else { uv__set_sys_error(loop, GET_REQ_ERROR(req));