]> gitweb.factorcode.org Git - factor.git/commitdiff
VM: attempt to cancel blocking system calls when ctrl-c is pressed
authorBjörn Lindqvist <bjourne@gmail.com>
Tue, 25 Mar 2014 16:44:55 +0000 (17:44 +0100)
committerDoug Coleman <doug.coleman@gmail.com>
Sun, 11 May 2014 01:13:04 +0000 (18:13 -0700)
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.

vm/main-windows.cpp
vm/mvm-windows.cpp
vm/os-windows.cpp
vm/os-windows.hpp

index b01f780cf1f8be2764fa384b6b2fd69af57fb766..f9c6ae5baa8f4c69742e2d1943a2cee8e52e45c4 100644 (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;
index 2177629f5a3755568b9acea96be3029b450ac5ee..e90538d11af5b53054aefc92e18b4791e315c373 100644 (file)
@@ -2,6 +2,8 @@
 
 namespace factor {
 
+HANDLE boot_thread;
+
 DWORD current_vm_tls_key;
 
 void init_mvm() {
index 5b29f23f02f3746d7f0e0f1183287d90bbbf2d5b..64e425b13ad255fe312a09c4bb83293b706dcd9d 100644 (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:
index dd429340fdc533bf897f6cb9cfabc5bc5337be0c..a83ea2ff8d27c278bec33bfc8d203e979495deae 100644 (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;
 }