]> gitweb.factorcode.org Git - factor.git/commitdiff
VM: implement a ctrl-break handler thread (#1573)
authorAlexander Iljin <ajsoft@yandex.ru>
Wed, 15 Jun 2016 13:19:52 +0000 (16:19 +0300)
committerJohn Benediktsson <mrjbq7@gmail.com>
Tue, 1 Nov 2016 23:53:00 +0000 (16:53 -0700)
Nmakefile
vm/os-unix.cpp
vm/os-windows.cpp
vm/safepoints.cpp
vm/vm.cpp
vm/vm.hpp

index 689156a57fdc0987cd7598c37c8e13a681f5735e..ffd8b2d14e41f0eab5627820c40c94b78d05d8a0 100644 (file)
--- a/Nmakefile
+++ b/Nmakefile
@@ -8,7 +8,7 @@ GIT_LABEL = git-label-missing
 
 !IF DEFINED(PLATFORM)
 
-LINK_FLAGS = /nologo shell32.lib
+LINK_FLAGS = /nologo shell32.lib user32.lib
 CL_FLAGS = /nologo /O2 /WX /W3 /D_CRT_SECURE_NO_WARNINGS /DFACTOR_VERSION=$(VERSION) /DFACTOR_GIT_LABEL=$(GIT_LABEL)
 CL_FLAGS_VISTA = /D_WIN32_WINNT=0x0600
 
index 7c018eee0db22f5253ad01ed0b83dc3737c0a055..5d030d2c8e5c9aae60a9a4ccd891f66ae716a748 100644 (file)
@@ -474,6 +474,14 @@ void handle_ctrl_c() {
   sigaction_safe(SIGINT, &fep_sigaction, NULL);
 }
 
+void factor_vm::primitive_disable_ctrl_break() {
+  stop_on_ctrl_break = false;
+}
+
+void factor_vm::primitive_enable_ctrl_break() {
+  stop_on_ctrl_break = true;
+}
+
 void abort() {
   sig_t ret;
   do {
index 145344d767f860bb6126c865ce46c7f25d8ebef0..08651a1bd5a3cbdcf2e87bf6ffc9d4fe820ed68f 100644 (file)
@@ -294,6 +294,50 @@ void handle_ctrl_c() {
   SetConsoleCtrlHandler(factor::ctrl_handler, TRUE);
 }
 
+const int ctrl_break_sleep = 10; /* msec */
+
+static DWORD WINAPI ctrl_break_thread_proc(LPVOID parent_vm) {
+  bool ctrl_break_handled = false;
+  factor_vm* vm = static_cast<factor_vm*>(parent_vm);
+  while (vm->stop_on_ctrl_break) {
+    if (GetAsyncKeyState(VK_CANCEL) >= 0) { /* Ctrl-Break is released. */
+      ctrl_break_handled = false;  /* Wait for the next press. */
+    } else if (!ctrl_break_handled) {
+      /* Check if the VM thread has the same Id as the thread Id of the
+         currently active window. Note that thread Id is not a handle. */
+      DWORD fg_thd_id = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
+      if ((fg_thd_id == vm->thread_id) && !vm->fep_p) {
+        vm->enqueue_fep();
+        ctrl_break_handled = true;
+      }
+    }
+    Sleep(ctrl_break_sleep);
+  }
+  return 0;
+}
+
+void factor_vm::primitive_disable_ctrl_break() {
+  stop_on_ctrl_break = false;
+  if (ctrl_break_thread != NULL) {
+    DWORD wait_result = WaitForSingleObject(ctrl_break_thread,
+                                            2 * ctrl_break_sleep);
+    if (wait_result != WAIT_OBJECT_0)
+      TerminateThread(ctrl_break_thread, 0);
+    CloseHandle(ctrl_break_thread);
+    ctrl_break_thread = NULL;
+  }
+}
+
+void factor_vm::primitive_enable_ctrl_break() {
+  stop_on_ctrl_break = true;
+  if (ctrl_break_thread == NULL) {
+    DisableProcessWindowsGhosting();
+    ctrl_break_thread = CreateThread(NULL, 0, factor::ctrl_break_thread_proc,
+                                     static_cast<LPVOID>(this), 0, NULL);
+    SetThreadPriority(ctrl_break_thread, THREAD_PRIORITY_ABOVE_NORMAL);
+  }
+}
+
 void lock_console() {}
 
 void unlock_console() {}
index ccfc27672ee114a057d27ddba3a53183bf166f39..180074a2d44f673640d58ab65d900be147a4fda6 100644 (file)
@@ -35,11 +35,18 @@ void factor_vm::handle_safepoint(cell pc) {
   faulting_p = false;
 
   if (atomic::load(&safepoint_fep_p)) {
+    atomic::store(&safepoint_fep_p, false);
     if (atomic::load(&sampling_profiler_p))
       end_sampling_profiler();
     std::cout << "Interrupted\n";
+    if (stop_on_ctrl_break) {
+      /* Ctrl-Break throws an exception, interrupting the main thread, same
+         as the "t" command in the factorbug debugger. But for Ctrl-Break to
+         work we don't require the debugger to be activated, or even enabled. */
+      general_error(ERROR_INTERRUPT, false_object, false_object);
+      FACTOR_ASSERT(false);
+    }
     factorbug();
-    atomic::store(&safepoint_fep_p, false);
   } else if (atomic::load(&sampling_profiler_p)) {
     FACTOR_ASSERT(code->seg->in_segment_p(pc));
     code_block* block = code->code_block_for_address(pc);
index b0bae8b778ffdaa955b0aca77d12962d7e17394f..5e9f0209d665092625f153aa8e050dfdaba8e34e 100644 (file)
--- a/vm/vm.cpp
+++ b/vm/vm.cpp
@@ -7,6 +7,11 @@ factor_vm::factor_vm(THREADHANDLE thread)
       nursery(0, 0),
       faulting_p(false),
       thread(thread),
+#if defined(WINDOWS)
+      thread_id(GetCurrentThreadId()),
+      ctrl_break_thread(NULL),
+      stop_on_ctrl_break(false),
+#endif
       callback_id(0),
       c_to_factor_func(NULL),
       sampling_profiler_p(false),
index 5fc4aabf543b6b41319f44c444b6621e8244ae7c..900ca98dec419abc321348e492b38b37d34d5e7d 100644 (file)
--- a/vm/vm.hpp
+++ b/vm/vm.hpp
@@ -393,6 +393,7 @@ struct factor_vm {
   void factorbug_usage(bool advanced_p);
   void factorbug();
   void primitive_die();
+  volatile bool stop_on_ctrl_break;
 
   // arrays
   inline void set_array_nth(array* array, cell slot, cell value);
@@ -701,6 +702,11 @@ struct factor_vm {
 
 // os-windows
 #if defined(WINDOWS)
+  /* Id of the main thread we run in. Used for Ctrl-Break handling. */
+  DWORD thread_id;
+
+  HANDLE ctrl_break_thread;
+
   HANDLE sampler_thread;
   void sampler_thread_loop();