bool wxFsEventsFileSystemWatcher::RemoveTree(const wxFileName& path) { wxString canonical = GetCanonicalPath(path); if ( canonical.empty() ) { return false; } // Remove any kqueue watches created with Add() // RemoveTree() should remove all watches no matter // if they are tree watches or single directory watches. wxArrayString dirsWatched; wxKqueueFileSystemWatcher::GetWatchedPaths(&dirsWatched); for ( size_t i = 0; i < dirsWatched.size(); i++ ) { if (dirsWatched[i].Find(canonical) == 0) { wxKqueueFileSystemWatcher::Remove(dirsWatched[i]); } } FSEventStreamRefMap::iterator it = m_streams.find(canonical); bool removed = false; if ( it != m_streams.end() ) { FSEventStreamStop(it->second); FSEventStreamInvalidate(it->second); FSEventStreamRelease(it->second); m_streams.erase(it); removed = true; } return removed; }
void event_cb(ConstFSEventStreamRef streamRef, void *ctx, size_t count, void *paths, const FSEventStreamEventFlags flags[], const FSEventStreamEventId ids[]) { file_paths_t *file_paths = (file_paths_t *)ctx; size_t i; size_t ignored_paths = 0; for (i = 0; i < count; i++) { char *path = ((char **)paths)[i]; /* flags are unsigned long, IDs are uint64_t */ printf("Change %llu in %s, flags %lu\n", ids[i], path, (long)flags[i]); size_t j; for (j = 0; j < file_paths->len; j++) { char *file_path = file_paths->paths[j]; printf("%s %s\n", file_path, path); if (strcmp(file_path, path) == 0) { printf("File %s changed.\n", file_path); exit(0); } } } if (count > ignored_paths) { /* OS X occasionally leaks event streams. Manually stop the stream just to make sure. */ FSEventStreamStop((FSEventStreamRef)streamRef); exit(0); } }
static void stopFSStream(FSEventStreamRef stream) { if (stream) { FSEventStreamStop(stream); FSEventStreamInvalidate(stream); } }
static VALUE t_stop(VALUE self) { FSEventStreamStop(stream); FSEventStreamInvalidate(stream); FSEventStreamRelease(stream); CFRunLoopStop(CFRunLoopGetCurrent()); return self; }
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 int handle_rm_repo (SeafWTMonitorPriv *priv, gpointer handle) { FSEventStreamRef stream = (FSEventStreamRef)handle; FSEventStreamStop (stream); FSEventStreamInvalidate (stream); FSEventStreamRelease (stream); return 0; }
void FileSystem::deinitializeInternalApple() { for (auto d : _directories) { DirectoryHandle* dh = d.second; FSEventStreamStop(dh->_eventStream); FSEventStreamInvalidate(dh->_eventStream); FSEventStreamRelease(dh->_eventStream); delete dh; } }
fse_stream::~fse_stream() { if (stream) { FSEventStreamStop(stream); FSEventStreamInvalidate(stream); FSEventStreamRelease(stream); } if (uuid) { CFRelease(uuid); } }
AppleReloadManager::~AppleReloadManager() { //Unregister from file system FSEventStreamStop(stream); FSEventStreamUnscheduleFromRunLoop(stream,CFRunLoopGetCurrent(),kCFRunLoopDefaultMode); FSEventStreamInvalidate(stream); FSEventStreamRelease(stream); //Destory the lock pthread_mutex_destroy(&AppleReloadManager::reloadMutex); }
MacFileSystemChangeNotifier::~MacFileSystemChangeNotifier() { for( U32 i = 0, num = mEvents.size(); i < num; ++ i ) { FSEventStreamStop( mEvents[ i ]->mStream ); FSEventStreamInvalidate( mEvents[ i ]->mStream ); FSEventStreamRelease( mEvents[ i ]->mStream ); SAFE_DELETE( mEvents[ i ] ); } }
void DeleteEventStream() { if ( g_Stream != NULL ) { FSEventStreamStop(g_Stream); FSEventStreamInvalidate(g_Stream); FSEventStreamRelease(g_Stream); g_Stream = NULL; } }
static PyObject* pyfsevents_unschedule(PyObject* self, PyObject* stream) { PyObject* value = PyDict_GetItem(streams, stream); PyDict_DelItem(streams, stream); FSEventStreamRef fsstream = PyCObject_AsVoidPtr(value); FSEventStreamStop(fsstream); FSEventStreamInvalidate(fsstream); FSEventStreamRelease(fsstream); Py_INCREF(Py_None); return Py_None; }
VError XMacFileSystemNotification::StopWatchingForChanges( VFileSystemNotifier::VChangeData *inChangeData, bool inIsLastOne) { // First, we need to find the folder's path so that we can locate our entry // in the watch list XMacChangeData *data = dynamic_cast<XMacChangeData*>( inChangeData); // We are watching this, so we need to stop that FSEventStreamStop( data->fStreamRef ); FSEventStreamInvalidate( data->fStreamRef ); return VE_OK; }
void fsevents_monitor::on_stop() { lock_guard<mutex> run_loop_lock(run_mutex); if (!run_loop) throw libfsw_exception(_("run loop is null")); FSW_ELOG(_("Stopping event stream...\n")); FSEventStreamStop(stream); stream = nullptr; FSW_ELOG(_("Stopping run loop...\n")); CFRunLoopStop(run_loop); run_loop = nullptr; }
void FDirectoryWatchRequestMac::Shutdown( void ) { if( bRunning ) { check(EventStream); FSEventStreamStop(EventStream); FSEventStreamUnscheduleFromRunLoop(EventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); FSEventStreamInvalidate(EventStream); FSEventStreamRelease(EventStream); bRunning = false; } }
static int handle_rm_repo (SeafWTMonitor *monitor, const char *repo_id, gpointer handle) { SeafWTMonitorPriv *priv = monitor->priv; FSEventStreamRef stream = (FSEventStreamRef)handle; FSEventStreamStop (stream); FSEventStreamInvalidate (stream); FSEventStreamRelease (stream); pthread_mutex_lock (&priv->hash_lock); g_hash_table_remove (priv->handle_hash, repo_id); g_hash_table_remove (priv->info_hash, (gpointer)(long)stream); pthread_mutex_unlock (&priv->hash_lock); return 0; }
int main(int argc, const char * argv[]) { int result = 0; FSEventStreamRef streamRef; Boolean startedOK; int flush_seconds = 3600; // When to force-flush any queued events if(argc < 2 || strcasecmp(argv[1], "--help") == 0) { fprintf(stderr, "usage: %s path ...\n", argv[0]); exit(1); } const char **paths = &argv[1]; streamRef = my_FSEventStreamCreate(paths, argc-1); FSEventStreamScheduleWithRunLoop(streamRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); startedOK = FSEventStreamStart(streamRef); if (!startedOK) { log_error("FSEventStreamStart(streamRef) failed"); goto out; } if (flush_seconds >= 0) { log_debug("CFAbsoluteTimeGetCurrent() => %.3f", CFAbsoluteTimeGetCurrent()); CFAllocatorRef allocator = kCFAllocatorDefault; CFAbsoluteTime fireDate = CFAbsoluteTimeGetCurrent() + /*settings->*/flush_seconds; CFTimeInterval interval = /*settings->*/flush_seconds; CFOptionFlags flags = 0; CFIndex order = 0; CFRunLoopTimerCallBack callback = (CFRunLoopTimerCallBack)timer_callback; CFRunLoopTimerContext context = { 0, streamRef, NULL, NULL, NULL }; CFRunLoopTimerRef timer = CFRunLoopTimerCreate(allocator, fireDate, interval, flags, order, callback, &context); CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); } // Run CFRunLoopRun(); // Stop / Invalidate / Release FSEventStreamStop(streamRef); out: FSEventStreamInvalidate(streamRef); FSEventStreamRelease(streamRef); return result; }
bool wxFsEventsFileSystemWatcher::RemoveAll() { // remove all watches created with Add() bool ret = wxKqueueFileSystemWatcher::RemoveAll(); FSEventStreamRefMap::iterator it = m_streams.begin(); while ( it != m_streams.end() ) { FSEventStreamStop(it->second); FSEventStreamInvalidate(it->second); FSEventStreamRelease(it->second); it++; ret |= true; } m_streams.clear(); return ret; }
fsevents_monitor::~fsevents_monitor() { if (stream) { FSW_ELOG(_("Stopping event stream...\n")); FSEventStreamStop(stream); FSW_ELOG(_("Invalidating event stream...\n")); FSEventStreamInvalidate(stream); FSW_ELOG(_("Releasing event stream...\n")); FSEventStreamRelease(stream); } stream = nullptr; }
void FSEventsEventPublisher::stop() { // Stop the stream. if (stream_ != nullptr) { FSEventStreamStop(stream_); stream_started_ = false; FSEventStreamUnscheduleFromRunLoop( stream_, run_loop_, kCFRunLoopDefaultMode); FSEventStreamInvalidate(stream_); FSEventStreamRelease(stream_); stream_ = nullptr; } // Stop the run loop. if (run_loop_ != nullptr) { CFRunLoopStop(run_loop_); } }
void start_watches() { CFStringRef watch_paths[100]; int path_count = 0; int i; for (i = 0; i < 100; i += 1) { if (NULL != FSEVENTS_GLOBAL(watches)[i].path) { watch_paths[i] = CFStringCreateWithCString(NULL, FSEVENTS_GLOBAL(watches)[i].path, kCFStringEncodingUTF8); path_count++; } } void *callback_info = NULL; // could put stream-specific data here. CFArrayRef watch_path_array = CFArrayCreate(NULL, (void *) watch_paths, path_count, NULL); CFAbsoluteTime latency = .75; /* Latency in seconds */ CFRunLoopRef run_loop = CFRunLoopGetMain(); FSEventStreamRef stream; /* Create the stream, passing in a callback */ stream = FSEventStreamCreate( NULL, (FSEventStreamCallback)&handle_events, callback_info, watch_path_array, kFSEventStreamEventIdSinceNow, latency, kFSEventStreamCreateFlagNone ); FSEventStreamScheduleWithRunLoop( stream, run_loop, kCFRunLoopDefaultMode ); FSEventStreamStart(stream); CFRunLoopRun(); FSEventStreamFlushSync(stream); FSEventStreamStop(stream); }
void FSEventsEventPublisher::stop() { // Stop the stream. WriteLock lock(mutex_); if (run_loop_ == nullptr) { // No need to stop if there is not run loop. return; } if (stream_ != nullptr) { FSEventStreamStop(stream_); stream_started_ = false; FSEventStreamUnscheduleFromRunLoop( stream_, run_loop_, kCFRunLoopDefaultMode); FSEventStreamInvalidate(stream_); FSEventStreamRelease(stream_); stream_ = nullptr; } // Stop the run loop. CFRunLoopStop(run_loop_); }
bool MacFileSystemChangeNotifier::internalRemoveNotification( const Torque::Path& dir ) { for( U32 i = 0, num = mEvents.size(); i < num; ++ i ) if( mEvents[ i ]->mDir == dir ) { #ifdef DEBUG_SPEW Platform::outputDebugString( "[MacFileSystemChangeNotifier] Removing change notification %i from '%s'", i + 1, dir.getFullPath().c_str() ); #endif FSEventStreamStop( mEvents[ i ]->mStream ); FSEventStreamInvalidate( mEvents[ i ]->mStream ); FSEventStreamRelease( mEvents[ i ]->mStream ); SAFE_DELETE( mEvents[ i ] ); mEvents.erase( i ); return true; } return false; }
FSEventsWatcher::~FSEventsWatcher() { FSEventStreamStop(stream_); FSEventStreamInvalidate(stream_); /* will remove from runloop */ FSEventStreamRelease(stream_); delete context_; }
FolderWatcherPrivate::~FolderWatcherPrivate() { FSEventStreamStop(_stream); FSEventStreamInvalidate(_stream); FSEventStreamRelease(_stream); }
static void *fsevents_thread(void *arg) { w_root_t *root = arg; FSEventStreamContext ctx; CFMutableArrayRef parray; CFStringRef cpath; FSEventStreamRef fs_stream = NULL; CFFileDescriptorContext fdctx; CFFileDescriptorRef fdref; struct fsevents_root_state *state = root->watch; double latency; w_set_thread_name("fsevents %.*s", root->root_path->len, root->root_path->buf); // Block until fsevents_root_start is waiting for our initialization pthread_mutex_lock(&state->fse_mtx); memset(&ctx, 0, sizeof(ctx)); ctx.info = root; memset(&fdctx, 0, sizeof(fdctx)); fdctx.info = root; fdref = CFFileDescriptorCreate(NULL, state->fse_pipe[0], true, fse_pipe_callback, &fdctx); CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); { CFRunLoopSourceRef fdsrc; fdsrc = CFFileDescriptorCreateRunLoopSource(NULL, fdref, 0); if (!fdsrc) { root->failure_reason = w_string_new( "CFFileDescriptorCreateRunLoopSource failed"); goto done; } CFRunLoopAddSource(CFRunLoopGetCurrent(), fdsrc, kCFRunLoopDefaultMode); CFRelease(fdsrc); } parray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (!parray) { root->failure_reason = w_string_new("CFArrayCreateMutable failed"); goto done; } cpath = CFStringCreateWithBytes(NULL, (const UInt8*)root->root_path->buf, root->root_path->len, kCFStringEncodingUTF8, false); if (!cpath) { root->failure_reason = w_string_new("CFStringCreateWithBytes failed"); goto done; } CFArrayAppendValue(parray, cpath); CFRelease(cpath); latency = cfg_get_double(root, "fsevents_latency", 0.01), w_log(W_LOG_DBG, "FSEventStreamCreate for path %.*s with latency %f seconds\n", root->root_path->len, root->root_path->buf, latency); fs_stream = FSEventStreamCreate(NULL, fse_callback, &ctx, parray, kFSEventStreamEventIdSinceNow, latency, kFSEventStreamCreateFlagNoDefer| kFSEventStreamCreateFlagWatchRoot| kFSEventStreamCreateFlagFileEvents); if (!fs_stream) { root->failure_reason = w_string_new("FSEventStreamCreate failed"); goto done; } FSEventStreamScheduleWithRunLoop(fs_stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); if (!FSEventStreamStart(fs_stream)) { root->failure_reason = w_string_make_printf( "FSEventStreamStart failed, look at your log file %s for " "lines mentioning FSEvents and see " "https://facebook.github.io/watchman/docs/troubleshooting.html#" "fsevents for more information\n", log_name); goto done; } // Signal to fsevents_root_start that we're done initializing pthread_cond_signal(&state->fse_cond); pthread_mutex_unlock(&state->fse_mtx); // Process the events stream until we get signalled to quit CFRunLoopRun(); // Since the goto's above hold fse_mtx, we should grab it here pthread_mutex_lock(&state->fse_mtx); done: if (fs_stream) { FSEventStreamStop(fs_stream); FSEventStreamInvalidate(fs_stream); FSEventStreamRelease(fs_stream); } if (fdref) { CFRelease(fdref); } // Signal to fsevents_root_start that we're done initializing in // the failure path. We'll also do this after we've completed // the run loop in the success path; it's a spurious wakeup but // harmless and saves us from adding and setting a control flag // in each of the failure `goto` statements. fsevents_root_dtor // will `pthread_join` us before `state` is freed. pthread_cond_signal(&state->fse_cond); pthread_mutex_unlock(&state->fse_mtx); w_log(W_LOG_DBG, "fse_thread done\n"); w_root_delref(root); return NULL; }
void WatcherData::perform(void* thread) { WatcherData* watcher = static_cast<WatcherData*>(thread); std::unique_lock<std::mutex> locker(watcher->mutex); if (watcher->flags & Stop) { if (watcher->fss) { FSEventStreamStop(watcher->fss); FSEventStreamInvalidate(watcher->fss); } CFRunLoopSourceInvalidate(watcher->source); CFRunLoopStop(watcher->loop); return; } else if (watcher->flags & Clear) { watcher->flags &= ~Clear; if (watcher->fss) { FSEventStreamStop(watcher->fss); FSEventStreamInvalidate(watcher->fss); watcher->fss = 0; } // We might have paths added since the clear operation was inititated if (watcher->paths.empty()) return; } // ### might make sense to have multiple streams instead of recreating one for each change // ### and then merge them if the stream count reaches a given treshold const int pathSize = watcher->paths.size(); FSEventStreamRef newfss = 0; if (pathSize) { StackBuffer<1024, CFStringRef> refs(pathSize); int i = 0; const Set<Path> copy = watcher->paths; for (const Path &path : copy) { refs[i++] = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, path.constData(), kCFStringEncodingUTF8, kCFAllocatorNull); } // don't need to hold the mutex beyond this point locker.unlock(); CFArrayRef list = CFArrayCreate(kCFAllocatorDefault, reinterpret_cast<const void**>(&refs[0]), pathSize, &kCFTypeArrayCallBacks); for (int j = 0; j < i; ++j) CFRelease(refs[j]); FSEventStreamContext ctx = { 0, watcher, 0, 0, 0 }; newfss = FSEventStreamCreate(kCFAllocatorDefault, notifyCallback, &ctx, list, watcher->since, .1, kFSEventStreamCreateFlagIgnoreSelf | kFSEventStreamCreateFlagFileEvents ); CFRelease(list); } if (!newfss) return; if (watcher->fss) { FSEventStreamStop(watcher->fss); FSEventStreamInvalidate(watcher->fss); } watcher->fss = newfss; FSEventStreamScheduleWithRunLoop(watcher->fss, watcher->loop, kCFRunLoopDefaultMode); FSEventStreamStart(watcher->fss); }
void WatcherThread::perform(void* thread) { WatcherThread* watcher = static_cast<WatcherThread*>(thread); MutexLocker locker(&watcher->mutex); if (watcher->flags & Stop) { if (watcher->fss) { FSEventStreamStop(watcher->fss); FSEventStreamInvalidate(watcher->fss); } CFRunLoopSourceInvalidate(watcher->source); CFRunLoopStop(watcher->loop); return; } else if (watcher->flags & Clear) { watcher->flags &= ~Clear; if (watcher->fss) { FSEventStreamStop(watcher->fss); FSEventStreamInvalidate(watcher->fss); watcher->fss = 0; } // We might have paths added since the clear operation was inititated if (watcher->paths.empty()) return; } // ### might make sense to have multiple streams instead of recreating one for each change // ### and then merge them if the stream count reaches a given treshold const int pathSize = watcher->paths.size(); FSEventStreamRef newfss = 0; if (pathSize) { CFStringRef refs[pathSize]; int i = 0; Set<Path>::const_iterator path = watcher->paths.begin(); const Set<Path>::const_iterator end = watcher->paths.end(); while (path != end) { // CFStringCreateWithCString copies the string data // ### use CFStringCreateWithCStringNoCopy instead? refs[i++] = CFStringCreateWithCString(kCFAllocatorDefault, path->nullTerminated(), kCFStringEncodingUTF8); ++path; } // don't need to hold the mutex beyond this point locker.unlock(); CFArrayRef list = CFArrayCreate(kCFAllocatorDefault, reinterpret_cast<const void**>(refs), pathSize, 0); FSEventStreamContext ctx = { 0, watcher, 0, 0, 0 }; newfss = FSEventStreamCreate(kCFAllocatorDefault, notifyCallback, &ctx, list, watcher->since, .5, kFSEventStreamCreateFlagWatchRoot | kFSEventStreamCreateFlagIgnoreSelf | kFSEventStreamCreateFlagFileEvents); } if (!newfss) return; if (watcher->fss) { FSEventStreamStop(watcher->fss); FSEventStreamInvalidate(watcher->fss); } watcher->fss = newfss; FSEventStreamScheduleWithRunLoop(watcher->fss, watcher->loop, kCFRunLoopDefaultMode); FSEventStreamStart(watcher->fss); }