Exemple #1
0
        private static unsafe void DoQueuedCompletionWork(
            ISwatcherConfig config, IWindowsFacade facade, SafeLocalMemHandle completionPortHandle,
            ISubject <SwatcherCreatedEventArgs> createdSubject, ISubject <SwatcherEventArgs> deletedSubject,
            ISubject <SwatcherEventArgs> changedSubject, ISubject <RenamedInfo> renamedSubject)
        {
            //this is a blocking call...
            var completionStatus = WaitForCompletionStatus(facade, completionPortHandle);

            if (completionStatus == null)
            {
                return;
            }

            var overlapped    = Overlapped.Unpack(completionStatus.Value.OverlappedPointer);
            var asyncResult   = (SwatcherAsyncResult)overlapped.AsyncResult;
            var currentOffset = 0;
            // ReSharper disable once TooWideLocalVariableScope
            var nextOffset = 0;

            try
            {
                do
                {
                    nextOffset = DeserializeMessage(
                        config, asyncResult, ref currentOffset, createdSubject,
                        deletedSubject, changedSubject, renamedSubject);
                } while (nextOffset != 0);
            }
            finally
            {
                //*always* free up the overlapped. otherwise, we will have a ~65kb memory leak after each callback.
                Overlapped.Free(completionStatus.Value.OverlappedPointer);
            }
        }
Exemple #2
0
        // ReSharper disable once SuggestVarOrType_Elsewhere
        private static unsafe void WatchFolderForChanges(
            object wrapper, ISwatcherConfig config,
            IWindowsFacade windowsFacade, SafeFileHandle directoryHandle)
        {
            var result = new SwatcherAsyncResult {
                Buffer = new byte[DefaultBufferSize]
            };
            var overlapped = new Overlapped {
                AsyncResult = result
            };

            //the first parameter is null because we're not using IO completion callbacks; they're too slow.
            //we're taking the byte array from our empty byte array and passing that as user data to the overlapped.
            var overlappedPointer = overlapped.UnsafePack(null, result.Buffer);

            var success = false;

            try
            {
                //now we wrap this section in a fixed block to pin it to the original address.
                //we cannot have it move because the OS will write information about the changes
                //into this byte array.
                fixed(byte *bufferPointer = result.Buffer)
                {
                    var bytesReturned = 0;
                    var bufferHandle  = new HandleRef(result, (IntPtr)bufferPointer);
                    var isRecursive   = Convert.ToInt32(config.IsRecursive);

                    //because we're using IO completion ports, we pass our overlapped pointer into this unmanaged
                    //call. when a change has been received, the OS will callback via GetQueuedCompletionStatus
                    //passing the overlapped pointer (which has our IAsyncResult/byte array) back to us.
                    success = windowsFacade.ReadDirectoryChangesW(
                        directoryHandle, bufferHandle, DefaultBufferSize, isRecursive,
                        (int)config.NotificationTypes, bytesReturned, overlappedPointer, SafeLocalMemHandle.Empty);

                    //in this usage of ReadDirectoryChangesW, we should *always* get 0 bytes returned.
                    if (bytesReturned != 0)
                    {
                        Debugger.Break();
                    }
                }
            }
            finally
            {
                //if success is false, our directory handle has likely become invalid. attempt to re-establish it.
                if (!success)
                {
                    Debugger.Break();
                    //before doing anything else, cleanup here to prevent memory leaks.
                    Overlapped.Free(overlappedPointer);
                }
            }
        }
Exemple #3
0
        internal Swatcher(ISwatcherConfig config, IWindowsFacade windowsFacade)
        {
            Config        = config;
            WindowsFacade = windowsFacade;

            var createdEventStream         = CreateCreatedEventStream();
            var finishedCreatedEventStream = CreateFinishedCreatedEventStream(createdEventStream);

            finishedCreatedEventStream
            .Delay(TimeSpan.FromSeconds(2.5))
            .Subscribe(x => CreatedEventsInProgress.Remove(x.FullPath));

            var createdEventWindows         = CreateCreatedEventWindowStream(createdEventStream);
            var finishedCreatedEventWindows = CreateFinishedCreatedEventWindows(finishedCreatedEventStream);

            var changedEventStream  = CreateChangedEventStream();
            var changedEventWindows = CreatedChangedEventWindows(changedEventStream);

            Renamed = CreatePublicRenamedStream(Config);
            Deleted = CreatePublicDeletedStream();
            Created = CreatePublicCreatedStream(finishedCreatedEventStream);
            Changed = CreatePublicChangedStream(changedEventStream,
                                                changedEventWindows, createdEventWindows, finishedCreatedEventWindows);

            ChangedEventPatternSource =
                Changed.Select(x => new EventPattern <SwatcherEventArgs>(this, x)).ToEventPattern();
            ChangedEventPatternSource.OnNext += OnItemChanged;

            DeletedEventPatternSource =
                Deleted.Select(x => new EventPattern <SwatcherEventArgs>(this, x)).ToEventPattern();
            DeletedEventPatternSource.OnNext += OnItemDeleted;

            CreatedEventPatternSource =
                Created.Select(x => new EventPattern <SwatcherCreatedEventArgs>(this, x)).ToEventPattern();
            CreatedEventPatternSource.OnNext += OnItemCreated;

            RenamedEventPatternSource =
                Renamed.Select(x => new EventPattern <SwatcherRenamedEventArgs>(this, x)).ToEventPattern();
            RenamedEventPatternSource.OnNext += OnItemRenamed;
        }
Exemple #4
0
        private static unsafe QueuedCompletionStatus?WaitForCompletionStatus(
            IWindowsFacade facade, SafeLocalMemHandle completionPortHandle)
        {
            uint bytesRead;
            uint completionKey;
            NativeOverlapped *overlappedPointer;

            //when change events have occurred, the OS will callback on this blocking method.
            //the key is that we provide the completion port handle, which has been bound to the
            //directory handle being watched (see InitializeCompletionPort() method). we get our change data
            //by passing a pointer by reference to our nativeoverlapped -> IAsyncResult -> buffer.
            var result = facade.GetQueuedCompletionStatus(
                completionPortHandle, out bytesRead, out completionKey,
                &overlappedPointer, InfiniteTimeout);

            //I don't think that this has ever returned false during testing.
            //if (!result)
            //    Debugger.Break();

            if (completionKey == StopIocpThreads)
            {
                Logger.Trace($"Stopping {Thread.CurrentThread.Name}");
                Thread.CurrentThread.Abort();
                return(null);
            }
            if (bytesRead == 0)
            {
                return(null);
            }

            return(new QueuedCompletionStatus()
            {
                BytesRead = bytesRead,
                CompletionKey = completionKey,
                OverlappedPointer = overlappedPointer
            });
        }