VM: attempt to cancel blocking system calls when ctrl-c is pressed

Windows runs ctrl-c in its own thread and doesn't by itself interrupt
blocking system calls when it is pressed. Therefore you have to manually
send an interrupt signal to the stuck thread.
db4
Björn Lindqvist 2014-03-25 17:44:55 +01:00 committed by Doug Coleman
parent e2eebdec4d
commit 0226718a82
4 changed files with 36 additions and 0 deletions

View File

@ -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;

View File

@ -2,6 +2,8 @@
namespace factor {
HANDLE boot_thread;
DWORD current_vm_tls_key;
void init_mvm() {

View File

@ -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:

View File

@ -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;
}