Merge pull request #50 from vibe-d/fix_watcher_cancellation
Fix watcher cancellation
This commit is contained in:
commit
30f614a7ff
|
@ -8,7 +8,6 @@ import eventcore.internal.win32;
|
||||||
|
|
||||||
private extern(Windows) @trusted nothrow @nogc {
|
private extern(Windows) @trusted nothrow @nogc {
|
||||||
BOOL SetEndOfFile(HANDLE hFile);
|
BOOL SetEndOfFile(HANDLE hFile);
|
||||||
BOOL CancelIoEx(HANDLE hFile, OVERLAPPED* lpOverlapped);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final class WinAPIEventDriverFiles : EventDriverFiles {
|
final class WinAPIEventDriverFiles : EventDriverFiles {
|
||||||
|
@ -170,7 +169,7 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
|
||||||
{
|
{
|
||||||
if (slot.callback) {
|
if (slot.callback) {
|
||||||
m_core.removeWaiter();
|
m_core.removeWaiter();
|
||||||
//CancelIoEx(h, &slot.overlapped); // FIXME: currently causes linker errors for DMD due to outdated kernel32.lib files
|
() @trusted { CancelIoEx(h, &slot.overlapped); } ();
|
||||||
slot.callback = null;
|
slot.callback = null;
|
||||||
slot.buffer = null;
|
slot.buffer = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,9 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
|
||||||
return WatcherID.invalid;
|
return WatcherID.invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keep alive as long as the overlapped I/O operation is pending
|
||||||
|
addRef(id);
|
||||||
|
|
||||||
m_core.addWaiter();
|
m_core.addWaiter();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
@ -62,16 +65,36 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
|
||||||
|
|
||||||
override bool releaseRef(WatcherID descriptor)
|
override bool releaseRef(WatcherID descriptor)
|
||||||
{
|
{
|
||||||
auto handle = idToHandle(descriptor);
|
return doReleaseRef(idToHandle(descriptor));
|
||||||
return m_core.m_handles[handle].releaseRef(()nothrow{
|
}
|
||||||
m_core.removeWaiter();
|
|
||||||
|
private static bool doReleaseRef(HANDLE handle)
|
||||||
|
{
|
||||||
|
auto core = WinAPIEventDriver.threadInstance.core;
|
||||||
|
auto slot = () @trusted { return &core.m_handles[handle]; } ();
|
||||||
|
|
||||||
|
if (!slot.releaseRef(() nothrow {
|
||||||
CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
|
|
||||||
() @trusted {
|
() @trusted {
|
||||||
try theAllocator.dispose(m_core.m_handles[handle].watcher.buffer);
|
try theAllocator.dispose(slot.watcher.buffer);
|
||||||
catch (Exception e) assert(false, "Freeing directory watcher buffer failed.");
|
catch (Exception e) assert(false, "Freeing directory watcher buffer failed.");
|
||||||
} ();
|
} ();
|
||||||
m_core.freeSlot(handle);
|
core.freeSlot(handle);
|
||||||
});
|
}))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If only one reference left, then this is the reference created for
|
||||||
|
// the current wait operation. Simply cancel the I/O to let the
|
||||||
|
// completion callback
|
||||||
|
if (slot.refCount == 1) {
|
||||||
|
() @trusted { CancelIoEx(handle, &slot.watcher.overlapped); } ();
|
||||||
|
core.removeWaiter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static nothrow extern(System)
|
private static nothrow extern(System)
|
||||||
|
@ -81,30 +104,23 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
|
||||||
import std.file : isDir;
|
import std.file : isDir;
|
||||||
import std.path : dirName, baseName, buildPath;
|
import std.path : dirName, baseName, buildPath;
|
||||||
|
|
||||||
if (dwError != 0) {
|
|
||||||
// FIXME: this must be propagated to the caller
|
|
||||||
//logWarn("Failed to read directory changes: %s", dwError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto handle = overlapped.hEvent; // *file* handle
|
auto handle = overlapped.hEvent; // *file* handle
|
||||||
auto id = WatcherID(cast(int)handle);
|
auto id = WatcherID(cast(int)handle);
|
||||||
|
|
||||||
/* HACK: this avoids a range voilation in case an already destroyed
|
auto gslot = () @trusted { return &WinAPIEventDriver.threadInstance.core.m_handles[handle]; } ();
|
||||||
watcher still fires a completed event. It does not avoid problems
|
auto slot = () @trusted { return &gslot.watcher(); } ();
|
||||||
that may arise from reused file handles.
|
|
||||||
*/
|
if (dwError != 0 || gslot.refCount == 1) {
|
||||||
if (handle !in WinAPIEventDriver.threadInstance.core.m_handles)
|
// FIXME: error must be propagated to the caller (except for ABORTED
|
||||||
|
// errors)
|
||||||
|
//logWarn("Failed to read directory changes: %s", dwError);
|
||||||
|
doReleaseRef(handle);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: can be 0 if the buffer overflowed
|
// NOTE: cbTransferred can be 0 if the buffer overflowed
|
||||||
if (!cbTransferred)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto slot = () @trusted { return &WinAPIEventDriver.threadInstance.core.m_handles[handle].watcher(); } ();
|
|
||||||
|
|
||||||
ubyte[] result = slot.buffer[0 .. cbTransferred];
|
ubyte[] result = slot.buffer[0 .. cbTransferred];
|
||||||
do {
|
while (result.length) {
|
||||||
assert(result.length >= FILE_NOTIFY_INFORMATION._FileName.offsetof);
|
assert(result.length >= FILE_NOTIFY_INFORMATION._FileName.offsetof);
|
||||||
auto fni = () @trusted { return cast(FILE_NOTIFY_INFORMATION*)result.ptr; } ();
|
auto fni = () @trusted { return cast(FILE_NOTIFY_INFORMATION*)result.ptr; } ();
|
||||||
result = result[fni.NextEntryOffset .. $];
|
result = result[fni.NextEntryOffset .. $];
|
||||||
|
@ -130,7 +146,7 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
|
||||||
if (ch.kind != FileChangeKind.modified || !ch.isDirectory)
|
if (ch.kind != FileChangeKind.modified || !ch.isDirectory)
|
||||||
slot.callback(id, ch);
|
slot.callback(id, ch);
|
||||||
if (fni.NextEntryOffset == 0) break;
|
if (fni.NextEntryOffset == 0) break;
|
||||||
} while (result.length > 0);
|
}
|
||||||
|
|
||||||
triggerRead(handle, *slot);
|
triggerRead(handle, *slot);
|
||||||
}
|
}
|
||||||
|
@ -157,6 +173,7 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
|
||||||
//logError("Failed to read directory changes in '%s'", m_path);
|
//logError("Failed to read directory changes in '%s'", m_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue