Skip to content

Commit 4d0b898

Browse files
committed
Add locking around subdirectoryWatchers changes
github.com//pull/124716#discussion_r2838494096
1 parent 78b201d commit 4d0b898

1 file changed

Lines changed: 33 additions & 9 deletions

File tree

src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.SunOS.cs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,10 @@ private void CreateSubdirectoryWatchers(DirectorySnapshot snapshot)
390390
// Share parent's cancellation token so entire tree can be cancelled together
391391
var childWatcher = new RunningInstance(watcher, subdirPath, subdirRelativePath, true, _notifyFilters, _cancellationToken);
392392
childWatcher.Start();
393-
_subdirectoryWatchers.Add(childWatcher);
393+
lock (_subdirectoryWatchers)
394+
{
395+
_subdirectoryWatchers.Add(childWatcher);
396+
}
394397
subdirCount++;
395398
}
396399
}
@@ -756,10 +759,17 @@ private void ProcessDeletion(FileSystemWatcher watcher, string name, FileEntry o
756759
if (isDir && _includeSubdirectories)
757760
{
758761
string subdirPath = System.IO.Path.Combine(_directoryPath, name);
759-
var childToRemove = _subdirectoryWatchers.Find(c => c._directoryPath == subdirPath);
762+
RunningInstance? childToRemove;
763+
lock (_subdirectoryWatchers)
764+
{
765+
childToRemove = _subdirectoryWatchers.Find(c => c._directoryPath == subdirPath);
766+
if (childToRemove is not null)
767+
{
768+
_subdirectoryWatchers.Remove(childToRemove);
769+
}
770+
}
760771
if (childToRemove is not null)
761772
{
762-
_subdirectoryWatchers.Remove(childToRemove);
763773
childToRemove.Cancel();
764774
}
765775
}
@@ -787,10 +797,17 @@ private void ProcessRename(FileSystemWatcher watcher, string oldName, FileEntry
787797
if (isDir && _includeSubdirectories)
788798
{
789799
string oldSubdirPath = System.IO.Path.Combine(_directoryPath, oldName);
790-
var childToUpdate = _subdirectoryWatchers.Find(c => c._directoryPath == oldSubdirPath);
800+
RunningInstance? childToUpdate;
801+
lock (_subdirectoryWatchers)
802+
{
803+
childToUpdate = _subdirectoryWatchers.Find(c => c._directoryPath == oldSubdirPath);
804+
if (childToUpdate is not null)
805+
{
806+
_subdirectoryWatchers.Remove(childToUpdate);
807+
}
808+
}
791809
if (childToUpdate is not null)
792810
{
793-
_subdirectoryWatchers.Remove(childToUpdate);
794811
childToUpdate.Cancel();
795812
CreateSingleSubdirectoryWatcher(newName);
796813
}
@@ -833,7 +850,10 @@ private void CreateSingleSubdirectoryWatcher(string name)
833850
{
834851
var childWatcher = new RunningInstance(watcher, subdirPath, subdirRelativePath, true, _notifyFilters, _cancellationToken);
835852
childWatcher.Start();
836-
_subdirectoryWatchers.Add(childWatcher);
853+
lock (_subdirectoryWatchers)
854+
{
855+
_subdirectoryWatchers.Add(childWatcher);
856+
}
837857
}
838858
}
839859
catch (Exception ex)
@@ -980,9 +1000,13 @@ internal void Cancel()
9801000
_isCancelling = true;
9811001

9821002
// First, cancel all subdirectory watchers (depth-first)
983-
// ToArray() creates a snapshot to avoid race conditions with ProcessEvents thread
984-
// modifying the list during iteration
985-
foreach (var child in _subdirectoryWatchers.ToArray())
1003+
// Take a lock when creating the snapshot to avoid races with concurrent modifications
1004+
RunningInstance[] children;
1005+
lock (_subdirectoryWatchers)
1006+
{
1007+
children = _subdirectoryWatchers.ToArray();
1008+
}
1009+
foreach (RunningInstance child in children)
9861010
{
9871011
child.Cancel();
9881012
}

0 commit comments

Comments
 (0)