cquit.c

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2003-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <signal.h>
00028 #include <string.h>
00029 
00030 #include "quit.h"
00031 
00032 octave_jmp_buf current_context;
00033 
00034 void
00035 octave_save_current_context (void *save_buf)
00036 {
00037   memcpy (save_buf, current_context, sizeof (octave_jmp_buf));
00038 }
00039 
00040 void
00041 octave_restore_current_context (void *save_buf)
00042 {
00043   memcpy (current_context, save_buf, sizeof (octave_jmp_buf));
00044 }
00045 
00046 #if defined (__WIN32__) && ! defined (_POSIX_VERSION)
00047 
00048 /* FIXME -- eventually remove the debugging */
00049 #if defined (DEBUG)
00050 
00051 #define PRINT_CURRENT_THREAD() printf ("%lx: ", GetCurrentThreadId ())
00052 
00053 #define DEBUGs(s) \
00054   do \
00055     { \
00056       PRINT_CURRENT_THREAD (); \
00057       printf (s "\n"); \
00058       fflush (stdout); \
00059     } \
00060   while (0)
00061 
00062 #define DEBUGd(s, d) \
00063   do \
00064     { \
00065       PRINT_CURRENT_THREAD (); \
00066       printf (s "\n", d); \
00067       fflush (stdout); \
00068     } \
00069   while (0)
00070 
00071 #else
00072 #define DEBUGs(s)
00073 #define DEBUGd(s, d)
00074 #endif
00075 
00076 CRITICAL_SECTION w32_thread_setjmp_mutex;
00077 static CONTEXT w32_signal_context;
00078 static int w32_signal_to_raise = 0;
00079 static DWORD w32_main_thread_id;
00080 static HANDLE w32_main_thread;
00081 static HANDLE w32_restore_thread = NULL;
00082 
00083 int
00084 w32_in_main_thread(void)
00085 {
00086   return (GetCurrentThreadId () == w32_main_thread_id);
00087 }
00088 
00089 static DWORD WINAPI
00090 w32_reset_context (LPVOID v)
00091 {
00092   PCONTEXT context = (PCONTEXT)v;
00093   int ret;
00094 
00095   /* Mutex the setjmp/longjmp */
00096   EnterCriticalSection (&w32_thread_setjmp_mutex);
00097 
00098   DEBUGs ("enter w32_set_context");
00099   SuspendThread (w32_main_thread);
00100   DEBUGs ("main suspended");
00101   if (! SetThreadContext (w32_main_thread, context))
00102     {
00103       fprintf (stderr, "%lx: context failed: ctrl-c won't work\n",
00104                GetCurrentThreadId ());
00105       fflush (stderr);
00106     }
00107   DEBUGs ("context captured (or not)");
00108   ret = ResumeThread (w32_main_thread);
00109   DEBUGd ("main resumed with %d", ret);
00110 
00111   LeaveCriticalSection (&w32_thread_setjmp_mutex);
00112   return 0;
00113 }
00114 
00115 static void
00116 w32_raise_in_main (void)
00117 {
00118   DWORD threadid;
00119 
00120   DEBUGd ("w32_raise_in_main with signal %d", w32_signal_to_raise);
00121   raise (w32_signal_to_raise);
00122   DEBUGd ("w32_raise_in_main signal %d returned a value",
00123           w32_signal_to_raise);
00124 
00125   DEBUGs ("attempting to restore main to pre-signal configuration");
00126   if (w32_restore_thread != NULL) /* Catch leaky threads */
00127     CloseHandle (w32_restore_thread);
00128   w32_restore_thread = CreateThread (NULL, 10000, w32_reset_context,
00129                                      &w32_signal_context, 0, &threadid);
00130   if (w32_restore_thread == NULL)
00131     {
00132       fprintf (stderr, "w32_raise_in_main couldn't create thread\n");
00133       fflush (stderr);
00134     }
00135   else
00136     {
00137       DEBUGs ("waiting to restore raise context");
00138       WaitForSingleObject (w32_restore_thread, INFINITE);
00139       fprintf (stderr, "w32_raise_in_main couldn't restore context\n");
00140       fflush (stderr);
00141     }
00142 }
00143 
00144 void
00145 w32_raise_final (void)
00146 {
00147   CloseHandle (w32_main_thread);
00148   if (w32_restore_thread != NULL) /* Catch leaky threads */
00149     CloseHandle (w32_restore_thread);
00150   w32_main_thread = w32_restore_thread = NULL;
00151 }
00152 
00153 /* Raise the given signal in the main thread.  w32_raise_init ()
00154    must have been called from the main thread already.  */
00155 void
00156 w32_raise (int sig)
00157 {
00158   int ret;
00159 
00160   if (w32_in_main_thread ())
00161     {
00162       /* Called from main thread -- a simple raise () should work.  */
00163       DEBUGd ("raising signal %d within main", signal);
00164       raise (sig);
00165       DEBUGd ("returning from signal %d within main", signal);
00166     }
00167   else
00168     {
00169       /* Called from alternate thread -- call w32_raise_in_main in the
00170          main thread with w32_signal_to_raise set to the signal */
00171       CONTEXT raise_context;
00172       DEBUGd ("raising signal %d from separate thread", signal);
00173 
00174       /* Suspend main and remember the context.  */
00175       SuspendThread (w32_main_thread);
00176       /* X86 code */
00177       w32_signal_context.ContextFlags
00178         = CONTEXT_FULL|CONTEXT_FLOATING_POINT|CONTEXT_DEBUG_REGISTERS;
00179       GetThreadContext (w32_main_thread, &w32_signal_context);
00180 
00181       /* Change the context to w32_raise_in_main.  The
00182          context.Eip=&fn trick for setting the program counter is
00183          courtesy of
00184 
00185            http://fit.c2.com/files/LispPlatform/lisp/clisp-2.28/src/win32aux.d
00186 
00187          Auxiliary functions for CLISP on Win32, Bruno Haible
00188          1997-1999.  */
00189 
00190       memcpy (&raise_context, &w32_signal_context, sizeof (CONTEXT));
00191       raise_context.Eip = (DWORD)&w32_raise_in_main; /* X86 code */
00192       w32_signal_to_raise = sig;
00193       SetThreadContext (w32_main_thread, &raise_context);
00194 
00195       /* Resume main at w32_raise_in_main */
00196       ret = ResumeThread (w32_main_thread);
00197       DEBUGd ("main resumed at w32_raise_in_main with suspend count %d",
00198               ret);
00199     }
00200 }
00201 
00202 void
00203 w32_sigint_init (void)
00204 {
00205   /* Capture main context */
00206   w32_main_thread_id = GetCurrentThreadId ();
00207   DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
00208                    GetCurrentProcess (), &w32_main_thread,
00209                    0, FALSE, DUPLICATE_SAME_ACCESS);
00210 
00211   InitializeCriticalSectionAndSpinCount (&w32_thread_setjmp_mutex, 0);
00212 }
00213 
00214 #endif /* #if defined (__WIN32__) && ! defined (_POSIX_VERSION) */
00215 
00216 void
00217 octave_jump_to_enclosing_context (void)
00218 {
00219 #if defined (OCTAVE_HAVE_SIG_JUMP)
00220   siglongjmp (current_context, 1);
00221 #else
00222   longjmp (current_context, 1);
00223 #endif
00224 }
00225 
00226 /* Allow us to save the signal mask and then restore it to the most
00227    recently saved value.  This is necessary when using the POSIX
00228    signal handling interface on some systems calling longjmp out of
00229    the signal handler to get to the top level on an interrupt doesn't
00230    restore the original signal mask.  Alternatively, we could use
00231    sigsetjmp/siglongjmp, but saving and restoring the signal mask
00232    ourselves works ok and seems simpler just now.  */
00233 
00234 static sigset_t octave_signal_mask;
00235 
00236 void
00237 octave_save_signal_mask (void)
00238 {
00239   sigprocmask (0, 0, &octave_signal_mask);
00240 }
00241 
00242 void
00243 octave_restore_signal_mask (void)
00244 {
00245   sigprocmask (SIG_SETMASK, &octave_signal_mask, 0);
00246 }
00247 
00248 sig_atomic_t octave_interrupt_immediately = 0;
00249 
00250 sig_atomic_t octave_interrupt_state = 0;
00251 
00252 sig_atomic_t octave_exception_state = 0;
00253 
00254 volatile sig_atomic_t octave_signal_caught = 0;
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines