diff --git a/vm/main-windows.cpp b/vm/main-windows.cpp index b01f780cf1..f9c6ae5baa 100644 --- a/vm/main-windows.cpp +++ b/vm/main-windows.cpp @@ -1,6 +1,14 @@ #include "master.hpp" VM_C_API int wmain(int argc, wchar_t** argv) { + HANDLE proc = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + BOOL res = DuplicateHandle(proc, thread, proc, + &factor::boot_thread, GENERIC_ALL, FALSE, 0); + if (!res) { + factor::fatal_error("DuplicateHandle() failed", GetLastError()); + return 1; + } factor::init_globals(); factor::start_standalone_factor(argc, argv); return 0; diff --git a/vm/mvm-windows.cpp b/vm/mvm-windows.cpp index 2177629f5a..e90538d11a 100644 --- a/vm/mvm-windows.cpp +++ b/vm/mvm-windows.cpp @@ -2,6 +2,8 @@ namespace factor { +HANDLE boot_thread; + DWORD current_vm_tls_key; void init_mvm() { diff --git a/vm/os-windows.cpp b/vm/os-windows.cpp index 5b29f23f02..64e425b13a 100644 --- a/vm/os-windows.cpp +++ b/vm/os-windows.cpp @@ -249,6 +249,26 @@ VM_C_API LONG exception_handler(PEXCEPTION_RECORD e, void* frame, PCONTEXT c, return ExceptionContinueSearch; } +/* On Unix SIGINT (ctrl-c) automatically interrupts blocking io system + calls. It doesn't on Windows, so we need to manually send some + cancellation requests to unblock the thread. */ +VOID CALLBACK dummy_cb (ULONG_PTR dwParam) { } + +static void wake_up_thread(HANDLE thread) { + if (!CancelSynchronousIo(thread)) { + DWORD err = GetLastError(); + /* CancelSynchronousIo() didn't find anything to cancel, let's try + with QueueUserAPC() instead. */ + if (err == ERROR_NOT_FOUND) { + if (!QueueUserAPC(&dummy_cb, thread, NULL)) { + fatal_error("QueueUserAPC() failed", GetLastError()); + } + } else { + fatal_error("CancelSynchronousIo() failed", err); + } + } +} + static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: { @@ -259,6 +279,10 @@ static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) { FACTOR_ASSERT(thread_vms.size() == 1); factor_vm* vm = thread_vms.begin()->second; vm->safepoint.enqueue_fep(vm); + + /* Before leaving the ctrl_handler, try and wake up the main + thread. */ + wake_up_thread(factor::boot_thread); return TRUE; } default: diff --git a/vm/os-windows.hpp b/vm/os-windows.hpp index dd429340fd..a83ea2ff8d 100644 --- a/vm/os-windows.hpp +++ b/vm/os-windows.hpp @@ -88,4 +88,6 @@ inline static void breakpoint() { DebugBreak(); } #define CODE_TO_FUNCTION_POINTER_CALLBACK(vm, code) (void)0 #define FUNCTION_CODE_POINTER(ptr) ptr #define FUNCTION_TOC_POINTER(ptr) ptr + +extern HANDLE boot_thread; }