diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 4fc93693..1003201f 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)); diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 871d0e7d..42f990f3 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -27,16 +27,16 @@ 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; 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); } @@ -137,7 +137,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 { @@ -291,7 +291,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"); } @@ -328,3 +328,95 @@ 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; +} + + +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 ed27cf12..634d5677 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -138,6 +138,8 @@ 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_event_close_in_callback); TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (fs_readdir_file) TEST_DECLARE (fs_open_dir) @@ -339,6 +341,8 @@ 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_event_close_in_callback) TEST_ENTRY (fs_readdir_empty_dir) TEST_ENTRY (fs_readdir_file) TEST_ENTRY (fs_open_dir)