private async Task SetDirectoryHandle() { await Task.Run(() => { var directoryHandle = WindowsFacade.CreateFile( Config.PathToWatch, FileSystemConstants.FileListDirectory, // access (read-write) mode FileSystemConstants.FileShareRead | FileSystemConstants.FileShareDelete | FileSystemConstants.FileShareWrite, // share mode null, // security descriptor FileSystemConstants.OpenExisting, // how to create FileSystemConstants.FileFlagBackupSemantics | FileSystemConstants.FileFlagOverlapped, // file attributes new SafeFileHandle(IntPtr.Zero, false) // file with attributes to copy ); if (!directoryHandle.IsHandleValid()) { throw new ApplicationException( $"Swatcher failed to start because it couldn't access the folder path provided in configuration."); } DirectoryHandle = directoryHandle; }) .ConfigureAwait(false); }
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"); }); }
private async Task SetCompletionPortHandle(int completionKey) { await Task.Run(() => { //if the completion port doesn't exist yet, this call will create it. //if it already exists, this call will bind the directory handle to the completion port, //whilst retaining any other directory handles that were previously bound. //passing 0 to the last parameter uses the default number of concurrent threads, which //is the number of CPUs on the machine. var pointer = WindowsFacade.CreateIoCompletionPort( DirectoryHandle, SafeLocalMemHandle.Empty, (uint)completionKey, (uint)Environment.ProcessorCount); CompletionPortHandle = new SafeLocalMemHandle(pointer); }) .ConfigureAwait(false); }