Exemplo n.º 1
0
        private static void RunLoopThreadStart()
        {
            Debug.Assert(s_runLoop == IntPtr.Zero);

            s_runLoop = Interop.RunLoop.CFRunLoopGetCurrent();
            Interop.RunLoop.CFRunLoopAddSource(
                s_runLoop,
                s_runLoopSource.DangerousGetHandle(),
                Interop.RunLoop.kCFRunLoopDefaultMode.DangerousGetHandle());

            s_runLoopStartedEvent.Set();
            Interop.RunLoop.CFRunLoopRun();

            Interop.RunLoop.CFRunLoopRemoveSource(
                s_runLoop,
                s_runLoopSource.DangerousGetHandle(),
                Interop.RunLoop.kCFRunLoopDefaultMode.DangerousGetHandle());

            s_runLoop = IntPtr.Zero;

            s_runLoopSource.Dispose();
            s_runLoopSource = null;

            s_dynamicStoreRef.Dispose();
            s_dynamicStoreRef = null;

            s_runLoopEndedEvent.Set();
        }
        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.º 3
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.º 4
0
        private static unsafe void CreateAndStartRunLoop()
        {
            Debug.Assert(s_dynamicStoreRef == null);

            var storeContext = new Interop.SystemConfiguration.SCDynamicStoreContext();

            using (SafeCreateHandle storeName = Interop.CoreFoundation.CFStringCreateWithCString("NetworkAddressChange.OSX"))
            {
                s_dynamicStoreRef = Interop.SystemConfiguration.SCDynamicStoreCreate(
                    storeName.DangerousGetHandle(),
                    s_storeCallback,
                    &storeContext);
            }

            // Notification key string parts. We want to match notification keys
            // for any kind of IP address change, addition, or removal.
            using (SafeCreateHandle dynamicStoreDomainStateString = Interop.CoreFoundation.CFStringCreateWithCString("State:"))
                using (SafeCreateHandle compAnyRegexString = Interop.CoreFoundation.CFStringCreateWithCString("[^/]+"))
                    using (SafeCreateHandle entNetIpv4String = Interop.CoreFoundation.CFStringCreateWithCString("IPv4"))
                        using (SafeCreateHandle entNetIpv6String = Interop.CoreFoundation.CFStringCreateWithCString("IPv6"))
                        {
                            if (dynamicStoreDomainStateString.IsInvalid || compAnyRegexString.IsInvalid ||
                                entNetIpv4String.IsInvalid || entNetIpv6String.IsInvalid)
                            {
                                s_dynamicStoreRef.Dispose();
                                s_dynamicStoreRef = null;
                                throw new NetworkInformationException(SR.net_PInvokeError);
                            }

                            using (SafeCreateHandle ipv4Pattern = Interop.SystemConfiguration.SCDynamicStoreKeyCreateNetworkServiceEntity(
                                       dynamicStoreDomainStateString.DangerousGetHandle(),
                                       compAnyRegexString.DangerousGetHandle(),
                                       entNetIpv4String.DangerousGetHandle()))
                                using (SafeCreateHandle ipv6Pattern = Interop.SystemConfiguration.SCDynamicStoreKeyCreateNetworkServiceEntity(
                                           dynamicStoreDomainStateString.DangerousGetHandle(),
                                           compAnyRegexString.DangerousGetHandle(),
                                           entNetIpv6String.DangerousGetHandle()))
                                    using (SafeCreateHandle patterns = Interop.CoreFoundation.CFArrayCreate(
                                               new CFStringRef[2]
                                    {
                                        ipv4Pattern.DangerousGetHandle(),
                                        ipv6Pattern.DangerousGetHandle()
                                    }, (UIntPtr)2))
                                    {
                                        // Try to register our pattern strings with the dynamic store instance.
                                        if (patterns.IsInvalid || !Interop.SystemConfiguration.SCDynamicStoreSetNotificationKeys(
                                                s_dynamicStoreRef.DangerousGetHandle(),
                                                IntPtr.Zero,
                                                patterns.DangerousGetHandle()))
                                        {
                                            s_dynamicStoreRef.Dispose();
                                            s_dynamicStoreRef = null;
                                            throw new NetworkInformationException(SR.net_PInvokeError);
                                        }

                                        // Create a "RunLoopSource" that can be added to our listener thread's RunLoop.
                                        s_runLoopSource = Interop.SystemConfiguration.SCDynamicStoreCreateRunLoopSource(
                                            s_dynamicStoreRef.DangerousGetHandle(),
                                            IntPtr.Zero);
                                    }
                        }
            s_runLoopThread = new Thread(RunLoopThreadStart);
            s_runLoopThread.Start();
            s_runLoopStartedEvent.WaitOne(); // Wait for the new thread to finish initialization.
        }
            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())));
                    }
                }
            }
            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();
            }