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)
 {