Skip to content

Commit

Permalink
fsevents: use FlagNoDefer for FSEventStreamCreate
Browse files Browse the repository at this point in the history
Otherwise `FSEventStreamCreate()` will coalesce events, even if they're
happening in the interval, bigger than supplied `latency`. In other
words, if this flag is not set events will happen in separate callback
only if there was a delay bigger than `latency` between two consecutive
events.
  • Loading branch information
indutny committed Nov 10, 2013
1 parent c6ecf97 commit 0f5c28b
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 18 deletions.
19 changes: 15 additions & 4 deletions src/unix/fsevents.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,21 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
ctx.release = NULL;
ctx.copyDescription = NULL;

latency = 0.15;

/* Set appropriate flags */
flags = kFSEventStreamCreateFlagFileEvents;
latency = 0.05;

/* Explanation of selected flags:
* 1. NoDefer - without this flag, events that are happening continuously
* (i.e. each event is happening after time interval less than `latency`,
* counted from previous event), will be deferred and passed to callback
* once they'll either fill whole OS buffer, or when this continuous stream
* will stop (i.e. there'll be delay between events, bigger than
* `latency`).
* Specifying this flag will invoke callback after `latency` time passed
* since event.
* 2. FileEvents - fire callback for file changes too (by default it is firing
* it only for directory changes).
*/
flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;

/*
* NOTE: It might sound like a good idea to remember last seen StreamEventId,
Expand Down
1 change: 1 addition & 0 deletions src/unix/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ void uv__fsevents_loop_delete(uv_loop_t* loop);
/* OSX < 10.7 has no file events, polyfill them */
#ifndef MAC_OS_X_VERSION_10_7

static const int kFSEventStreamCreateFlagNoDefer = 0x00000002;
static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
Expand Down
97 changes: 83 additions & 14 deletions test/test-fs-event.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,21 @@
#endif

static uv_fs_event_t fs_event;
static const char file_prefix[] = "fsevent-";
static uv_timer_t timer;
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 int timer_cb_called;
static int close_cb_called;
static const int fs_event_file_count = 128;
static int fs_event_created;
static int fs_event_cb_called;
#if defined(PATH_MAX)
static char fs_event_filename[PATH_MAX];
#else
static char fs_event_filename[1024];
#endif /* defined(PATH_MAX) */
static int timer_cb_touch_called;

static void fs_event_unlink_files(uv_timer_t* handle, int status);

static void create_dir(uv_loop_t* loop, const char* name) {
int r;
Expand Down Expand Up @@ -107,6 +117,69 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
uv_close((uv_handle_t*)handle, close_cb);
}

static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
const char* filename,
int events,
int status) {
fs_event_cb_called++;
ASSERT(handle == &fs_event);
ASSERT(status == 0);
ASSERT(events == UV_RENAME);
ASSERT(filename == NULL ||
strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);

/* Stop watching dir when received events about all files:
* both create and close events */
if (fs_event_cb_called == 2 * fs_event_file_count) {
ASSERT(0 == uv_fs_event_stop(handle));
uv_close((uv_handle_t*) handle, close_cb);
}
}

static const char* fs_event_get_filename(int i) {
snprintf(fs_event_filename,
sizeof(fs_event_filename),
"watch_dir/%s%d",
file_prefix,
i);
return fs_event_filename;
}

static void fs_event_create_files(uv_timer_t* handle, int status) {
int i;

/* Already created all files */
if (fs_event_created == fs_event_file_count) {
uv_close((uv_handle_t*) &timer, close_cb);
return;
}

/* Create all files */
for (i = 0; i < 16; i++, fs_event_created++)
create_file(handle->loop, fs_event_get_filename(i));

/* And unlink them */
ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 50, 0));
}

void fs_event_unlink_files(uv_timer_t* handle, int status) {
int r;
int i;

/* NOTE: handle might be NULL if invoked not as timer callback */

/* Unlink all files */
for (i = 0; i < 16; i++) {
r = remove(fs_event_get_filename(i));
if (handle != NULL)
ASSERT(r == 0);
}

/* And create them again */
if (handle != NULL)
ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 50, 0));
}

static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
int events, int status) {
++fs_event_cb_called;
Expand Down Expand Up @@ -148,12 +221,6 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
}
}

static void timer_cb_dir(uv_timer_t* handle, int status) {
++timer_cb_called;
create_file(handle->loop, "watch_dir/file1");
uv_close((uv_handle_t*)handle, close_cb);
}

static void timer_cb_file(uv_timer_t* handle, int status) {
++timer_cb_called;

Expand Down Expand Up @@ -184,27 +251,29 @@ TEST_IMPL(fs_event_watch_dir) {
int r;

/* Setup */
fs_event_unlink_files(NULL, 0);
remove("watch_dir/file2");
remove("watch_dir/file1");
remove("watch_dir/");
create_dir(loop, "watch_dir");

r = uv_fs_event_init(loop, &fs_event);
ASSERT(r == 0);
r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_dir", 0);
r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
ASSERT(r == 0);
r = uv_timer_init(loop, &timer);
ASSERT(r == 0);
r = uv_timer_start(&timer, timer_cb_dir, 100, 0);
r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
ASSERT(r == 0);

uv_run(loop, UV_RUN_DEFAULT);

ASSERT(fs_event_cb_called == 1);
ASSERT(timer_cb_called == 1);
ASSERT(fs_event_cb_called == 2 * fs_event_file_count);
ASSERT(fs_event_created == fs_event_file_count);
ASSERT(close_cb_called == 2);

/* Cleanup */
fs_event_unlink_files(NULL, 0);
remove("watch_dir/file2");
remove("watch_dir/file1");
remove("watch_dir/");
Expand Down

0 comments on commit 0f5c28b

Please sign in to comment.