private void CancellationCallback() { if (!_stopping && _eventStream != null) { _stopping = true; try { // When we get here, we've requested to stop so cleanup the EventStream and unschedule from the RunLoop Interop.EventStream.FSEventStreamStop(_eventStream); } finally { StaticWatcherRunLoopManager.UnscheduleFromRunLoop(_eventStream); } } }
internal unsafe void Start() { // Make sure _fullPath doesn't contain a link or alias // since the OS will give back the actual, non link'd or alias'd paths _fullDirectory = Interop.Sys.RealPath(_fullDirectory); if (_fullDirectory == null) { throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true); } Debug.Assert(string.IsNullOrEmpty(_fullDirectory) == false, "Watch directory is null or empty"); // Normalize the _fullDirectory path to have a trailing slash if (_fullDirectory[_fullDirectory.Length - 1] != '/') { _fullDirectory += "/"; } // Get the path to watch and verify we created the CFStringRef SafeCreateHandle path = Interop.CoreFoundation.CFStringCreateWithCString(_fullDirectory); if (path.IsInvalid) { throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true); } // Take the CFStringRef and put it into an array to pass to the EventStream SafeCreateHandle arrPaths = Interop.CoreFoundation.CFArrayCreate(new CFStringRef[1] { path.DangerousGetHandle() }, (UIntPtr)1); if (arrPaths.IsInvalid) { path.Dispose(); throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true); } // Create the callback for the EventStream if it wasn't previously created for this instance. if (_callback == null) { _callback = new Interop.EventStream.FSEventStreamCallback(FileSystemEventCallback); } _context = ExecutionContext.Capture(); // Make sure the OS file buffer(s) are fully flushed so we don't get events from cached I/O Interop.Sys.Sync(); // Create the event stream for the path and tell the stream to watch for file system events. _eventStream = Interop.EventStream.FSEventStreamCreate( _callback, arrPaths, Interop.EventStream.kFSEventStreamEventIdSinceNow, 0.0f, EventStreamFlags); if (_eventStream.IsInvalid) { arrPaths.Dispose(); path.Dispose(); throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true); } StaticWatcherRunLoopManager.ScheduleEventStream(_eventStream); bool started = Interop.EventStream.FSEventStreamStart(_eventStream); if (!started) { // Try to get the Watcher to raise the error event; if we can't do that, just silently exit since the watcher is gone anyway FileSystemWatcher watcher; if (_weakWatcher.TryGetTarget(out watcher)) { // An error occurred while trying to start the run loop so fail out watcher.OnError(new ErrorEventArgs(new IOException(SR.EventStream_FailedToStart, Marshal.GetLastWin32Error()))); } } }