[io/file_watch] Don't attempt to close already closed DirectoryWatchHandle.

Fixes https://github.com/dart-lang/sdk/issues/43941

TEST=Running four dart scripts in parallel that delete/watch thousands of file reproduces the failure after several minutes. After the fix it no longer reproduces.

Change-Id: I6a0a928838c676f44e747a822611b56f0ffc4841
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169601
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
diff --git a/sdk/lib/_internal/vm/bin/file_patch.dart b/sdk/lib/_internal/vm/bin/file_patch.dart
index b243920..43fb061 100644
--- a/sdk/lib/_internal/vm/bin/file_patch.dart
+++ b/sdk/lib/_internal/vm/bin/file_patch.dart
@@ -174,9 +174,17 @@
       assert(watcherPath.count > 0);
       watcherPath.count--;
       if (watcherPath.count == 0) {
-        _unwatchPath(_id!, watcherPath.pathId);
-        _pathWatchedEnd();
-        _idMap.remove(watcherPath.pathId);
+        var pathId = watcherPath.pathId;
+        // DirectoryWatchHandle(aka pathId) might be closed already initiated
+        // by issueReadEvent for example. When that happens, appropriate closeEvent
+        // will arrive to us and we will remove this pathId from _idMap. If that
+        // happens we should not try to close it again as pathId is no
+        // longer usable(the memory it points to might be released)
+        if (_idMap.containsKey(pathId)) {
+          _unwatchPath(_id!, pathId);
+          _pathWatchedEnd();
+          _idMap.remove(pathId);
+        }
       }
       _watcherPath = null;
     }