Exemplo n.º 1
0
        private void CleanupStreamAndWatcher()
        {
            // If we're currently streaming, stop
            StopStream();

            // Clean up the EventStream, if it exists
            if (!_eventStream.IsInvalid)
            {
                _eventStream = new SafeEventStreamHandle(IntPtr.Zero);
            }

            // Make sure there's a loop to clear
            if (_watcherRunLoop != IntPtr.Zero)
            {
                // Stop the RunLoop and wait for the thread to exit gracefully
                Interop.RunLoop.CFRunLoopStop(_watcherRunLoop);
                _watcherThread.Join();
                _watcherRunLoop = IntPtr.Zero;
            }

            // Cleanup the callback
            if (_callback != null)
            {
                _callback = null;
            }
        }
        private void StopRaisingEvents()
        {
            // Make sure the Start and Stop can be called from different threads and don't
            // stomp on the other's operation. We use the _syncLock instead of the
            // RunLoop or StreamRef because IntPtrs are value types and can't be locked
            lock (_syncLock)
            {
                // Make sure there's a loop to clear
                if (_watcherRunLoop != IntPtr.Zero)
                {
                    // Stop the RunLoop and wait for the thread to exit gracefully
                    Interop.RunLoop.CFRunLoopStop(_watcherRunLoop);
                    _watcherThread.Join();
                    _watcherRunLoop = IntPtr.Zero;
                }

                // Clean up the EventStream, if it exists
                if (!_eventStream.IsInvalid)
                {
                    _eventStream = new SafeEventStreamHandle(IntPtr.Zero);
                }

                // Cleanup the callback
                if (_callback != null)
                {
                    _callback = null;
                }
            }
        }
        private void CreateStreamAndStartWatcher()
        {
            Debug.Assert(_eventStream.IsInvalid);
            Debug.Assert(_watcherRunLoop == IntPtr.Zero);
            Debug.Assert(_callback == null);

            // Make sure we only do this if there is a valid directory
            if (String.IsNullOrEmpty(_directory) == false)
            {
                _fullDirectory = System.IO.Path.GetFullPath(_directory);

                // 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()
                }, 1);
                if (arrPaths.IsInvalid)
                {
                    path.Dispose();
                    throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true);
                }

                // Create the callback for the EventStream
                _callback = new Interop.EventStream.FSEventStreamCallback(FileSystemEventCallback);

                // Make sure the OS file buffer(s) are fully flushed so we don't get events from cached I/O
                Interop.libc.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);
                }

                // Create and start our watcher thread then wait for the thread to initialize and start
                // the RunLoop. We wait for that to prevent this function from returning before the RunLoop
                // has a chance to start so that any callers won't race with the background thread's initialization
                // and calling Stop, which would attempt to stop a RunLoop that hasn't started yet.
                _watcherThread = new Thread(new ThreadStart(WatchForFileSystemEventsThreadStart));
                _watcherThread.Start();
                _runLoopStartedEvent.WaitOne();
            }
        }
Exemplo n.º 4
0
            internal void Start()
            {
                // 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()
                }, 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);
                }

                // 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);
                }

                // Create and start our watcher thread then wait for the thread to initialize and start
                // the RunLoop. We wait for that to prevent this function from returning before the RunLoop
                // has a chance to start so that any callers won't race with the background thread's initialization
                // and calling Stop, which would attempt to stop a RunLoop that hasn't started yet.
                var runLoopStarted = new ManualResetEventSlim();

                new Thread(WatchForFileSystemEventsThreadStart)
                {
                    IsBackground = true
                }.Start(runLoopStarted);
                runLoopStarted.Wait();
            }
Exemplo n.º 5
0
                public static void ScheduleEventStream(SafeEventStreamHandle eventStream)
                {
                    lock (s_lockObject)
                    {
                        if (s_watcherRunLoop != IntPtr.Zero)
                        {
                            // Schedule the EventStream to run on the thread's RunLoop
                            s_scheduledStreamsCount++;
                            Interop.EventStream.FSEventStreamScheduleWithRunLoop(eventStream, s_watcherRunLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
                            return;
                        }

                        Debug.Assert(s_scheduledStreamsCount == 0);
                        s_scheduledStreamsCount = 1;
                        var runLoopStarted = new ManualResetEventSlim();
                        new Thread(static args =>
Exemplo n.º 6
0
            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);
                        _eventStream.Close();
                        _eventStream = null;
                    }
                }
            }
                public static void UnscheduleFromRunLoop(SafeEventStreamHandle eventStream)
                {
                    Debug.Assert(s_watcherRunLoop != IntPtr.Zero);
                    lock (s_lockObject)
                    {
                        if (s_watcherRunLoop != IntPtr.Zero)
                        {
                            // Always unschedule the RunLoop before cleaning up
                            Interop.EventStream.FSEventStreamUnscheduleFromRunLoop(eventStream, s_watcherRunLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
                            s_scheduledStreamsCount--;

                            if (s_scheduledStreamsCount == 0)
                            {
                                // Stop the FS event message pump
                                Interop.RunLoop.CFRunLoopStop(s_watcherRunLoop);
                                s_watcherRunLoop = IntPtr.Zero;
                            }
                        }
                    }
                }
                public static void ScheduleEventStream(SafeEventStreamHandle eventStream)
                {
                    lock (s_lockObject)
                    {
                        if (s_watcherRunLoop != IntPtr.Zero)
                        {
                            // Schedule the EventStream to run on the thread's RunLoop
                            s_scheduledStreamsCount++;
                            Interop.EventStream.FSEventStreamScheduleWithRunLoop(eventStream, s_watcherRunLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
                            return;
                        }

                        Debug.Assert(s_scheduledStreamsCount == 0);
                        s_scheduledStreamsCount = 1;
                        var runLoopStarted = new ManualResetEventSlim();
                        new Thread(WatchForFileSystemEventsThreadStart)
                        {
                            IsBackground = true
                        }.Start(new object[] { runLoopStarted, eventStream });
                        runLoopStarted.Wait();
                    }
                }
Exemplo n.º 9
0
 internal static extern void FSEventStreamUnscheduleFromRunLoop(
     SafeEventStreamHandle streamRef,
     CFRunLoopRef runLoop,
     SafeCreateHandle runLoopMode);
Exemplo n.º 10
0
 internal static extern void FSEventStreamStop(SafeEventStreamHandle streamRef);
Exemplo n.º 11
0
 internal static extern bool FSEventStreamStart(SafeEventStreamHandle streamRef);
Exemplo n.º 12
0
 internal static partial void FSEventStreamStop(SafeEventStreamHandle streamRef);
Exemplo n.º 13
0
 internal static partial bool FSEventStreamStart(SafeEventStreamHandle streamRef);
Exemplo n.º 14
0
 internal static partial void FSEventStreamScheduleWithRunLoop(
     SafeEventStreamHandle streamRef,
     CFRunLoopRef runLoop,
     SafeCreateHandle runLoopMode);
            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())));
                    }
                }
            }
Exemplo n.º 16
0
            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);
                }

                // 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);
                }

                // Create and start our watcher thread then wait for the thread to initialize and start
                // the RunLoop. We wait for that to prevent this function from returning before the RunLoop
                // has a chance to start so that any callers won't race with the background thread's initialization
                // and calling Stop, which would attempt to stop a RunLoop that hasn't started yet.
                var runLoopStarted = new ManualResetEventSlim();

                new Thread(WatchForFileSystemEventsThreadStart)
                {
                    IsBackground = true
                }.Start(runLoopStarted);
                runLoopStarted.Wait();
            }