Merge pull request #53 from vibe-d/fix_winapi_handles

Fix WinAPI issues
This commit is contained in:
Sönke Ludwig 2018-03-03 20:51:10 +01:00 committed by GitHub
commit 8242fd058e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 32 deletions

View file

@ -219,22 +219,20 @@ private struct HandleSlot {
package struct FileSlot { package struct FileSlot {
static struct Direction(bool RO) { static struct Direction(bool RO) {
OVERLAPPED overlapped; OVERLAPPED_FILE overlapped;
WinAPIEventDriverCore core;
FileIOCallback callback; FileIOCallback callback;
ulong offset; ulong offset;
size_t bytesTransferred; size_t bytesTransferred;
IOMode mode; IOMode mode;
static if (RO) const(ubyte)[] buffer; static if (RO) const(ubyte)[] buffer;
else ubyte[] buffer; else ubyte[] buffer;
HANDLE handle; // set to INVALID_HANDLE_VALUE when closed
void invokeCallback(IOStatus status, size_t bytes_transferred) void invokeCallback(IOStatus status, size_t bytes_transferred)
@safe nothrow { @safe nothrow {
auto cb = this.callback; auto cb = this.callback;
this.callback = null; this.callback = null;
assert(cb !is null); assert(cb !is null);
cb(FileFD(cast(int)this.handle), status, bytes_transferred); cb(overlapped.handle, status, bytes_transferred);
} }
} }
Direction!false read; Direction!false read;
@ -248,3 +246,9 @@ package struct WatcherSlot {
bool recursive; bool recursive;
FileChangesCallback callback; FileChangesCallback callback;
} }
package struct OVERLAPPED_FILE {
OVERLAPPED overlapped;
WinAPIEventDriverCore driver;
FileFD handle;
}

View file

@ -21,7 +21,7 @@ import eventcore.drivers.winapi.watchers;
import core.sys.windows.windows; import core.sys.windows.windows;
static assert(HANDLE.sizeof <= FD.BaseType.sizeof); static assert(HANDLE.sizeof <= FD.BaseType.sizeof);
static assert(FD(cast(int)INVALID_HANDLE_VALUE) == FD.init); static assert(FD(cast(size_t)INVALID_HANDLE_VALUE) == FD.init);
final class WinAPIEventDriver : EventDriver { final class WinAPIEventDriver : EventDriver {

View file

@ -142,6 +142,6 @@ final class WinAPIEventDriverEvents : EventDriverEvents {
private static HANDLE idToHandle(EventID event) private static HANDLE idToHandle(EventID event)
@trusted { @trusted {
return cast(HANDLE)cast(int)event; return cast(HANDLE)cast(size_t)event;
} }
} }

View file

@ -43,33 +43,41 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
BOOL ret = SetEndOfFile(handle); BOOL ret = SetEndOfFile(handle);
if (!ret) { if (!ret) {
CloseHandle(handle); CloseHandle(handle);
return FileFD.init; return FileFD.invalid;
} }
} }
return adopt(cast(int)handle); return adoptInternal(handle);
} }
override FileFD adopt(int system_handle) override FileFD adopt(int system_handle)
{ {
auto handle = () @trusted { return cast(HANDLE)system_handle; } (); return adoptInternal(() @trusted { return cast(HANDLE)system_handle; } ());
}
private FileFD adoptInternal(HANDLE handle)
{
DWORD f; DWORD f;
if (!() @trusted { return GetHandleInformation(handle, &f); } ()) if (!() @trusted { return GetHandleInformation(handle, &f); } ())
return FileFD.init; return FileFD.invalid;
auto s = m_core.setupSlot!FileSlot(handle); auto s = m_core.setupSlot!FileSlot(handle);
s.read.handle = s.write.handle = handle;
return FileFD(system_handle); s.read.overlapped.driver = m_core;
s.read.overlapped.handle = FileFD(cast(size_t)handle);
s.write.overlapped.driver = m_core;
s.write.overlapped.handle = FileFD(cast(size_t)handle);
return FileFD(cast(size_t)handle);
} }
override void close(FileFD file) override void close(FileFD file)
{ {
auto h = idToHandle(file); auto h = idToHandle(file);
auto slot = () @trusted { return &m_core.m_handles[h].file(); } (); auto slot = () @trusted { return &m_core.m_handles[h].file(); } ();
if (slot.read.handle != INVALID_HANDLE_VALUE) { if (slot.read.overlapped.handle != FileFD.invalid) {
CloseHandle(h); CloseHandle(h);
slot.read.handle = slot.write.handle = INVALID_HANDLE_VALUE; slot.read.overlapped.handle = slot.write.overlapped.handle = FileFD.invalid;
} }
} }
@ -95,7 +103,6 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
slot.offset = offset; slot.offset = offset;
slot.buffer = buffer; slot.buffer = buffer;
slot.mode = mode; slot.mode = mode;
slot.core = m_core;
slot.callback = on_write_finish; slot.callback = on_write_finish;
m_core.addWaiter(); m_core.addWaiter();
startIO!(WriteFileEx, true)(h, slot); startIO!(WriteFileEx, true)(h, slot);
@ -114,7 +121,6 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
slot.offset = offset; slot.offset = offset;
slot.buffer = buffer; slot.buffer = buffer;
slot.mode = mode; slot.mode = mode;
slot.core = m_core;
slot.callback = on_read_finish; slot.callback = on_read_finish;
m_core.addWaiter(); m_core.addWaiter();
startIO!(ReadFileEx, false)(h, slot); startIO!(ReadFileEx, false)(h, slot);
@ -150,7 +156,7 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
{ {
import std.algorithm.comparison : min; import std.algorithm.comparison : min;
with (slot.overlapped) { with (slot.overlapped.overlapped) {
Internal = 0; Internal = 0;
InternalHigh = 0; InternalHigh = 0;
Offset = cast(uint)(slot.offset & 0xFFFFFFFF); Offset = cast(uint)(slot.offset & 0xFFFFFFFF);
@ -159,8 +165,8 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
} }
auto nbytes = min(slot.buffer.length, DWORD.max); auto nbytes = min(slot.buffer.length, DWORD.max);
if (!() @trusted { return fun(h, &slot.buffer[0], nbytes, &slot.overlapped, &onIOFinished!(fun, RO)); } ()) { if (!() @trusted { return fun(h, &slot.buffer[0], nbytes, &slot.overlapped.overlapped, &onIOFinished!(fun, RO)); } ()) {
slot.core.removeWaiter(); slot.overlapped.driver.removeWaiter();
slot.invokeCallback(IOStatus.error, slot.bytesTransferred); slot.invokeCallback(IOStatus.error, slot.bytesTransferred);
} }
} }
@ -169,20 +175,23 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
{ {
if (slot.callback) { if (slot.callback) {
m_core.removeWaiter(); m_core.removeWaiter();
() @trusted { CancelIoEx(h, &slot.overlapped); } (); () @trusted { CancelIoEx(h, &slot.overlapped.overlapped); } ();
slot.callback = null; slot.callback = null;
slot.buffer = null; slot.buffer = null;
} }
} }
private static extern(Windows) private static extern(Windows)
void onIOFinished(alias fun, bool RO)(DWORD error, DWORD bytes_transferred, OVERLAPPED* overlapped) void onIOFinished(alias fun, bool RO)(DWORD error, DWORD bytes_transferred, OVERLAPPED* _overlapped)
{ {
auto ctx = () @trusted { return cast(OVERLAPPED_FILE*)_overlapped; } ();
auto slot = () @trusted { return cast(FileSlot.Direction!RO*)overlapped.hEvent; } (); FileFD id = ctx.handle;
auto handle = idToHandle(id);
static if (RO)
auto slot = () @trusted { return &ctx.driver.m_handles[handle].file.write; } ();
else
auto slot = () @trusted { return &ctx.driver.m_handles[handle].file.read; } ();
assert(slot !is null); assert(slot !is null);
HANDLE h = slot.handle;
auto id = FileFD(cast(int)h);
if (!slot.callback) { if (!slot.callback) {
// request was already cancelled // request was already cancelled
@ -190,7 +199,7 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
} }
if (error != 0) { if (error != 0) {
slot.core.removeWaiter(); ctx.driver.removeWaiter();
slot.invokeCallback(IOStatus.error, slot.bytesTransferred + bytes_transferred); slot.invokeCallback(IOStatus.error, slot.bytesTransferred + bytes_transferred);
return; return;
} }
@ -199,15 +208,15 @@ final class WinAPIEventDriverFiles : EventDriverFiles {
slot.offset += bytes_transferred; slot.offset += bytes_transferred;
if (slot.bytesTransferred >= slot.buffer.length || slot.mode != IOMode.all) { if (slot.bytesTransferred >= slot.buffer.length || slot.mode != IOMode.all) {
slot.core.removeWaiter(); ctx.driver.removeWaiter();
slot.invokeCallback(IOStatus.ok, slot.bytesTransferred); slot.invokeCallback(IOStatus.ok, slot.bytesTransferred);
} else { } else {
startIO!(fun, RO)(h, slot); startIO!(fun, RO)(handle, slot);
} }
} }
private static HANDLE idToHandle(FileFD id) private static HANDLE idToHandle(FileFD id)
@trusted { @trusted {
return cast(HANDLE)cast(int)id; return cast(HANDLE)cast(size_t)id;
} }
} }

View file

@ -35,7 +35,7 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
return WatcherID.invalid; return WatcherID.invalid;
auto id = WatcherID(cast(int)handle); auto id = WatcherID(cast(size_t)handle);
auto slot = m_core.setupSlot!WatcherSlot(handle); auto slot = m_core.setupSlot!WatcherSlot(handle);
slot.directory = path; slot.directory = path;
@ -80,6 +80,7 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
try theAllocator.dispose(slot.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.");
} (); } ();
slot.watcher.buffer = null;
core.freeSlot(handle); core.freeSlot(handle);
})) }))
{ {
@ -91,6 +92,7 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
// completion callback // completion callback
if (slot.refCount == 1) { if (slot.refCount == 1) {
() @trusted { CancelIoEx(handle, &slot.watcher.overlapped); } (); () @trusted { CancelIoEx(handle, &slot.watcher.overlapped); } ();
slot.watcher.callback = null;
core.removeWaiter(); core.removeWaiter();
} }
@ -105,7 +107,7 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
import std.path : dirName, baseName, buildPath; import std.path : dirName, baseName, buildPath;
auto handle = overlapped.hEvent; // *file* handle auto handle = overlapped.hEvent; // *file* handle
auto id = WatcherID(cast(int)handle); auto id = WatcherID(cast(size_t)handle);
auto gslot = () @trusted { return &WinAPIEventDriver.threadInstance.core.m_handles[handle]; } (); auto gslot = () @trusted { return &WinAPIEventDriver.threadInstance.core.m_handles[handle]; } ();
auto slot = () @trusted { return &gslot.watcher(); } (); auto slot = () @trusted { return &gslot.watcher(); } ();
@ -118,11 +120,21 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
return; return;
} }
if (!slot.callback) return;
// NOTE: cbTransferred can be 0 if the buffer overflowed // NOTE: cbTransferred can be 0 if the buffer overflowed
ubyte[] result = slot.buffer[0 .. cbTransferred]; ubyte[] result = slot.buffer[0 .. cbTransferred];
while (result.length) { 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; } ();
if (fni.NextEntryOffset > result.length) {
import std.stdio : stderr;
() @trusted {
try stderr.writeln("ERROR: Invalid directory watcher event received.");
catch (Exception e) {}
} ();
break;
}
result = result[fni.NextEntryOffset .. $]; result = result[fni.NextEntryOffset .. $];
FileChange ch; FileChange ch;
@ -177,5 +189,5 @@ final class WinAPIEventDriverWatchers : EventDriverWatchers {
return true; return true;
} }
static private HANDLE idToHandle(WatcherID id) @trusted { return cast(HANDLE)cast(int)id; } static private HANDLE idToHandle(WatcherID id) @trusted { return cast(HANDLE)cast(size_t)id; }
} }