// Handle the next file in the enumeration. private void EnumerateNextFile(EnumerableWrapper wrapper) { LogicalThread enumerationThread; Action enumerateNextFile; string file; try { while (true) { // Advance enumeration until the // next file that matches the filter if (!wrapper.MoveNext()) return; if (m_fileProcessor.MatchesFilter(wrapper.Current)) break; Interlocked.Increment(ref m_fileProcessor.m_skippedFileCount); } // Prepare the callback to return execution to this thread enumerationThread = LogicalThread.CurrentThread; enumerateNextFile = () => EnumerateNextFile(wrapper); file = wrapper.Current; // Kick off the operation to process the current file, // but don't enumerate to the next file until processing // for the current file has begun m_fileProcessor.m_processingThread.Push(1, () => { // Check the state of cancellation for the // enumeration thread on the processing // thread as well to speed up cancellation if (wrapper.CancellationToken.IsCancelled) { enumerationThread.Push(DeactivateThread); return; } enumerationThread.Push(enumerateNextFile); m_fileProcessor.TouchLockAndProcess(file); }); } catch { // If an exception occurs, // dispose of the enumerable wrapper wrapper.Dispose(); throw; } finally { // If there are no more files to enumerate, // dispose of the wrapper and move to the next wrapper if (!wrapper.LastMove) { wrapper.Dispose(); EnumerateNextWrapper(); } } }
// Handle the next directory in the enumeration. private void EnumerateNextDirectory(EnumerableWrapper wrapper) { EnumerableWrapper fileWrapper; EnumerableWrapper directoryWrapper; string directory; try { // Advance directory enumeration if (!wrapper.MoveNext()) { // No more directories, so dispose // and then move to the next wrapper wrapper.Dispose(); EnumerateNextWrapper(); return; } // Initialize the fileWrapper // and directoryWrapper directory = wrapper.Current; fileWrapper = null; directoryWrapper = null; } catch { // If an error occurs, dispose of the // wrapper and then move to the next wrapper wrapper.Dispose(); EnumerateNextWrapper(); throw; } try { switch (m_fileProcessor.EnumerationStrategy) { // Sequential and ParallelWatchDirectories strategies // place subdirectories on the current thread case FileEnumerationStrategy.Sequential: case FileEnumerationStrategy.ParallelWatchDirectories: // Create the fileWrapper and directoryWrapper objects fileWrapper = new EnumerableWrapper(Directory.EnumerateFiles(directory), wrapper.CancellationToken); directoryWrapper = new EnumerableWrapper(Directory.EnumerateDirectories(directory), wrapper.CancellationToken); // Push the current directory wrapper onto the stack m_wrapperStack.Value.Push(() => EnumerateNextDirectory(wrapper)); // Push the subdirectory's file wrapper onto the stack m_wrapperStack.Value.Push(() => EnumerateNextFile(fileWrapper)); // Continue enumeration with the directory wrapper for the subdirectory LogicalThread.CurrentThread.Push(() => EnumerateNextDirectory(directoryWrapper)); break; // ParallelSubdirectories strategy spawns new threads for subdirectories case FileEnumerationStrategy.ParallelSubdirectories: // Create the fileWrapper and directoryWrapper objects fileWrapper = new EnumerableWrapper(Directory.EnumerateFiles(directory), wrapper.CancellationToken); directoryWrapper = new EnumerableWrapper(Directory.EnumerateDirectories(directory), wrapper.CancellationToken); // Create a new thread, push the file wrapper onto the new thread's // stack, then enumerate the directory wrapper on the new thread m_fileProcessor.m_threadScheduler.CreateThread().Push(() => { ActivateThread(); m_wrapperStack.Value.Push(() => EnumerateNextFile(fileWrapper)); EnumerateNextDirectory(directoryWrapper); }); // Continue enumeration on this thread with the current directory wrapper LogicalThread.CurrentThread.Push(() => EnumerateNextDirectory(wrapper)); break; // The only other file enumeration // strategy is no strategy at all default: // Clear out the stack and queue, // then dispose of the wrapper m_wrapperStack.Value.Clear(); m_directoryQueue.Value.Clear(); wrapper.Dispose(); DeactivateThread(); break; } } catch { // If an exception occurs, dispose of the file // wrapper and directory wrapper, then continue // enumeration with the current directory wrapper if ((object)fileWrapper != null) fileWrapper.Dispose(); if ((object)directoryWrapper != null) directoryWrapper.Dispose(); LogicalThread.CurrentThread.Push(() => EnumerateNextDirectory(wrapper)); throw; } }