Close file watcher when target is deleted.

BUG=http://code.google.com/p/dart/issues/detail?id=14374
R=sgjesse@google.com

Review URL: https://codereview.chromium.org//39613002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@29159 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
ajohnsen@google.com 2013-10-24 08:12:16 +00:00
parent faba61a261
commit fdea26c768
5 changed files with 48 additions and 11 deletions

View file

@ -76,6 +76,7 @@ class _FileSystemWatcherImpl
} }
var socket = new _RawSocket(new _NativeSocket.watch(socketId)); var socket = new _RawSocket(new _NativeSocket.watch(socketId));
_subscription = socket.expand((event) { _subscription = socket.expand((event) {
bool stop = false;
var events = []; var events = [];
var pair = {}; var pair = {};
if (event == RawSocketEvent.READ) { if (event == RawSocketEvent.READ) {
@ -87,18 +88,22 @@ class _FileSystemWatcherImpl
} }
return path; return path;
} }
void add(event) {
if ((event.type & _events) == 0) return;
events.add(event);
}
while (socket.available() > 0) { while (socket.available() > 0) {
for (var event in _readEvents()) { for (var event in _readEvents()) {
if (event == null) continue; if (event == null) continue;
var path = getPath(event); var path = getPath(event);
if ((event[0] & FileSystemEvent.CREATE) != 0) { if ((event[0] & FileSystemEvent.CREATE) != 0) {
events.add(new FileSystemCreateEvent._(path)); add(new FileSystemCreateEvent._(path));
} }
if ((event[0] & FileSystemEvent.MODIFY) != 0) { if ((event[0] & FileSystemEvent.MODIFY) != 0) {
events.add(new FileSystemModifyEvent._(path, true)); add(new FileSystemModifyEvent._(path, true));
} }
if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES) != 0) { if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES) != 0) {
events.add(new FileSystemModifyEvent._(path, false)); add(new FileSystemModifyEvent._(path, false));
} }
if ((event[0] & FileSystemEvent.MOVE) != 0) { if ((event[0] & FileSystemEvent.MOVE) != 0) {
int link = event[1]; int link = event[1];
@ -111,11 +116,15 @@ class _FileSystemWatcherImpl
pair[link] = event; pair[link] = event;
} }
} else { } else {
events.add(new FileSystemMoveEvent._(path, null)); add(new FileSystemMoveEvent._(path, null));
} }
} }
if ((event[0] & FileSystemEvent.DELETE) != 0) { if ((event[0] & FileSystemEvent.DELETE) != 0) {
events.add(new FileSystemDeleteEvent._(path)); add(new FileSystemDeleteEvent._(path));
}
if ((event[0] & FileSystemEvent._DELETE_SELF) != 0) {
add(new FileSystemDeleteEvent._(path));
stop = true;
} }
} }
} }
@ -127,9 +136,9 @@ class _FileSystemWatcherImpl
} else { } else {
assert(false); assert(false);
} }
if (stop) socket.close();
return events; return events;
}) })
.where((event) => (event.type & _events) != 0)
.listen(_controller.add, onDone: _cancel); .listen(_controller.add, onDone: _cancel);
} }
@ -138,6 +147,7 @@ class _FileSystemWatcherImpl
if (_subscription != null) { if (_subscription != null) {
_subscription.cancel(); _subscription.cancel();
} }
_controller.close();
} }
Stream<FileSystemEvent> get stream => _controller.stream; Stream<FileSystemEvent> get stream => _controller.stream;

View file

@ -24,7 +24,8 @@ class FileSystemWatcher {
kModifyContent = 1 << 1, kModifyContent = 1 << 1,
kDelete = 1 << 2, kDelete = 1 << 2,
kMove = 1 << 3, kMove = 1 << 3,
kModefyAttribute = 1 << 4 kModefyAttribute = 1 << 4,
kDeleteSelf = 1 << 5
}; };
struct Event { struct Event {

View file

@ -24,7 +24,7 @@ intptr_t FileSystemWatcher::WatchPath(const char* path,
bool recursive) { bool recursive) {
int fd = TEMP_FAILURE_RETRY(inotify_init1(IN_NONBLOCK | IN_CLOEXEC)); int fd = TEMP_FAILURE_RETRY(inotify_init1(IN_NONBLOCK | IN_CLOEXEC));
if (fd < 0) return -1; if (fd < 0) return -1;
int list_events = 0; int list_events = IN_DELETE_SELF;
if (events & kCreate) list_events |= IN_CREATE; if (events & kCreate) list_events |= IN_CREATE;
if (events & kModifyContent) list_events |= IN_MODIFY | IN_ATTRIB; if (events & kModifyContent) list_events |= IN_MODIFY | IN_ATTRIB;
if (events & kDelete) list_events |= IN_DELETE; if (events & kDelete) list_events |= IN_DELETE;
@ -56,7 +56,7 @@ Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
if (bytes < 0) { if (bytes < 0) {
return DartUtils::NewDartOSError(); return DartUtils::NewDartOSError();
} }
const intptr_t kMaxCount = kBufferSize / kEventSize + 1; const intptr_t kMaxCount = bytes / kEventSize;
Dart_Handle events = Dart_NewList(kMaxCount); Dart_Handle events = Dart_NewList(kMaxCount);
intptr_t offset = 0; intptr_t offset = 0;
intptr_t i = 0; intptr_t i = 0;
@ -70,6 +70,7 @@ Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
if (e->mask & IN_CREATE) mask |= kCreate; if (e->mask & IN_CREATE) mask |= kCreate;
if (e->mask & IN_MOVE) mask |= kMove; if (e->mask & IN_MOVE) mask |= kMove;
if (e->mask & IN_DELETE) mask |= kDelete; if (e->mask & IN_DELETE) mask |= kDelete;
if (e->mask & IN_DELETE_SELF) mask |= kDeleteSelf;
Dart_ListSetAt(event, 0, Dart_NewInteger(mask)); Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie)); Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
if (e->len > 0) { if (e->len > 0) {

View file

@ -353,8 +353,13 @@ abstract class FileSystemEntity {
* files and directories. Recursive watching is supported. * files and directories. Recursive watching is supported.
* *
* The system will start listening for events once the returned [Stream] is * The system will start listening for events once the returned [Stream] is
* being listened to, not when the call to [watch] is issued. Note that the * being listened to, not when the call to [watch] is issued.
* returned [Stream] is endless. To stop the [Stream], cancel the subscription. *
* Note that the returned [Stream] is endless, unless:
*
* * The [Stream] is canceled, e.g. by calling `cancel` on the
* [StreamSubscription].
* * The [FileSystemEntity] being watches, is deleted.
*/ */
Stream<FileSystemEvent> watch({int events: FileSystemEvent.ALL, Stream<FileSystemEvent> watch({int events: FileSystemEvent.ALL,
bool recursive: false}) bool recursive: false})
@ -623,6 +628,7 @@ class FileSystemEvent {
static const int ALL = CREATE | MODIFY | DELETE | MOVE; static const int ALL = CREATE | MODIFY | DELETE | MOVE;
static const int _MODIFY_ATTRIBUTES = 1 << 4; static const int _MODIFY_ATTRIBUTES = 1 << 4;
static const int _DELETE_SELF = 1 << 5;
/** /**
* The type of event. See [FileSystemEvent] for a list of events. * The type of event. See [FileSystemEvent] for a list of events.

View file

@ -111,6 +111,24 @@ void testWatchDeleteFile() {
} }
void testWatchDeleteDir() {
var dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
var watcher = dir.watch(events: 0);
asyncStart();
var sub;
sub = watcher.listen((event) {
if (event is FileSystemDeleteEvent) {
Expect.isTrue(event.path == dir.path);
}
}, onDone: () {
asyncEnd();
});
dir.deleteSync();
}
void testWatchOnlyModifyFile() { void testWatchOnlyModifyFile() {
var dir = Directory.systemTemp.createTempSync('dart_file_system_watcher'); var dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
var file = new File(dir.path + '/file'); var file = new File(dir.path + '/file');
@ -244,6 +262,7 @@ void main() {
testWatchModifyFile(); testWatchModifyFile();
testWatchMoveFile(); testWatchMoveFile();
testWatchDeleteFile(); testWatchDeleteFile();
testWatchDeleteDir();
testWatchOnlyModifyFile(); testWatchOnlyModifyFile();
testMultipleEvents(); testMultipleEvents();
testWatchNonRecursive(); testWatchNonRecursive();