Merge pull request #53 from vibe-d/fix_winapi_handles
Fix WinAPI issues
This commit is contained in:
commit
8242fd058e
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue