xonsh / slug

A snail without its shell
BSD 3-Clause "New" or "Revised" License
15 stars 2 forks source link

Interruptible Reads on Windows #7

Open AstraLuma opened 7 years ago

AstraLuma commented 7 years ago

Both Valve and QuickConnect need extremely special windows implementations.

So I think we need to use win32's ReadFile() manually in conjunction with CancelSynchronousIo() in order to not read an extra block when switching.

AstraLuma commented 7 years ago

(On POSIX, I'm just using a selector, which seems to be ok.)

AstraLuma commented 7 years ago

The cross-platform solution is to have a background singleton that reads from all the pipes we care about and dispatch to the object that cares about it at the moment. (ie, the home-spun event loop option) Which will be fine until someone wants to coordinate those changes with something that can't be controlled the same way (eg, an external process).

AstraLuma commented 7 years ago

Note: WaitForMultipleObjectsEx()

EDIT: Doesn't work on pipes.

AstraLuma commented 7 years ago

PeekNamedPipe() does work on anonymous pipes, though.

EDIT: .fileno() returns some kind of emulated file descriptor with Unix-like semantics, not the actual windows handle. Oddly, Win32 calls want the handle, not the file descriptor.

AstraLuma commented 7 years ago

The winvalve branch tries to use CancelSynchronousIo(). This doesn't work because CPython's .read() loops on the C read() call unless there's a Python exception and an interrupted flag is set. (Or the C read() not breaking, I didn't dig deep enough to tell the difference.)

The winvalve-peek branch tries to use PeekNamedPipe(), but fails due to the file descriptor emulation layer and the true win32 handles being hidden from us. (Basically, _pipe() vs CreatePipe())

AstraLuma commented 7 years ago

Oh, and just as a reminder: These might need to be used with other things (standard IO, files, etc)

AstraLuma commented 7 years ago

So I think ReadFile()/CancelSyncronousIO() is the way to go on this, because it should support whatever kind of file-like that gets passed in. To avoid the file descriptor/handle issue, use _get_osfhandle() (Py). (Note that this handle is managed by the ms c runtime and should NOT be closed by slug. Slug should maintain a reference to the Python file object associated with the file descriptor and delete its copy of the handle before letting the file object fall out of scope.)