int main(int argc, const char *argv[]) { /* * a subprocess will initially inherit the process group of its parent. the * process group may have a control terminal associated with it, which would * be the first tty device opened by the group leader. typically the group * leader is your shell and the control terminal is your login device. a * subset of signals triggered on the control terminal are sent to all members * of the process group, in large part to facilitate sane and consistent * cleanup (ex: control terminal was closed). * * so why the overly descriptive lecture style comment? * 1. SIGINT and SIGQUIT are among the signals with this behavior * 2. a number of applications gank the above for their own use * 3. ruby's insanely useful "guard" is one of these applications * 4. despite having some level of understanding of POSIX signals and a few * of the scenarios that might cause problems, i learned this one only * after reading ruby 1.9's process.c * 5. if left completely undocumented, even slightly obscure bugfixes * may be removed as cruft by a future maintainer * * hindsight is 20/20 addition: if you're single-threaded and blocking on IO * with a subprocess, then handlers for deferrable signals might not get run * when you expect them to. In the case of Ruby 1.8, that means making use of * IO::select, which will preserve correct signal handling behavior. */ if (setpgid(0,0) < 0) { fprintf(stderr, "Unable to set new process group.\n"); return 1; } parse_cli_settings(argc, argv); FSEventStreamContext context = {0, NULL, NULL, NULL, NULL}; FSEventStreamRef stream; stream = FSEventStreamCreate(kCFAllocatorDefault, (FSEventStreamCallback)&callback, &context, config.paths, config.sinceWhen, config.latency, config.flags); #ifdef DEBUG FSEventStreamShow(stream); fprintf(stderr, "\n"); fflush(stderr); #endif FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); FSEventStreamStart(stream); CFRunLoopRun(); FSEventStreamFlushSync(stream); FSEventStreamStop(stream); return 0; }
static FSEventStreamRef my_FSEventStreamCreate(const char **paths, size_t num_paths) { void *user_data = (void *)(num_paths ? paths[0] : "?"); FSEventStreamContext context = {0, user_data, NULL, NULL, NULL}; FSEventStreamRef streamRef = NULL; CFMutableArrayRef cfArray; // Settings FSEventStreamEventId sinceWhen = kFSEventStreamEventIdSinceNow; int flags = 0; CFAbsoluteTime latency = 5.0; // How long it takes from that something // happened to an event is dispatched. // Used as buffer for absolutize_path char abspath[PATH_MAX]; // Create paths array cfArray = CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks); if (NULL == cfArray) { log_error("CFArrayCreateMutable() => NULL"); goto Return; } // Add paths to array for(int i=0; i<num_paths; i++) { absolutize_path(paths[i], abspath); CFStringRef cfStr = CFStringCreateWithCString(kCFAllocatorDefault, abspath, kCFStringEncodingUTF8); if (NULL == cfStr) { CFRelease(cfArray); goto Return; } CFArraySetValueAtIndex(cfArray, i, cfStr); CFRelease(cfStr); } // Create the stream streamRef = FSEventStreamCreate(kCFAllocatorDefault, (FSEventStreamCallback)&fsevents_callback, &context, cfArray, /*settings->*/sinceWhen, /*settings->*/latency, /*settings->*/flags); // Check if FSEventStreamCreate failed if (NULL == streamRef) { log_error("FSEventStreamCreate() failed"); goto Return; } // Print the setup IFDEBUG( FSEventStreamShow(streamRef); )
static FSEventStreamRef add_watch (SeafWTMonitor *monitor, const char* repo_id, const char* worktree) { SeafWTMonitorPriv *priv = monitor->priv; const char *path = worktree; RepoWatchInfo *info; double latency = 0.25; /* unit: second */ CFStringRef mypath = CFStringCreateWithCString (kCFAllocatorDefault, path, kCFStringEncodingUTF8); CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL); FSEventStreamRef stream; /* Create the stream, passing in a callback */ struct FSEventStreamContext ctx = {0, monitor, NULL, NULL, NULL}; stream = FSEventStreamCreate(kCFAllocatorDefault, stream_callback, &ctx, pathsToWatch, kFSEventStreamEventIdSinceNow, latency, kFSEventStreamCreateFlagFileEvents /* deprecated OSX 10.6 support*/ ); CFRelease (mypath); CFRelease (pathsToWatch); if (!stream) { seaf_warning ("[wt] Failed to create event stream \n"); return stream; } FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); FSEventStreamStart (stream); #ifdef FSEVENT_DEBUG FSEventStreamShow (stream); seaf_debug ("[wt mon] Add repo %s watch success :%s.\n", repo_id, repo->worktree); #endif pthread_mutex_lock (&priv->hash_lock); g_hash_table_insert (priv->handle_hash, g_strdup(repo_id), (gpointer)(long)stream); info = create_repo_watch_info (repo_id, worktree); g_hash_table_insert (priv->info_hash, (gpointer)(long)stream, info); pthread_mutex_unlock (&priv->hash_lock); /* An empty path indicates repo-mgr to scan the whole worktree. */ add_event_to_queue (info->status, WT_EVENT_CREATE_OR_UPDATE, "", NULL); return stream; }
static FSEventStreamRef add_watch (SeafWTMonitorPriv *priv, const char* repo_id) { SeafRepo *repo = NULL; const char *path = NULL; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { seaf_warning ("[wt mon] cannot find repo %s.\n", repo_id); return 0; } path = repo->worktree; CFStringRef mypath = CFStringCreateWithCString (kCFAllocatorDefault, path, kCFStringEncodingUTF8); CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL); FSEventStreamRef stream; /* Create the stream, passing in a callback */ struct FSEventStreamContext ctx = {0, priv, NULL, NULL, NULL}; stream = FSEventStreamCreate(kCFAllocatorDefault, stream_callback, &ctx, pathsToWatch, kFSEventStreamEventIdSinceNow, 1.0, kFSEventStreamCreateFlagWatchRoot ); CFRelease (mypath); CFRelease (pathsToWatch); if (!stream) { seaf_warning ("[wt] Failed to create event stream \n"); return stream; } FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); FSEventStreamStart (stream); #ifdef FSEVENT_DEBUG FSEventStreamShow (stream); seaf_debug ("[wt mon] Add repo %s watch success :%s.\n", repo_id, repo->worktree); #endif return stream; }