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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/builtin_natives.cc ('k') | runtime/bin/file_system_watcher.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 patch class _File { 5 patch class _File {
6 /* patch */ static _exists(String path) native "File_Exists"; 6 /* patch */ static _exists(String path) native "File_Exists";
7 /* patch */ static _create(String path) native "File_Create"; 7 /* patch */ static _create(String path) native "File_Create";
8 /* patch */ static _createLink(String path, String target) 8 /* patch */ static _createLink(String path, String target)
9 native "File_CreateLink"; 9 native "File_CreateLink";
10 /* patch */ static _linkTarget(String path) native "File_LinkTarget"; 10 /* patch */ static _linkTarget(String path) native "File_LinkTarget";
11 /* patch */ static _deleteNative(String path) native "File_Delete"; 11 /* patch */ static _deleteNative(String path) native "File_Delete";
12 /* patch */ static _deleteLinkNative(String path) native "File_DeleteLink"; 12 /* patch */ static _deleteLinkNative(String path) native "File_DeleteLink";
13 /* patch */ static _rename(String oldPath, String newPath) 13 /* patch */ static _rename(String oldPath, String newPath)
14 native "File_Rename"; 14 native "File_Rename";
15 /* patch */ static _renameLink(String oldPath, String newPath) 15 /* patch */ static _renameLink(String oldPath, String newPath)
16 native "File_RenameLink"; 16 native "File_RenameLink";
17 /* patch */ static _lengthFromPath(String path) native "File_LengthFromPath"; 17 /* patch */ static _lengthFromPath(String path) native "File_LengthFromPath";
18 /* patch */ static _lastModified(String path) native "File_LastModified"; 18 /* patch */ static _lastModified(String path) native "File_LastModified";
19 /* patch */ static _open(String path, int mode) native "File_Open"; 19 /* patch */ static _open(String path, int mode) native "File_Open";
20 /* patch */ static int _openStdio(int fd) native "File_OpenStdio"; 20 /* patch */ static int _openStdio(int fd) native "File_OpenStdio";
21 } 21 }
22 22
23
23 patch class _RandomAccessFile { 24 patch class _RandomAccessFile {
24 /* patch */ static int _close(int id) native "File_Close"; 25 /* patch */ static int _close(int id) native "File_Close";
25 /* patch */ static _readByte(int id) native "File_ReadByte"; 26 /* patch */ static _readByte(int id) native "File_ReadByte";
26 /* patch */ static _read(int id, int bytes) native "File_Read"; 27 /* patch */ static _read(int id, int bytes) native "File_Read";
27 /* patch */ static _readInto(int id, List<int> buffer, int start, int end) 28 /* patch */ static _readInto(int id, List<int> buffer, int start, int end)
28 native "File_ReadInto"; 29 native "File_ReadInto";
29 /* patch */ static _writeByte(int id, int value) native "File_WriteByte"; 30 /* patch */ static _writeByte(int id, int value) native "File_WriteByte";
30 /* patch */ static _writeFrom(int id, List<int> buffer, int start, int end) 31 /* patch */ static _writeFrom(int id, List<int> buffer, int start, int end)
31 native "File_WriteFrom"; 32 native "File_WriteFrom";
32 /* patch */ static _position(int id) native "File_Position"; 33 /* patch */ static _position(int id) native "File_Position";
33 /* patch */ static _setPosition(int id, int position) 34 /* patch */ static _setPosition(int id, int position)
34 native "File_SetPosition"; 35 native "File_SetPosition";
35 /* patch */ static _truncate(int id, int length) native "File_Truncate"; 36 /* patch */ static _truncate(int id, int length) native "File_Truncate";
36 /* patch */ static _length(int id) native "File_Length"; 37 /* patch */ static _length(int id) native "File_Length";
37 /* patch */ static _flush(int id) native "File_Flush"; 38 /* patch */ static _flush(int id) native "File_Flush";
38 } 39 }
39 40
40 patch class _FileSystemWatcher {
41 /* patch */ factory _FileSystemWatcher(
42 String path, int events, bool recursive)
43 => new _FileSystemWatcherImpl(path, events, recursive);
44 41
45 /* patch */ static bool get isSupported => _FileSystemWatcherImpl.isSupported; 42 class _WatcherPath {
43 final int pathId;
44 final String path;
45 final int events;
46 int count = 0;
47 _WatcherPath(this.pathId, this.path, this.events);
46 } 48 }
47 49
48 class _FileSystemWatcherImpl 50
49 extends NativeFieldWrapperClass1 51 patch class _FileSystemWatcher {
50 implements _FileSystemWatcher { 52 static int _id;
53 static final Map<int, _FileSystemWatcherPath> _idMap = {};
54
51 final String _path; 55 final String _path;
52 final int _events; 56 final int _events;
53 final bool _recursive; 57 final bool _recursive;
54 58
55 StreamController _controller; 59 _WatcherPath _watcherPath;
56 StreamSubscription _subscription;
57 60
58 _FileSystemWatcherImpl(this._path, this._events, this._recursive) { 61 StreamController _broadcastController;
62
63 /* patch */ static Stream<FileSystemEvent> watch(
64 String path, int events, bool recursive) {
65 if (Platform.isLinux) {
66 return new _InotifyFileSystemWatcher(path, events, recursive).stream;
67 }
68 if (Platform.isWindows) {
69 return new _Win32FileSystemWatcher(path, events, recursive).stream;
70 }
71 if (Platform.isMacOS) {
72 return new _FSEventStreamFileSystemWatcher(
73 path, events, recursive).stream;
74 }
75 throw new FileSystemException(
76 "File system watching is not supported on this platform");
77 }
78
79 _FileSystemWatcher._(this._path, this._events, this._recursive) {
59 if (!isSupported) { 80 if (!isSupported) {
60 throw new FileSystemException( 81 throw new FileSystemException(
61 "File system watching is not supported on this system", 82 "File system watching is not supported on this platform",
62 _path); 83 _path);
63 } 84 }
64 _controller = new StreamController.broadcast(onListen: _listen, 85 _broadcastController = new StreamController.broadcast(onListen: _listen,
65 onCancel: _cancel); 86 onCancel: _cancel);
66 } 87 }
67 88
89 Stream get stream => _broadcastController.stream;
90
68 void _listen() { 91 void _listen() {
69 int socketId; 92 if (_id == null) {
93 try {
94 _id = _initWatcher();
95 _newWatcher();
96 } catch (e) {
97 _broadcastController.addError(new FileSystemException(
98 "Failed to initialize file system entity watcher"));
99 _broadcastController.close();
100 return;
101 }
102 }
103 var pathId;
70 try { 104 try {
71 socketId = _watchPath(_path, _events, identical(true, _recursive)); 105 pathId = _watchPath(_id, _path, _events, _recursive);
72 } catch (e) { 106 } catch (e) {
73 _controller.addError(new FileSystemException( 107 _broadcastController.addError(new FileSystemException(
74 "Failed to watch path", _path, e)); 108 "Failed to watch path", _path, e));
75 _controller.close(); 109 _broadcastController.close();
76 return; 110 return;
77 } 111 }
112 if (!_idMap.containsKey(pathId)) {
113 _idMap[pathId] = new _WatcherPath(pathId, _path, _events);
114 }
115 _watcherPath = _idMap[pathId];
116 _watcherPath.count++;
117 _pathWatched().pipe(_broadcastController);
118 }
119
120 void _cancel() {
121 if (_watcherPath != null) {
122 assert(_watcherPath.count > 0);
123 _watcherPath.count--;
124 if (_watcherPath.count == 0) {
125 _pathWatchedEnd();
126 _unwatchPath(_id, _watcherPath.pathId);
127 _idMap.remove(_watcherPath.pathId);
128 }
129 _watcherPath = null;
130 }
131 if (_idMap.isEmpty && _id != null) {
132 _closeWatcher(_id);
133 _doneWatcher();
134 _id = null;
135 }
136 }
137
138 // Called when (and after) a new watcher instance is created and available.
139 void _newWatcher() {}
140 // Called when a watcher is no longer needed.
141 void _doneWatcher() {}
142 // Called when a new path is being watched.
143 Stream _pathWatched() {}
144 // Called when a path is no longer being watched.
145 void _donePathWatched() {}
146
147 static _WatcherPath _pathFromPathId(int pathId) {
148 return _idMap[pathId];
149 }
150
151 static Stream _listenOnSocket(int socketId, int id, int pathId) {
78 var socket = new _RawSocket(new _NativeSocket.watch(socketId)); 152 var socket = new _RawSocket(new _NativeSocket.watch(socketId));
79 _subscription = socket.expand((event) { 153 return socket.expand((event) {
80 bool stop = false; 154 var stops = [];
81 var events = []; 155 var events = [];
82 var pair = {}; 156 var pair = {};
83 if (event == RawSocketEvent.READ) { 157 if (event == RawSocketEvent.READ) {
84 String getPath(event) { 158 String getPath(event) {
85 var path = _path; 159 var path = _pathFromPathId(event[4]).path;
86 if (event[2] != null && event[2].isNotEmpty) { 160 if (event[2] != null && event[2].isNotEmpty) {
87 path += Platform.pathSeparator; 161 path += Platform.pathSeparator;
88 path += event[2]; 162 path += event[2];
89 } 163 }
90 return path; 164 return path;
91 } 165 }
92 bool getIsDir(event) { 166 bool getIsDir(event) {
93 if (Platform.isWindows) { 167 if (Platform.isWindows) {
94 // Windows does not get 'isDir' as part of the event. 168 // Windows does not get 'isDir' as part of the event.
95 return FileSystemEntity.isDirectorySync(getPath(event)); 169 return FileSystemEntity.isDirectorySync(getPath(event));
96 } 170 }
97 return (event[0] & FileSystemEvent._IS_DIR) != 0; 171 return (event[0] & FileSystemEvent._IS_DIR) != 0;
98 } 172 }
99 void add(event) { 173 void add(id, event) {
100 if ((event.type & _events) == 0) return; 174 if ((event.type & _pathFromPathId(id).events) == 0) return;
101 events.add(event); 175 events.add([id, event]);
102 } 176 }
103 void rewriteMove(event, isDir) { 177 void rewriteMove(event, isDir) {
104 if (event[3]) { 178 if (event[3]) {
105 add(new FileSystemCreateEvent._(getPath(event), isDir)); 179 add(event[4], new FileSystemCreateEvent._(getPath(event), isDir));
106 } else { 180 } else {
107 add(new FileSystemDeleteEvent._(getPath(event), isDir)); 181 add(event[4], new FileSystemDeleteEvent._(getPath(event), isDir));
108 } 182 }
109 } 183 }
110 while (socket.available() > 0) { 184 while (socket.available() > 0) {
111 for (var event in _readEvents()) { 185 for (var event in _readEvents(id, pathId)) {
112 if (event == null) continue; 186 if (event == null) continue;
187 int pathId = event[4];
113 bool isDir = getIsDir(event); 188 bool isDir = getIsDir(event);
114 var path = getPath(event); 189 var path = getPath(event);
115 if ((event[0] & FileSystemEvent.CREATE) != 0) { 190 if ((event[0] & FileSystemEvent.CREATE) != 0) {
116 add(new FileSystemCreateEvent._(path, isDir)); 191 add(event[4], new FileSystemCreateEvent._(path, isDir));
117 } 192 }
118 if ((event[0] & FileSystemEvent.MODIFY) != 0) { 193 if ((event[0] & FileSystemEvent.MODIFY) != 0) {
119 add(new FileSystemModifyEvent._(path, isDir, true)); 194 add(event[4], new FileSystemModifyEvent._(path, isDir, true));
120 } 195 }
121 if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES) != 0) { 196 if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES) != 0) {
122 add(new FileSystemModifyEvent._(path, isDir, false)); 197 add(event[4], new FileSystemModifyEvent._(path, isDir, false));
123 } 198 }
124 if ((event[0] & FileSystemEvent.MOVE) != 0) { 199 if ((event[0] & FileSystemEvent.MOVE) != 0) {
125 int link = event[1]; 200 int link = event[1];
126 if (link > 0) { 201 if (link > 0) {
127 if (pair.containsKey(link)) { 202 pair.putIfAbsent(pathId, () => {});
128 events.add(new FileSystemMoveEvent._( 203 if (pair[pathId].containsKey(link)) {
129 getPath(pair[link]), isDir, path)); 204 add(event[4],
130 pair.remove(link); 205 new FileSystemMoveEvent._(
206 getPath(pair[pathId][link]), isDir, path));
207 pair[pathId].remove(link);
131 } else { 208 } else {
132 pair[link] = event; 209 pair[pathId][link] = event;
133 } 210 }
134 } else { 211 } else {
135 rewriteMove(event, isDir); 212 rewriteMove(event, isDir);
136 } 213 }
137 } 214 }
138 if ((event[0] & FileSystemEvent.DELETE) != 0) { 215 if ((event[0] & FileSystemEvent.DELETE) != 0) {
139 add(new FileSystemDeleteEvent._(path, isDir)); 216 add(event[4], new FileSystemDeleteEvent._(path, isDir));
140 } 217 }
141 if ((event[0] & FileSystemEvent._DELETE_SELF) != 0) { 218 if ((event[0] & FileSystemEvent._DELETE_SELF) != 0) {
142 add(new FileSystemDeleteEvent._(path, isDir)); 219 add(event[4], new FileSystemDeleteEvent._(path, isDir));
143 stop = true; 220 // Signal done event.
221 stops.add([event[4], null]);
144 } 222 }
145 } 223 }
146 } 224 }
147 for (var event in pair.values) { 225 for (var map in pair.values) {
148 rewriteMove(event, getIsDir(event)); 226 for (var event in map.values) {
227 rewriteMove(event, getIsDir(event));
228 }
149 } 229 }
150 } else if (event == RawSocketEvent.CLOSED) { 230 } else if (event == RawSocketEvent.CLOSED) {
151 } else if (event == RawSocketEvent.READ_CLOSED) { 231 } else if (event == RawSocketEvent.READ_CLOSED) {
152 } else { 232 } else {
153 assert(false); 233 assert(false);
154 } 234 }
155 if (stop) socket.close(); 235 events.addAll(stops);
156 return events; 236 return events;
157 }) 237 });
158 .listen(_controller.add, onDone: _cancel);
159 } 238 }
160 239
161 void _cancel() { 240 /* patch */ static bool get isSupported
162 if (_subscription != null) { 241 native "FileSystemWatcher_IsSupported";
163 _unwatchPath(); 242
164 _subscription.cancel(); 243 static int _initWatcher() native "FileSystemWatcher_InitWatcher";
165 _subscription = null; 244 static void _closeWatcher(int id) native "FileSystemWatcher_CloseWatcher";
245
246 static int _watchPath(int id, String path, int events, bool recursive)
247 native "FileSystemWatcher_WatchPath";
248 static void _unwatchPath(int id, int path_id)
249 native "FileSystemWatcher_UnwatchPath";
250 static List _readEvents(int id, int path_id)
251 native "FileSystemWatcher_ReadEvents";
252 static int _getSocketId(int id, int path_id)
253 native "FileSystemWatcher_GetSocketId";
254 }
255
256
257 class _InotifyFileSystemWatcher extends _FileSystemWatcher {
258 static final Map<int, StreamController> _idMap = {};
259 static StreamSubscription _subscription;
260
261 _InotifyFileSystemWatcher(path, events, recursive)
262 : super._(path, events, recursive);
263
264 void _newWatcher() {
265 int id = _FileSystemWatcher._id;
266 _subscription = _FileSystemWatcher._listenOnSocket(id, id, 0)
267 .listen((event) {
268 if (_idMap.containsKey(event[0])) {
269 if (event[1] != null) {
270 _idMap[event[0]].add(event[1]);
271 } else {
272 _idMap[event[0]].close();
273 }
274 }
275 });
276 }
277
278 void _doneWatcher() {
279 _subscription.cancel();
280 }
281
282 Stream _pathWatched() {
283 var pathId = _watcherPath.pathId;
284 if (!_idMap.containsKey(pathId)) {
285 _idMap[pathId] = new StreamController.broadcast();
166 } 286 }
287 return _idMap[pathId].stream;
288 }
289
290 void _pathWatchedEnd() {
291 var pathId = _watcherPath.pathId;
292 if (!_idMap.containsKey(pathId)) return;
293 _idMap[pathId].close();
294 _idMap.remove(pathId);
295 }
296 }
297
298
299 class _Win32FileSystemWatcher extends _FileSystemWatcher {
300 StreamSubscription _subscription;
301 StreamController _controller;
302
303 _Win32FileSystemWatcher(path, events, recursive)
304 : super._(path, events, recursive);
305
306 Stream _pathWatched() {
307 var pathId = _watcherPath.pathId;
308 _controller = new StreamController();
309 _subscription = _FileSystemWatcher._listenOnSocket(pathId, 0, pathId)
310 .listen((event) {
311 assert(event[0] == pathId);
312 if (event[1] != null) {
313 _controller.add(event[1]);
314 } else {
315 _controller.close();
316 }
317 });
318 return _controller.stream;
319 }
320
321 void _pathWatchedEnd() {
322 _subscription.cancel();
167 _controller.close(); 323 _controller.close();
168 } 324 }
325 }
169 326
170 Stream<FileSystemEvent> get stream => _controller.stream;
171 327
172 static bool get isSupported native "FileSystemWatcher_IsSupported"; 328 class _FSEventStreamFileSystemWatcher extends _FileSystemWatcher {
329 StreamSubscription _subscription;
330 StreamController _controller;
173 331
174 int _watchPath(String path, int events, bool recursive) 332 _FSEventStreamFileSystemWatcher(path, events, recursive)
175 native "FileSystemWatcher_WatchPath"; 333 : super._(path, events, recursive);
176 void _unwatchPath() native "FileSystemWatcher_UnwatchPath"; 334
177 List _readEvents() native "FileSystemWatcher_ReadEvents"; 335 Stream _pathWatched() {
336 var pathId = _watcherPath.pathId;
337 var socketId = _FileSystemWatcher._getSocketId(0, pathId);
338 _controller = new StreamController();
339 _subscription = _FileSystemWatcher._listenOnSocket(socketId, 0, pathId)
340 .listen((event) {
341 if (event[1] != null) {
342 _controller.add(event[1]);
343 } else {
344 _controller.close();
345 }
346 });
347 return _controller.stream;
348 }
349
350 void _pathWatchedEnd() {
351 _subscription.cancel();
352 _controller.close();
353 }
178 } 354 }
179 355
356
180 Uint8List _makeUint8ListView(Uint8List source, int offsetInBytes, int length) { 357 Uint8List _makeUint8ListView(Uint8List source, int offsetInBytes, int length) {
181 return new Uint8List.view(source.buffer, offsetInBytes, length); 358 return new Uint8List.view(source.buffer, offsetInBytes, length);
182 } 359 }
OLDNEW
« 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