diff --git a/Makefile.am b/Makefile.am index 99a4436e..bde152e0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -197,9 +197,6 @@ libuv_la_SOURCES += src/unix/darwin.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ src/unix/proctitle.c -libuv_la_LDFLAGS += -framework ApplicationServices \ - -framework CoreServices \ - -framework Foundation endif if FREEBSD diff --git a/src/unix/darwin-proctitle.c b/src/unix/darwin-proctitle.c index 90b2e418..c5f53a08 100644 --- a/src/unix/darwin-proctitle.c +++ b/src/unix/darwin-proctitle.c @@ -55,62 +55,111 @@ int uv__set_process_title(const char* title) { #if TARGET_OS_IPHONE return uv__pthread_setname_np(title); #else - typedef CFTypeRef (*LSGetCurrentApplicationASNType)(void); - typedef OSStatus (*LSSetApplicationInformationItemType)(int, - CFTypeRef, - CFStringRef, - CFStringRef, - CFDictionaryRef*); + CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, + const char*, + CFStringEncoding); + CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef); + void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef); + void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef); + OSErr (*pGetCurrentProcess)(ProcessSerialNumber*); + CFTypeRef (*pLSGetCurrentApplicationASN)(void); + OSStatus (*pLSSetApplicationInformationItem)(int, + CFTypeRef, + CFStringRef, + CFStringRef, + CFDictionaryRef*); + void* application_services_handle; + void* core_foundation_handle; CFBundleRef launch_services_bundle; - LSGetCurrentApplicationASNType ls_get_current_application_asn; - LSSetApplicationInformationItemType ls_set_application_information_item; CFStringRef* display_name_key; ProcessSerialNumber psn; CFTypeRef asn; - CFStringRef display_name; - OSStatus err; + int err; + + err = -ENOENT; + application_services_handle = dlopen("/System/Library/Frameworks/" + "ApplicationServices.framework/" + "Versions/A/ApplicationServices", + RTLD_LAZY | RTLD_LOCAL); + core_foundation_handle = dlopen("/System/Library/Frameworks/" + "CoreFoundation.framework/" + "Versions/A/CoreFoundation", + RTLD_LAZY | RTLD_LOCAL); + + if (application_services_handle == NULL || core_foundation_handle == NULL) + goto out; + + pGetCurrentProcess = + dlsym(application_services_handle, "GetCurrentProcess"); + pCFStringCreateWithCString = + dlsym(core_foundation_handle, "CFStringCreateWithCString"); + pCFBundleGetBundleWithIdentifier = + dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier"); + pCFBundleGetDataPointerForName = + dlsym(core_foundation_handle, "CFBundleGetDataPointerForName"); + pCFBundleGetFunctionPointerForName = + dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName"); + + if (pGetCurrentProcess == NULL || + pCFStringCreateWithCString == NULL || + pCFBundleGetBundleWithIdentifier == NULL || + pCFBundleGetDataPointerForName == NULL || + pCFBundleGetFunctionPointerForName == NULL) { + goto out; + } + +#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) launch_services_bundle = - CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices")); + pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices")); if (launch_services_bundle == NULL) - return -ENOENT; + goto out; - ls_get_current_application_asn = (LSGetCurrentApplicationASNType) - CFBundleGetFunctionPointerForName(launch_services_bundle, - CFSTR("_LSGetCurrentApplicationASN")); + pLSGetCurrentApplicationASN = + pCFBundleGetFunctionPointerForName(launch_services_bundle, + S("_LSGetCurrentApplicationASN")); - if (ls_get_current_application_asn == NULL) - return -ENOENT; + if (pLSGetCurrentApplicationASN == NULL) + goto out; - ls_set_application_information_item = (LSSetApplicationInformationItemType) - CFBundleGetFunctionPointerForName(launch_services_bundle, - CFSTR("_LSSetApplicationInformationItem")); + pLSSetApplicationInformationItem = + pCFBundleGetFunctionPointerForName(launch_services_bundle, + S("_LSSetApplicationInformationItem")); - if (ls_set_application_information_item == NULL) - return -ENOENT; + if (pLSSetApplicationInformationItem == NULL) + goto out; - display_name_key = CFBundleGetDataPointerForName(launch_services_bundle, - CFSTR("_kLSDisplayNameKey")); + display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle, + S("_kLSDisplayNameKey")); if (display_name_key == NULL || *display_name_key == NULL) - return -ENOENT; + goto out; /* Force the process manager to initialize. */ - GetCurrentProcess(&psn); + pGetCurrentProcess(&psn); - display_name = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8); - asn = ls_get_current_application_asn(); - err = ls_set_application_information_item(-2, /* Magic value. */ - asn, - *display_name_key, - display_name, - NULL); - if (err != noErr) - return -ENOENT; + asn = pLSGetCurrentApplicationASN(); + + err = -EINVAL; + if (pLSSetApplicationInformationItem(-2, /* Magic value. */ + asn, + *display_name_key, + S(title), + NULL) != noErr) { + goto out; + } uv__pthread_setname_np(title); /* Don't care if it fails. */ + err = 0; - return 0; +out: + if (core_foundation_handle != NULL) + dlclose(core_foundation_handle); + + if (application_services_handle != NULL) + dlclose(application_services_handle); + + return err; #endif /* !TARGET_OS_IPHONE */ } diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index 4d5e87fe..54da4289 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -40,6 +40,7 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) { #else /* TARGET_OS_IPHONE */ +#include #include #include #include @@ -94,6 +95,47 @@ static void uv__cf_loop_cb(void* arg); static void* uv__cf_loop_runner(void* arg); static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle); +/* Lazy-loaded by uv__fsevents_global_init(). */ +static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef, + const void**, + CFIndex, + const CFArrayCallBacks*); +static void (*pCFRelease)(CFTypeRef); +static void (*pCFRunLoopAddSource)(CFRunLoopRef, + CFRunLoopSourceRef, + CFStringRef); +static CFRunLoopRef (*pCFRunLoopGetCurrent)(void); +static void (*pCFRunLoopRemoveSource)(CFRunLoopRef, + CFRunLoopSourceRef, + CFStringRef); +static void (*pCFRunLoopRun)(void); +static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef, + CFIndex, + CFRunLoopSourceContext*); +static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef); +static void (*pCFRunLoopStop)(CFRunLoopRef); +static void (*pCFRunLoopWakeUp)(CFRunLoopRef); +static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, + const char*, + CFStringEncoding); +static CFStringEncoding (*pCFStringGetSystemEncoding)(void); +static CFStringRef (*pkCFRunLoopDefaultMode); +static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef, + FSEventStreamCallback, + FSEventStreamContext*, + CFArrayRef, + FSEventStreamEventId, + CFTimeInterval, + FSEventStreamCreateFlags); +static void (*pFSEventStreamFlushSync)(FSEventStreamRef); +static void (*pFSEventStreamInvalidate)(FSEventStreamRef); +static void (*pFSEventStreamRelease)(FSEventStreamRef); +static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef, + CFRunLoopRef, + CFStringRef); +static Boolean (*pFSEventStreamStart)(FSEventStreamRef); +static void (*pFSEventStreamStop)(FSEventStreamRef); + #define UV__FSEVENTS_PROCESS(handle, block) \ do { \ uv__fsevents_event_t* event; \ @@ -256,20 +298,20 @@ static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { * that is being watched now. Which will cause FSEventStream API to report * changes to files from the past. */ - ref = FSEventStreamCreate(NULL, - &uv__fsevents_event_cb, - &ctx, - paths, - kFSEventStreamEventIdSinceNow, - latency, - flags); + ref = pFSEventStreamCreate(NULL, + &uv__fsevents_event_cb, + &ctx, + paths, + kFSEventStreamEventIdSinceNow, + latency, + flags); assert(ref != NULL); state = loop->cf_state; - FSEventStreamScheduleWithRunLoop(ref, - state->loop, - kCFRunLoopDefaultMode); - if (!FSEventStreamStart(ref)) + pFSEventStreamScheduleWithRunLoop(ref, + state->loop, + *pkCFRunLoopDefaultMode); + if (!pFSEventStreamStart(ref)) abort(); state->fsevent_stream = ref; @@ -286,14 +328,14 @@ static void uv__fsevents_destroy_stream(uv_loop_t* loop) { return; /* Flush all accumulated events */ - FSEventStreamFlushSync(state->fsevent_stream); + pFSEventStreamFlushSync(state->fsevent_stream); /* Stop emitting events */ - FSEventStreamStop(state->fsevent_stream); + pFSEventStreamStop(state->fsevent_stream); /* Release stream */ - FSEventStreamInvalidate(state->fsevent_stream); - FSEventStreamRelease(state->fsevent_stream); + pFSEventStreamInvalidate(state->fsevent_stream); + pFSEventStreamRelease(state->fsevent_stream); state->fsevent_stream = NULL; } @@ -335,9 +377,9 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle) { curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); assert(curr->realpath != NULL); - paths[i] = CFStringCreateWithCString(NULL, - curr->realpath, - CFStringGetSystemEncoding()); + paths[i] = pCFStringCreateWithCString(NULL, + curr->realpath, + pCFStringGetSystemEncoding()); if (paths[i] == NULL) abort(); } @@ -346,7 +388,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle) { if (path_count != 0) { /* Create new FSEventStream */ - cf_paths = CFArrayCreate(NULL, (const void**) paths, path_count, NULL); + cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL); if (cf_paths == NULL) abort(); uv__fsevents_create_stream(handle->loop, cf_paths); @@ -363,6 +405,84 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle) { } +static int uv__fsevents_global_init(void) { + static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER; + static void* core_foundation_handle; + static void* core_services_handle; + int err; + + err = 0; + pthread_mutex_lock(&global_init_mutex); + if (core_foundation_handle != NULL) + goto out; + + /* The libraries are never unloaded because we currently don't have a good + * mechanism for keeping a reference count. It's unlikely to be an issue + * but if it ever becomes one, we can turn the dynamic library handles into + * per-event loop properties and have the dynamic linker keep track for us. + */ + err = -ENOSYS; + core_foundation_handle = dlopen("/System/Library/Frameworks/" + "CoreFoundation.framework/" + "Versions/A/CoreFoundation", + RTLD_LAZY | RTLD_LOCAL); + if (core_foundation_handle == NULL) + goto out; + + core_services_handle = dlopen("/System/Library/Frameworks/" + "CoreServices.framework/" + "Versions/A/CoreServices", + RTLD_LAZY | RTLD_LOCAL); + if (core_services_handle == NULL) + goto out; + + err = -ENOENT; +#define V(handle, symbol) \ + do { \ + p ## symbol = dlsym((handle), #symbol); \ + if (p ## symbol == NULL) \ + goto out; \ + } \ + while (0) + V(core_foundation_handle, CFArrayCreate); + V(core_foundation_handle, CFRelease); + V(core_foundation_handle, CFRunLoopAddSource); + V(core_foundation_handle, CFRunLoopGetCurrent); + V(core_foundation_handle, CFRunLoopRemoveSource); + V(core_foundation_handle, CFRunLoopRun); + V(core_foundation_handle, CFRunLoopSourceCreate); + V(core_foundation_handle, CFRunLoopSourceSignal); + V(core_foundation_handle, CFRunLoopStop); + V(core_foundation_handle, CFRunLoopWakeUp); + V(core_foundation_handle, CFStringCreateWithCString); + V(core_foundation_handle, CFStringGetSystemEncoding); + V(core_foundation_handle, kCFRunLoopDefaultMode); + V(core_services_handle, FSEventStreamCreate); + V(core_services_handle, FSEventStreamFlushSync); + V(core_services_handle, FSEventStreamInvalidate); + V(core_services_handle, FSEventStreamRelease); + V(core_services_handle, FSEventStreamScheduleWithRunLoop); + V(core_services_handle, FSEventStreamStart); + V(core_services_handle, FSEventStreamStop); +#undef V + err = 0; + +out: + if (err && core_services_handle != NULL) { + dlclose(core_services_handle); + core_services_handle = NULL; + } + + if (err && core_foundation_handle != NULL) { + dlclose(core_foundation_handle); + core_foundation_handle = NULL; + } + + pthread_mutex_unlock(&global_init_mutex); + return err; +} + + /* Runs in UV loop */ static int uv__fsevents_loop_init(uv_loop_t* loop) { CFRunLoopSourceContext ctx; @@ -374,6 +494,10 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { if (loop->cf_state != NULL) return 0; + err = uv__fsevents_global_init(); + if (err) + return err; + state = calloc(1, sizeof(*state)); if (state == NULL) return -ENOMEM; @@ -403,7 +527,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { memset(&ctx, 0, sizeof(ctx)); ctx.info = loop; ctx.perform = uv__cf_loop_cb; - state->signal_source = CFRunLoopSourceCreate(NULL, 0, &ctx); + state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx); if (state->signal_source == NULL) { err = -ENOMEM; goto fail_signal_source_create; @@ -483,7 +607,7 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) { state = loop->cf_state; uv_sem_destroy(&state->fsevent_sem); uv_mutex_destroy(&state->fsevent_mutex); - CFRelease(state->signal_source); + pCFRelease(state->signal_source); free(state); loop->cf_state = NULL; } @@ -496,18 +620,18 @@ static void* uv__cf_loop_runner(void* arg) { loop = arg; state = loop->cf_state; - state->loop = CFRunLoopGetCurrent(); + state->loop = pCFRunLoopGetCurrent(); - CFRunLoopAddSource(state->loop, - state->signal_source, - kCFRunLoopDefaultMode); + pCFRunLoopAddSource(state->loop, + state->signal_source, + *pkCFRunLoopDefaultMode); uv_sem_post(&loop->cf_sem); - CFRunLoopRun(); - CFRunLoopRemoveSource(state->loop, - state->signal_source, - kCFRunLoopDefaultMode); + pCFRunLoopRun(); + pCFRunLoopRemoveSource(state->loop, + state->signal_source, + *pkCFRunLoopDefaultMode); return NULL; } @@ -539,7 +663,7 @@ static void uv__cf_loop_cb(void* arg) { /* This was a termination signal */ if (s->handle == NULL) - CFRunLoopStop(state->loop); + pCFRunLoopStop(state->loop); else uv__fsevents_reschedule(s->handle); @@ -566,8 +690,8 @@ int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) { state = loop->cf_state; assert(state != NULL); - CFRunLoopSourceSignal(state->signal_source); - CFRunLoopWakeUp(state->loop); + pCFRunLoopSourceSignal(state->signal_source); + pCFRunLoopWakeUp(state->loop); return 0; } diff --git a/uv.gyp b/uv.gyp index 3b2533c7..3c662438 100644 --- a/uv.gyp +++ b/uv.gyp @@ -186,13 +186,6 @@ 'src/unix/fsevents.c', 'src/unix/darwin-proctitle.c', ], - 'link_settings': { - 'libraries': [ - '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', - '$(SDKROOT)/System/Library/Frameworks/CoreServices.framework', - '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework', - ], - }, 'defines': [ '_DARWIN_USE_64_BIT_INODE=1', ]