# HG changeset patch # User Michael Goffioul # Date 1384888898 18000 # Node ID 1adf3710bb68b7bd88b58197ebb35686b40f42dc # Parent e5566719e0a16532a8179bab6b0e4e7964faa9f2 Working CTRL-C handling implementation for Win32. * libgui/src/thread-manager.cc (sighandlers.h): New include. (windows_thread_manager::interrupt): Call w32_raise_sigint instead of ::raise. * libinterp/corefcn/sighandlers.h (w32_raise_sigint): New declatation. * libinterp/cirefcn/sighandlers.cc (user_abort): Forward declare. (class w32_interrupt_manager): New singleton helper class. (w32_raise_sigint): New function. (user_abort): Call w32_interrupt_manager::octave_jump_to_enclosing_context instead of octave_jump_to_enclosing_context on Win32 platform. (sigint_handler): Call w32_interrupt_manager::user_abort instead of user_abort on Win32 platform. (octave_catch_interrupts, octave_ignore_interrupts, octave_set_interrupt_handler): Call w32_interrupt_manager::init on Win32 platform. * liboctave/util/oct-rl-edit.c (octave_rl_initialize): Set rl_catch_signals to 0 on Win32 platform. diff -r e5566719e0a1 -r 1adf3710bb68 libgui/src/thread-manager.cc --- a/libgui/src/thread-manager.cc Sun Nov 10 11:06:58 2013 -0500 +++ b/libgui/src/thread-manager.cc Tue Nov 19 14:21:38 2013 -0500 @@ -33,6 +33,7 @@ #include #include +#include "sighandlers.h" #include "thread-manager.h" #if defined (__WIN32__) && ! defined (__CYGWIN__) @@ -47,15 +48,7 @@ void interrupt (void) { - // FIXME: This doesn't work when octave_interrupt_immediately is - // true. Octave crashes, presumably in the call to - // octave_jump_to_enclosing_context. Does this happen because the - // jump occurs while Octave is running in the wrong thread? That - // was happening on Unixy systems until we started using - // pthread_kill and blocking interrupts from all threads except the - // one running the Octave interpreter. - - ::raise (SIGINT); + w32_raise_sigint (); } }; diff -r e5566719e0a1 -r 1adf3710bb68 libinterp/corefcn/sighandlers.cc --- a/libinterp/corefcn/sighandlers.cc Sun Nov 10 11:06:58 2013 -0500 +++ b/libinterp/corefcn/sighandlers.cc Tue Nov 19 14:21:38 2013 -0500 @@ -74,6 +74,153 @@ // List of signals we have caught since last call to octave_signal_handler. static bool octave_signals_caught[NSIG]; +// Forward declaration. +static void user_abort (const char *sig_name, int sig_number); + +#if defined (__WIN32__) && ! defined (__CYGWIN__) + +#define WIN32_LEAN_AND_MEAN +#include + +class +w32_interrupt_manager +{ +public: + ~w32_interrupt_manager (void) + { + if (thread) + CloseHandle (thread); + } + + static bool init (void) { return instance_ok (); } + + static void octave_jump_to_enclosing_context (void) + { + if (instance_ok ()) + instance->do_octave_jump_to_enclosing_context (); + } + + static void user_abort (const char *sig_name, int sig_number) + { + if (instance_ok ()) + instance->do_user_abort (sig_name, sig_number); + } + + static void raise_sigint (void) + { + if (instance_ok ()) + instance->do_raise_sigint (); + } + +private: + w32_interrupt_manager (void) + : thread (0), thread_id (0) + { + thread_id = GetCurrentThreadId (); + + DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), + GetCurrentProcess (), &thread, 0, FALSE, + DUPLICATE_SAME_ACCESS); + } + + static void octave_jump_to_enclosing_context_sync (void) + { +#ifdef _MSC_VER + _fpreset (); +#endif + ::octave_jump_to_enclosing_context (); + } + + void do_octave_jump_to_enclosing_context (void) + { + bool is_interrupt_thread = (GetCurrentThreadId () == thread_id); + + if (is_interrupt_thread) + octave_jump_to_enclosing_context_sync (); + else + { + CONTEXT threadContext; + + SuspendThread (thread); + threadContext.ContextFlags = CONTEXT_CONTROL; + GetThreadContext (thread, &threadContext); + threadContext.Eip = (DWORD) octave_jump_to_enclosing_context_sync; + SetThreadContext (thread, &threadContext); + ResumeThread (thread); + } + } + + void do_user_abort (const char *sig_name, int sig_number) + { + bool is_interrupt_thread = (GetCurrentThreadId () == thread_id); + + if (is_interrupt_thread) + ::user_abort (sig_name, sig_number); + else + { + SuspendThread (thread); + ::user_abort (sig_name, sig_number); + ResumeThread (thread); + } + } + + void do_raise_sigint (void) + { + bool is_interrupt_thread = (GetCurrentThreadId () == thread_id); + + if (is_interrupt_thread) + ::raise (SIGINT); + else + { + SuspendThread (thread); + ::raise (SIGINT); + ResumeThread (thread); + } + } + + static bool instance_ok (void) + { + bool retval = true; + + if (! instance) + { + instance = new w32_interrupt_manager (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create w32_interrupt_manager"); + + retval = false; + } + + return retval; + } + + static void cleanup_instance (void) { delete instance; instance = 0; } + +private: + // A handle to the thread that is running the octave interpreter. + HANDLE thread; + + // The ID of the thread that is running the octave interpreter. + DWORD thread_id; + + static w32_interrupt_manager* instance; +}; + +w32_interrupt_manager* w32_interrupt_manager::instance = 0; + +void w32_raise_sigint (void) +{ + w32_interrupt_manager::raise_sigint (); +} + +#endif + // Signal handler return type. #ifndef BADSIG #define BADSIG (void (*)(int))-1 @@ -351,7 +498,11 @@ if (octave_interrupt_state == 0) octave_interrupt_state = 1; +#if defined (__WIN32__) && ! defined (__CYGWIN__) + w32_interrupt_manager::octave_jump_to_enclosing_context (); +#else octave_jump_to_enclosing_context (); +#endif } else { @@ -378,7 +529,11 @@ static void sigint_handler (int sig) { +#if defined (__WIN32__) && ! defined (__CYGWIN__) + w32_interrupt_manager::user_abort (strsignal (sig), sig); +#else user_abort (strsignal (sig), sig); +#endif } #ifdef SIGPIPE @@ -401,6 +556,10 @@ { octave_interrupt_handler retval; +#if defined (__WIN32__) && ! defined (__CYGWIN__) + w32_interrupt_manager::init (); +#endif + #ifdef SIGINT retval.int_handler = octave_set_signal_handler (SIGINT, sigint_handler); #endif @@ -417,6 +576,10 @@ { octave_interrupt_handler retval; +#if defined (__WIN32__) && ! defined (__CYGWIN__) + w32_interrupt_manager::init (); +#endif + #ifdef SIGINT retval.int_handler = octave_set_signal_handler (SIGINT, SIG_IGN); #endif @@ -434,6 +597,10 @@ { octave_interrupt_handler retval; +#if defined (__WIN32__) && ! defined (__CYGWIN__) + w32_interrupt_manager::init (); +#endif + #ifdef SIGINT retval.int_handler = octave_set_signal_handler (SIGINT, h.int_handler, restart_syscalls); diff -r e5566719e0a1 -r 1adf3710bb68 libinterp/corefcn/sighandlers.h --- a/libinterp/corefcn/sighandlers.h Sun Nov 10 11:06:58 2013 -0500 +++ b/libinterp/corefcn/sighandlers.h Tue Nov 19 14:21:38 2013 -0500 @@ -82,6 +82,10 @@ octave_set_interrupt_handler (const volatile octave_interrupt_handler&, bool restart_syscalls = true); +#if defined (__WIN32__) && ! defined (__CYGWIN__) +extern OCTINTERP_API void w32_raise_sigint (void); +#endif + // extern void ignore_sigchld (void); // Maybe this should be in a separate file? diff -r e5566719e0a1 -r 1adf3710bb68 liboctave/util/oct-rl-edit.c --- a/liboctave/util/oct-rl-edit.c Sun Nov 10 11:06:58 2013 -0500 +++ b/liboctave/util/oct-rl-edit.c Tue Nov 19 14:21:38 2013 -0500 @@ -395,6 +395,10 @@ void octave_rl_initialize (void) { +#if defined (__WIN32__) && ! defined (__CYGWIN__) + rl_catch_signals = 0; +#endif + rl_initialize (); }