fsevents: FSEvents is most likely not thread-safe

Perform all operation with FSEventStream in the same thread, where it'll
be used.

Conflicts:
	src/unix/fsevents.c
This commit is contained in:
Fedor Indutny 2013-08-14 17:14:35 +04:00
parent 9bae606d41
commit ea4cb77814
2 changed files with 64 additions and 45 deletions

View File

@ -212,12 +212,67 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
static void uv__fsevents_schedule(void* arg) { static void uv__fsevents_schedule(void* arg) {
uv_fs_event_t* handle; uv_fs_event_t* handle;
FSEventStreamContext ctx;
FSEventStreamRef ref;
CFStringRef path;
CFArrayRef paths;
CFAbsoluteTime latency;
FSEventStreamCreateFlags flags;
handle = arg; handle = arg;
/* Initialize context */
ctx.version = 0;
ctx.info = handle;
ctx.retain = NULL;
ctx.release = NULL;
ctx.copyDescription = NULL;
/* Initialize paths array */
path = CFStringCreateWithCString(NULL,
handle->filename,
CFStringGetSystemEncoding());
assert(path != NULL);
paths = CFArrayCreate(NULL, (const void**)&path, 1, NULL);
assert(paths != NULL);
latency = 0.15;
/* Set appropriate flags */
flags = kFSEventStreamCreateFlagFileEvents;
ref = FSEventStreamCreate(NULL,
&uv__fsevents_event_cb,
&ctx,
paths,
kFSEventStreamEventIdSinceNow,
latency,
flags);
assert(ref != NULL);
handle->cf_eventstream = ref;
FSEventStreamScheduleWithRunLoop(handle->cf_eventstream, FSEventStreamScheduleWithRunLoop(handle->cf_eventstream,
handle->loop->cf_loop, handle->loop->cf_loop,
kCFRunLoopDefaultMode); kCFRunLoopDefaultMode);
FSEventStreamStart(handle->cf_eventstream); if (!FSEventStreamStart(handle->cf_eventstream))
abort();
}
static void uv__fsevents_unschedule(void* arg) {
uv_fs_event_t* handle;
handle = arg;
/* Stop emitting events */
FSEventStreamStop(handle->cf_eventstream);
/* Release stream */
FSEventStreamInvalidate(handle->cf_eventstream);
FSEventStreamRelease(handle->cf_eventstream);
handle->cf_eventstream = NULL;
/* Notify main thread that we're done here */
uv_sem_post(&handle->cf_sem); uv_sem_post(&handle->cf_sem);
} }
@ -357,50 +412,18 @@ void uv__cf_loop_signal(uv_loop_t* loop, cf_loop_signal_cb cb, void* arg) {
int uv__fsevents_init(uv_fs_event_t* handle) { int uv__fsevents_init(uv_fs_event_t* handle) {
FSEventStreamContext ctx;
FSEventStreamRef ref;
CFStringRef path;
CFArrayRef paths;
CFAbsoluteTime latency;
FSEventStreamCreateFlags flags;
int err; int err;
err = uv__fsevents_loop_init(handle->loop); err = uv__fsevents_loop_init(handle->loop);
if (err) if (err)
return err; return err;
/* Initialize context */
ctx.version = 0;
ctx.info = handle;
ctx.retain = NULL;
ctx.release = NULL;
ctx.copyDescription = NULL;
/* Get absolute path to file */ /* Get absolute path to file */
handle->realpath = realpath(handle->filename, NULL); handle->realpath = realpath(handle->filename, NULL);
if (handle->realpath != NULL) if (handle->realpath != NULL)
handle->realpath_len = strlen(handle->realpath); handle->realpath_len = strlen(handle->realpath);
/* Initialize paths array */ handle->cf_eventstream = NULL;
path = CFStringCreateWithCString(NULL,
handle->filename,
CFStringGetSystemEncoding());
paths = CFArrayCreate(NULL, (const void**)&path, 1, NULL);
latency = 0.15;
/* Set appropriate flags */
flags = kFSEventStreamCreateFlagFileEvents;
ref = FSEventStreamCreate(NULL,
&uv__fsevents_event_cb,
&ctx,
paths,
kFSEventStreamEventIdSinceNow,
latency,
flags);
handle->cf_eventstream = ref;
/* /*
* Events will occur in other thread. * Events will occur in other thread.
* Initialize callback for getting them back into event loop's thread * Initialize callback for getting them back into event loop's thread
@ -425,21 +448,16 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
int uv__fsevents_close(uv_fs_event_t* handle) { int uv__fsevents_close(uv_fs_event_t* handle) {
if (handle->cf_eventstream == NULL) if (handle->cf_cb == NULL)
return -1; return -EINVAL;
/* Ensure that event stream was scheduled */ uv__cf_loop_signal(handle->loop, uv__fsevents_unschedule, handle);
/* Wait for deinitialization */
uv_sem_wait(&handle->cf_sem); uv_sem_wait(&handle->cf_sem);
/* Stop emitting events */
FSEventStreamStop(handle->cf_eventstream);
/* Release stream */
FSEventStreamInvalidate(handle->cf_eventstream);
FSEventStreamRelease(handle->cf_eventstream);
handle->cf_eventstream = NULL;
uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) free); uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) free);
handle->cf_cb = NULL;
/* Free data in queue */ /* Free data in queue */
UV__FSEVENTS_WALK(handle, { UV__FSEVENTS_WALK(handle, {

View File

@ -307,6 +307,7 @@ int uv_fs_event_init(uv_loop_t* loop,
#if defined(__APPLE__) #if defined(__APPLE__)
/* Nullify field to perform checks later */ /* Nullify field to perform checks later */
handle->cf_cb = NULL;
handle->cf_eventstream = NULL; handle->cf_eventstream = NULL;
handle->realpath = NULL; handle->realpath = NULL;
handle->realpath_len = 0; handle->realpath_len = 0;