Mercurial > octave-nkf
diff libcruft/misc/cquit.c @ 5451:ed08548b9054
[project @ 2005-09-15 19:52:50 by jwe]
author | jwe |
---|---|
date | Thu, 15 Sep 2005 19:52:50 +0000 |
parents | 4c8a2e4e0717 |
children | ace8d8d26933 |
line wrap: on
line diff
--- a/libcruft/misc/cquit.c Thu Sep 15 15:36:26 2005 +0000 +++ b/libcruft/misc/cquit.c Thu Sep 15 19:52:50 2005 +0000 @@ -44,6 +44,176 @@ memcpy (current_context, save_buf, sizeof (octave_jmp_buf)); } +#if defined (__WIN32__) && ! defined (_POSIX_VERSION) + +/* XXX FIXME XXX -- eventually remove the debugging */ +#if defined (DEBUG) + +#define PRINT_CURRENT_THREAD() printf ("%lx: ", GetCurrentThreadId ()) + +#define DEBUGs(s) \ + do \ + { \ + PRINT_CURRENT_THREAD (); \ + printf (s "\n"); \ + fflush (stdout); \ + } \ + while (0) + +#define DEBUGd(s, d) \ + do \ + { \ + PRINT_CURRENT_THREAD (); \ + printf (s "\n", d); \ + fflush (stdout); \ + } \ + while (0) + +#else +#define DEBUGs(s) +#define DEBUGd(s, d) +#endif + +CRITICAL_SECTION w32_thread_setjmp_mutex; +static CONTEXT w32_signal_context; +static int w32_signal_to_raise = 0; +static DWORD w32_main_thread_id; +static HANDLE w32_main_thread; +static HANDLE w32_restore_thread = NULL; + +int +w32_in_main_thread(void) +{ + return (GetCurrentThreadId () == w32_main_thread_id); +} + +static DWORD WINAPI +w32_reset_context (LPVOID v) +{ + PCONTEXT context = (PCONTEXT)v; + int ret; + + /* Mutex the setjmp/longjmp */ + EnterCriticalSection (&w32_thread_setjmp_mutex); + + DEBUGs ("enter w32_set_context"); + SuspendThread (w32_main_thread); + DEBUGs ("main suspended"); + if (! SetThreadContext (w32_main_thread, context)) + { + fprintf (stderr, "%lx: context failed: ctrl-c won't work\n", + GetCurrentThreadId ()); + fflush (stderr); + } + DEBUGs ("context captured (or not)"); + ret = ResumeThread (w32_main_thread); + DEBUGd ("main resumed with %d", ret); + + LeaveCriticalSection (&w32_thread_setjmp_mutex); + return 0; +} + +static void +w32_raise_in_main (void) +{ + DWORD threadid; + + DEBUGd ("w32_raise_in_main with signal %d", w32_signal_to_raise); + raise (w32_signal_to_raise); + DEBUGd ("w32_raise_in_main signal %d returned a value", + w32_signal_to_raise); + + DEBUGs ("attempting to restore main to pre-signal configuration"); + if (w32_restore_thread != NULL) /* Catch leaky threads */ + CloseHandle (w32_restore_thread); + w32_restore_thread = CreateThread (NULL, 10000, w32_reset_context, + &w32_signal_context, 0, &threadid); + if (w32_restore_thread == NULL) + { + fprintf (stderr, "w32_raise_in_main couldn't create thread\n"); + fflush (stderr); + } + else + { + DEBUGs ("waiting to restore raise context"); + WaitForSingleObject (w32_restore_thread, INFINITE); + fprintf (stderr, "w32_raise_in_main couldn't restore context\n"); + fflush (stderr); + } +} + +void +w32_raise_final (void) +{ + CloseHandle (w32_main_thread); + if (w32_restore_thread != NULL) /* Catch leaky threads */ + CloseHandle (w32_restore_thread); + w32_main_thread = w32_restore_thread = NULL; +} + +/* Raise the given signal in the main thread. w32_raise_init () + must have been called from the main thread already. */ +void +w32_raise (int sig) +{ + int ret; + + if (w32_in_main_thread ()) + { + /* Called from main thread -- a simple raise () should work. */ + DEBUGd ("raising signal %d within main", signal); + raise (sig); + DEBUGd ("returning from signal %d within main", signal); + } + else + { + /* Called from alternate thread -- call w32_raise_in_main in the + main thread with w32_signal_to_raise set to the signal */ + CONTEXT raise_context; + DEBUGd ("raising signal %d from separate thread", signal); + + /* Suspend main and remember the context. */ + SuspendThread (w32_main_thread); + /* X86 code */ + w32_signal_context.ContextFlags + = CONTEXT_FULL|CONTEXT_FLOATING_POINT|CONTEXT_DEBUG_REGISTERS; + GetThreadContext (w32_main_thread, &w32_signal_context); + + /* Change the context to w32_raise_in_main. The + context.Eip=&fn trick for setting the program counter is + courtesy of + + http://fit.c2.com/files/LispPlatform/lisp/clisp-2.28/src/win32aux.d + + Auxiliary functions for CLISP on Win32, Bruno Haible + 1997-1999. */ + + memcpy (&raise_context, &w32_signal_context, sizeof (CONTEXT)); + raise_context.Eip = (DWORD)&w32_raise_in_main; /* X86 code */ + w32_signal_to_raise = sig; + SetThreadContext (w32_main_thread, &raise_context); + + /* Resume main at w32_raise_in_main */ + ret = ResumeThread (w32_main_thread); + DEBUGd ("main resumed at w32_raise_in_main with suspend count %d", + ret); + } +} + +void +w32_sigint_init (void) +{ + /* Capture main context */ + w32_main_thread_id = GetCurrentThreadId (); + DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), + GetCurrentProcess (), &w32_main_thread, + 0, FALSE, DUPLICATE_SAME_ACCESS); + + InitializeCriticalSectionAndSpinCount (&w32_thread_setjmp_mutex, 0); +} + +#endif /* #if defined (__WIN32__) && ! defined (_POSIX_VERSION) */ + void octave_jump_to_enclosing_context (void) {