Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2260)

Unified Diff: runtime/bin/file_patch.dart

Issue 98773002: Rewrite file-system-watcher to better handle the different system APIs. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Android impl and doc fix. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/bin/builtin_natives.cc ('k') | runtime/bin/file_system_watcher.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/file_patch.dart
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 9f1f6d06aa165d8289fc49861e936487021335ca..46a640dcdc8e8dbf29e066e405d4a0d5d24b6381 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -20,6 +20,7 @@ patch class _File {
/* patch */ static int _openStdio(int fd) native "File_OpenStdio";
}
+
patch class _RandomAccessFile {
/* patch */ static int _close(int id) native "File_Close";
/* patch */ static _readByte(int id) native "File_ReadByte";
@@ -37,52 +38,125 @@ patch class _RandomAccessFile {
/* patch */ static _flush(int id) native "File_Flush";
}
-patch class _FileSystemWatcher {
- /* patch */ factory _FileSystemWatcher(
- String path, int events, bool recursive)
- => new _FileSystemWatcherImpl(path, events, recursive);
- /* patch */ static bool get isSupported => _FileSystemWatcherImpl.isSupported;
+class _WatcherPath {
+ final int pathId;
+ final String path;
+ final int events;
+ int count = 0;
+ _WatcherPath(this.pathId, this.path, this.events);
}
-class _FileSystemWatcherImpl
- extends NativeFieldWrapperClass1
- implements _FileSystemWatcher {
+
+patch class _FileSystemWatcher {
+ static int _id;
+ static final Map<int, _FileSystemWatcherPath> _idMap = {};
+
final String _path;
final int _events;
final bool _recursive;
- StreamController _controller;
- StreamSubscription _subscription;
+ _WatcherPath _watcherPath;
+
+ StreamController _broadcastController;
+
+ /* patch */ static Stream<FileSystemEvent> watch(
+ String path, int events, bool recursive) {
+ if (Platform.isLinux) {
+ return new _InotifyFileSystemWatcher(path, events, recursive).stream;
+ }
+ if (Platform.isWindows) {
+ return new _Win32FileSystemWatcher(path, events, recursive).stream;
+ }
+ if (Platform.isMacOS) {
+ return new _FSEventStreamFileSystemWatcher(
+ path, events, recursive).stream;
+ }
+ throw new FileSystemException(
+ "File system watching is not supported on this platform");
+ }
- _FileSystemWatcherImpl(this._path, this._events, this._recursive) {
+ _FileSystemWatcher._(this._path, this._events, this._recursive) {
if (!isSupported) {
throw new FileSystemException(
- "File system watching is not supported on this system",
+ "File system watching is not supported on this platform",
_path);
}
- _controller = new StreamController.broadcast(onListen: _listen,
- onCancel: _cancel);
+ _broadcastController = new StreamController.broadcast(onListen: _listen,
+ onCancel: _cancel);
}
+ Stream get stream => _broadcastController.stream;
+
void _listen() {
- int socketId;
+ if (_id == null) {
+ try {
+ _id = _initWatcher();
+ _newWatcher();
+ } catch (e) {
+ _broadcastController.addError(new FileSystemException(
+ "Failed to initialize file system entity watcher"));
+ _broadcastController.close();
+ return;
+ }
+ }
+ var pathId;
try {
- socketId = _watchPath(_path, _events, identical(true, _recursive));
+ pathId = _watchPath(_id, _path, _events, _recursive);
} catch (e) {
- _controller.addError(new FileSystemException(
+ _broadcastController.addError(new FileSystemException(
"Failed to watch path", _path, e));
- _controller.close();
+ _broadcastController.close();
return;
}
+ if (!_idMap.containsKey(pathId)) {
+ _idMap[pathId] = new _WatcherPath(pathId, _path, _events);
+ }
+ _watcherPath = _idMap[pathId];
+ _watcherPath.count++;
+ _pathWatched().pipe(_broadcastController);
+ }
+
+ void _cancel() {
+ if (_watcherPath != null) {
+ assert(_watcherPath.count > 0);
+ _watcherPath.count--;
+ if (_watcherPath.count == 0) {
+ _pathWatchedEnd();
+ _unwatchPath(_id, _watcherPath.pathId);
+ _idMap.remove(_watcherPath.pathId);
+ }
+ _watcherPath = null;
+ }
+ if (_idMap.isEmpty && _id != null) {
+ _closeWatcher(_id);
+ _doneWatcher();
+ _id = null;
+ }
+ }
+
+ // Called when (and after) a new watcher instance is created and available.
+ void _newWatcher() {}
+ // Called when a watcher is no longer needed.
+ void _doneWatcher() {}
+ // Called when a new path is being watched.
+ Stream _pathWatched() {}
+ // Called when a path is no longer being watched.
+ void _donePathWatched() {}
+
+ static _WatcherPath _pathFromPathId(int pathId) {
+ return _idMap[pathId];
+ }
+
+ static Stream _listenOnSocket(int socketId, int id, int pathId) {
var socket = new _RawSocket(new _NativeSocket.watch(socketId));
- _subscription = socket.expand((event) {
- bool stop = false;
+ return socket.expand((event) {
+ var stops = [];
var events = [];
var pair = {};
if (event == RawSocketEvent.READ) {
String getPath(event) {
- var path = _path;
+ var path = _pathFromPathId(event[4]).path;
if (event[2] != null && event[2].isNotEmpty) {
path += Platform.pathSeparator;
path += event[2];
@@ -96,87 +170,190 @@ class _FileSystemWatcherImpl
}
return (event[0] & FileSystemEvent._IS_DIR) != 0;
}
- void add(event) {
- if ((event.type & _events) == 0) return;
- events.add(event);
+ void add(id, event) {
+ if ((event.type & _pathFromPathId(id).events) == 0) return;
+ events.add([id, event]);
}
void rewriteMove(event, isDir) {
if (event[3]) {
- add(new FileSystemCreateEvent._(getPath(event), isDir));
+ add(event[4], new FileSystemCreateEvent._(getPath(event), isDir));
} else {
- add(new FileSystemDeleteEvent._(getPath(event), isDir));
+ add(event[4], new FileSystemDeleteEvent._(getPath(event), isDir));
}
}
while (socket.available() > 0) {
- for (var event in _readEvents()) {
+ for (var event in _readEvents(id, pathId)) {
if (event == null) continue;
+ int pathId = event[4];
bool isDir = getIsDir(event);
var path = getPath(event);
if ((event[0] & FileSystemEvent.CREATE) != 0) {
- add(new FileSystemCreateEvent._(path, isDir));
+ add(event[4], new FileSystemCreateEvent._(path, isDir));
}
if ((event[0] & FileSystemEvent.MODIFY) != 0) {
- add(new FileSystemModifyEvent._(path, isDir, true));
+ add(event[4], new FileSystemModifyEvent._(path, isDir, true));
}
if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES) != 0) {
- add(new FileSystemModifyEvent._(path, isDir, false));
+ add(event[4], new FileSystemModifyEvent._(path, isDir, false));
}
if ((event[0] & FileSystemEvent.MOVE) != 0) {
int link = event[1];
if (link > 0) {
- if (pair.containsKey(link)) {
- events.add(new FileSystemMoveEvent._(
- getPath(pair[link]), isDir, path));
- pair.remove(link);
+ pair.putIfAbsent(pathId, () => {});
+ if (pair[pathId].containsKey(link)) {
+ add(event[4],
+ new FileSystemMoveEvent._(
+ getPath(pair[pathId][link]), isDir, path));
+ pair[pathId].remove(link);
} else {
- pair[link] = event;
+ pair[pathId][link] = event;
}
} else {
rewriteMove(event, isDir);
}
}
if ((event[0] & FileSystemEvent.DELETE) != 0) {
- add(new FileSystemDeleteEvent._(path, isDir));
+ add(event[4], new FileSystemDeleteEvent._(path, isDir));
}
if ((event[0] & FileSystemEvent._DELETE_SELF) != 0) {
- add(new FileSystemDeleteEvent._(path, isDir));
- stop = true;
+ add(event[4], new FileSystemDeleteEvent._(path, isDir));
+ // Signal done event.
+ stops.add([event[4], null]);
}
}
}
- for (var event in pair.values) {
- rewriteMove(event, getIsDir(event));
+ for (var map in pair.values) {
+ for (var event in map.values) {
+ rewriteMove(event, getIsDir(event));
+ }
}
} else if (event == RawSocketEvent.CLOSED) {
} else if (event == RawSocketEvent.READ_CLOSED) {
} else {
assert(false);
}
- if (stop) socket.close();
+ events.addAll(stops);
return events;
- })
- .listen(_controller.add, onDone: _cancel);
+ });
}
- void _cancel() {
- if (_subscription != null) {
- _unwatchPath();
- _subscription.cancel();
- _subscription = null;
+ /* patch */ static bool get isSupported
+ native "FileSystemWatcher_IsSupported";
+
+ static int _initWatcher() native "FileSystemWatcher_InitWatcher";
+ static void _closeWatcher(int id) native "FileSystemWatcher_CloseWatcher";
+
+ static int _watchPath(int id, String path, int events, bool recursive)
+ native "FileSystemWatcher_WatchPath";
+ static void _unwatchPath(int id, int path_id)
+ native "FileSystemWatcher_UnwatchPath";
+ static List _readEvents(int id, int path_id)
+ native "FileSystemWatcher_ReadEvents";
+ static int _getSocketId(int id, int path_id)
+ native "FileSystemWatcher_GetSocketId";
+}
+
+
+class _InotifyFileSystemWatcher extends _FileSystemWatcher {
+ static final Map<int, StreamController> _idMap = {};
+ static StreamSubscription _subscription;
+
+ _InotifyFileSystemWatcher(path, events, recursive)
+ : super._(path, events, recursive);
+
+ void _newWatcher() {
+ int id = _FileSystemWatcher._id;
+ _subscription = _FileSystemWatcher._listenOnSocket(id, id, 0)
+ .listen((event) {
+ if (_idMap.containsKey(event[0])) {
+ if (event[1] != null) {
+ _idMap[event[0]].add(event[1]);
+ } else {
+ _idMap[event[0]].close();
+ }
+ }
+ });
+ }
+
+ void _doneWatcher() {
+ _subscription.cancel();
+ }
+
+ Stream _pathWatched() {
+ var pathId = _watcherPath.pathId;
+ if (!_idMap.containsKey(pathId)) {
+ _idMap[pathId] = new StreamController.broadcast();
}
+ return _idMap[pathId].stream;
+ }
+
+ void _pathWatchedEnd() {
+ var pathId = _watcherPath.pathId;
+ if (!_idMap.containsKey(pathId)) return;
+ _idMap[pathId].close();
+ _idMap.remove(pathId);
+ }
+}
+
+
+class _Win32FileSystemWatcher extends _FileSystemWatcher {
+ StreamSubscription _subscription;
+ StreamController _controller;
+
+ _Win32FileSystemWatcher(path, events, recursive)
+ : super._(path, events, recursive);
+
+ Stream _pathWatched() {
+ var pathId = _watcherPath.pathId;
+ _controller = new StreamController();
+ _subscription = _FileSystemWatcher._listenOnSocket(pathId, 0, pathId)
+ .listen((event) {
+ assert(event[0] == pathId);
+ if (event[1] != null) {
+ _controller.add(event[1]);
+ } else {
+ _controller.close();
+ }
+ });
+ return _controller.stream;
+ }
+
+ void _pathWatchedEnd() {
+ _subscription.cancel();
_controller.close();
}
+}
- Stream<FileSystemEvent> get stream => _controller.stream;
- static bool get isSupported native "FileSystemWatcher_IsSupported";
+class _FSEventStreamFileSystemWatcher extends _FileSystemWatcher {
+ StreamSubscription _subscription;
+ StreamController _controller;
- int _watchPath(String path, int events, bool recursive)
- native "FileSystemWatcher_WatchPath";
- void _unwatchPath() native "FileSystemWatcher_UnwatchPath";
- List _readEvents() native "FileSystemWatcher_ReadEvents";
+ _FSEventStreamFileSystemWatcher(path, events, recursive)
+ : super._(path, events, recursive);
+
+ Stream _pathWatched() {
+ var pathId = _watcherPath.pathId;
+ var socketId = _FileSystemWatcher._getSocketId(0, pathId);
+ _controller = new StreamController();
+ _subscription = _FileSystemWatcher._listenOnSocket(socketId, 0, pathId)
+ .listen((event) {
+ if (event[1] != null) {
+ _controller.add(event[1]);
+ } else {
+ _controller.close();
+ }
+ });
+ return _controller.stream;
+ }
+
+ void _pathWatchedEnd() {
+ _subscription.cancel();
+ _controller.close();
+ }
}
+
Uint8List _makeUint8ListView(Uint8List source, int offsetInBytes, int length) {
return new Uint8List.view(source.buffer, offsetInBytes, length);
}
« no previous file with comments | « runtime/bin/builtin_natives.cc ('k') | runtime/bin/file_system_watcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698