Fix segfault in DirectoryWatcher.

This commit is contained in:
Sönke Ludwig 2017-01-29 22:11:17 +01:00
parent d0a55ef374
commit e88d2d1b4b
No known key found for this signature in database
GPG key ID: D95E8DB493EE314C

View file

@ -563,21 +563,34 @@ struct DirectoryWatcher { // TODO: avoid all those heap allocations!
@safe: @safe:
private struct Context { private static struct Context {
Path path; Path path;
bool recursive; bool recursive;
Appender!(DirectoryChange[]) changes; Appender!(DirectoryChange[]) changes;
LocalManualEvent changeEvent; LocalManualEvent changeEvent;
void onChange(WatcherID, in ref FileChange change)
nothrow {
DirectoryChangeType ct;
final switch (change.kind) {
case FileChangeKind.added: ct = DirectoryChangeType.added; break;
case FileChangeKind.removed: ct = DirectoryChangeType.removed; break;
case FileChangeKind.modified: ct = DirectoryChangeType.modified; break;
}
this.changes ~= DirectoryChange(ct, Path(change.directory) ~ change.name.idup);
this.changeEvent.emit();
}
} }
private { private {
WatcherID m_watcher; WatcherID m_watcher;
Context m_context; Context* m_context;
} }
private this(Path path, bool recursive) private this(Path path, bool recursive)
{ {
m_watcher = eventDriver.watchers.watchDirectory(path.toNativeString, recursive, &onChange); m_context = new Context; // FIME: avoid GC allocation (use FD user data slot)
m_watcher = eventDriver.watchers.watchDirectory(path.toNativeString, recursive, &m_context.onChange);
m_context.path = path; m_context.path = path;
m_context.recursive = recursive; m_context.recursive = recursive;
m_context.changes = appender!(DirectoryChange[]); m_context.changes = appender!(DirectoryChange[]);
@ -608,31 +621,24 @@ struct DirectoryWatcher { // TODO: avoid all those heap allocations!
*/ */
bool readChanges(ref DirectoryChange[] dst, Duration timeout = Duration.max) bool readChanges(ref DirectoryChange[] dst, Duration timeout = Duration.max)
{ {
if (timeout == Duration.max) {
while (!m_context.changes.data.length)
m_context.changeEvent.wait(Duration.max, m_context.changeEvent.emitCount);
} else {
SysTime now = Clock.currTime(UTC()); SysTime now = Clock.currTime(UTC());
SysTime final_time = now + timeout; SysTime final_time = now + timeout;
while (!m_context.changes.data.length) { while (!m_context.changes.data.length) {
m_context.changeEvent.wait(final_time - now, m_context.changeEvent.emitCount); m_context.changeEvent.wait(final_time - now, m_context.changeEvent.emitCount);
if (m_context.changes.data.length) break; now = Clock.currTime(UTC());
else now = Clock.currTime(UTC()); if (now >= final_time) break;
}
if (!m_context.changes.data.length) return false;
} }
if (!m_context.changes.data.length) return false;
dst = m_context.changes.data; dst = m_context.changes.data;
m_context.changes = appender!(DirectoryChange[]); m_context.changes = appender!(DirectoryChange[]);
return true; return true;
} }
private void onChange(WatcherID, in ref FileChange change)
nothrow {
DirectoryChangeType ct;
final switch (change.kind) {
case FileChangeKind.added: ct = DirectoryChangeType.added; break;
case FileChangeKind.removed: ct = DirectoryChangeType.removed; break;
case FileChangeKind.modified: ct = DirectoryChangeType.modified; break;
}
m_context.changes ~= DirectoryChange(ct, Path(change.directory) ~ change.name.idup);
m_context.changeEvent.emit();
}
} }