!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
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 {
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() {}
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);
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),
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);
// 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();