Exemplo n.º 1
0
        private unsafe void SignalWorkerThreadsToStop()
        {
            Observable.Interval(TimeSpan.FromMilliseconds(25))
            .TakeWhile(_ => _runningThreads > 0)
            .Select(_ =>
            {
                var result = new SwatcherAsyncResult {
                    Buffer = new byte[0]
                };
                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);
                //when using IOCPs, we can send our own custom messages to the GetQueuedCompletionStatus
                //method by call PostQueuedCompletionStatus. In this case, we want to stop the threads that are
                //waiting on change events, so we will send a custom completion key "StopIocpThreads".
                WindowsFacade.PostQueuedCompletionStatus(CompletionPortHandle, 0, StopIocpThreads, overlappedPointer);
                return(Unit.Default);
            })
            .AsCompletion()
            .Where(_ => Config.LoggingEnabled)
            .Subscribe(_ =>
            {
                Disposables.Dispose();
                Logger.Info("Swatcher has stopped");
            });
        }
Exemplo n.º 2
0
        private static unsafe int DeserializeMessage(
            ISwatcherConfig config, SwatcherAsyncResult asyncResult, ref int currentOffset,
            ISubject <SwatcherCreatedEventArgs> createdSubject, ISubject <SwatcherEventArgs> deletedSubject,
            ISubject <SwatcherEventArgs> changedSubject, ISubject <RenamedInfo> renamedSubject)
        {
            int    nextOffset;
            string name;
            int    @event;

            fixed(byte *bufferPointer = asyncResult.Buffer)
            {
                //buffer pointer was the address where we started.
                //add current offset to get the address of our the next offset.
                //4 bytes in an integer ;-).
                nextOffset = *(int *)(bufferPointer + currentOffset);
                // the next integer contains the action.
                @event = *(int *)(bufferPointer + currentOffset + 4);
                //next int pointer has the address that contains the length of the name
                //of the item that was created,changed,renamed or deleted.
                var nameLength = *(int *)(bufferPointer + currentOffset + 8);

                //finally, retrieve the string via char* using the name length from above.
                //we divide the length by 2 because a char is 2 bytes.
                name = new string((char *)(bufferPointer + currentOffset + 12), 0, nameLength / 2);
            }

            switch ((FileSystemItemEvent)@event)
            {
            case FileSystemItemEvent.Created:
                OnItemCreatedInternal(config, createdSubject, name);
                break;

            case FileSystemItemEvent.Deleted:
                OnItemDeletedInternal(config, deletedSubject, name);
                break;

            case FileSystemItemEvent.Changed:
                OnItemChangedInternal(config, changedSubject, name);
                break;

            case FileSystemItemEvent.RenamedOldName:
                OnItemRenamedInternal(config, renamedSubject, name, FileSystemItemEvent.RenamedOldName);
                break;

            case FileSystemItemEvent.RenamedNewName:
                OnItemRenamedInternal(config, renamedSubject, name, FileSystemItemEvent.RenamedNewName);
                break;

            default:
                if (config.LoggingEnabled)
                {
                    Logger.Trace($"[Skipped] An event was skipped because it didn't map to a Swatcher FileSystemEvent. Value={@event}, Name={name ?? "null"}.");
                }
                break;
            }

            currentOffset += nextOffset;
            return(nextOffset);
        }
Exemplo n.º 3
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);
                }
            }
        }