diff src/win32.c @ 611:38db05db9cb5

[xemacs-hg @ 2001-06-08 12:21:09 by ben] ------ gc-in-window-procedure fixes ------ alloc.c: Create "post-gc actions", to avoid those dreaded "GC during window procedure" problems. event-msw.c: Abort, clean and simple, when GC in window procedure. We want to flush these puppies out. glyphs-msw.c: Use a post-gc action when destroying subwindows. lisp.h: Declare register_post_gc_action(). scrollbar-msw.c: Use a post-gc action when unshowing scrollbar windows, if in gc. redisplay.c: Add comment about the utter evilness of what's going down here. ------ cygwin setitimer fixes ------ Makefile.in.in: Compile profile.c only when HAVE_SETITIMER. nt.c: Style fixes. nt.c: Move setitimer() emulation to win32.c, because Cygwin needs it too. profile.c: Make sure we don't compile if no setitimer(). Use qxe_setitimer() instead of just plain setitimer(). signal.c: Define qxe_setitimer() as an encapsulation around setitimer() -- call setitimer() directly unless Cygwin or MS Win, in which case we use our simulated version in win32.c. systime.h: Prototype mswindows_setitimer() and qxe_setitimer(). Long comment about "qxe" and the policy regarding encapsulation. win32.c: Move setitimer() emulation here, so Cygwin can use it. Rename a couple of functions and variables to be longer and more descriptive. In setitimer_helper_proc(), send the signal using either mswindows_raise() or (on Cygwin) kill(). If for some reason we are still getting lockups, we'll change the kill() to directly invoke the signal handlers. ------ windows shell fixes ------ callproc.c, ntproc.c: Comments about how these two files must die. callproc.c: On MS Windows, init shell-file-name from SHELL, then COMSPEC, not just COMSPEC. (more correct and closer to FSF.) Don't force a value for SHELL into the environment. (Comments added to explain why not.) nt.c: Don't shove a fabricated SHELL into the environment. See above. ------ misc fixes ------ glyphs-shared.c: Style correction. xemacs-faq.texi: Merge in the rest of Hrvoje's Windows FAQ. Redo section 7 to update current reality and add condensed versions of new changes for 21.1 and 21.4. (Not quite done for 21.4.) Lots more Windows updates. process.el: Need to quote a null argument, too. From Dan Holmsand. startup.el: startup.el: Call MS Windows init function. win32-native.el: Correct comments at top. Correctly handle passing arguments to Cygwin programs and to bash. Fix quoting of zero-length arguments (from Dan Holmsand). Set shell-command-switch based on shell-file-name, which in turn comes from env var SHELL.
author ben
date Fri, 08 Jun 2001 12:21:27 +0000
parents 5fd7ba8b56e7
children 023b83f4e54b
line wrap: on
line diff
--- a/src/win32.c	Thu Jun 07 06:37:25 2001 +0000
+++ b/src/win32.c	Fri Jun 08 12:21:27 2001 +0000
@@ -22,6 +22,9 @@
 #include "lisp.h"
 
 #include "buffer.h"
+
+#include "syssignal.h"
+#include "systime.h"
 #include "syswindows.h"
 
 typedef BOOL (WINAPI *pfSwitchToThread_t) (VOID);
@@ -246,6 +249,141 @@
   return Qnil;
 }
 
+
+/*--------------------------------------------------------------------*/
+/*                               Async timers                         */
+/*--------------------------------------------------------------------*/
+
+/* setitimer() does not exist on native MS Windows, and appears broken
+   on Cygwin (random lockups when BROKEN_SIGIO is defined), so we
+   emulate in both cases by using multimedia timers. */
+
+/* We emulate two timers, one for SIGALRM, another for SIGPROF.
+
+   itimerproc() function has an implementation limitation: it does
+   not allow to set *both* interval and period. If an attempt is
+   made to set both, and then they are unequal, the function
+   asserts.
+
+   Minimum timer resolution on Win32 systems varies, and is greater
+   than or equal than 1 ms. The resolution is always wrapped not to
+   attempt to get below the system defined limit.
+   */
+
+/* Timer precision, denominator of one fraction: for 100 ms
+   interval, request 10 ms precision
+   */
+const int setitimer_helper_timer_prec = 10;
+
+/* Last itimervals, as set by calls to setitimer */
+static struct itimerval it_alarm;
+static struct itimerval it_prof;
+
+/* Timer IDs as returned by MM */
+MMRESULT tid_alarm = 0;
+MMRESULT tid_prof = 0;
+
+static void CALLBACK
+setitimer_helper_proc (UINT uID, UINT uMsg, DWORD dwUser,
+		       DWORD dw1, DWORD dw2)
+{
+  /* Just raise the signal indicated by the dwUser parameter */
+#ifdef CYGWIN
+  kill (getpid (), dwUser);
+#else
+  mswindows_raise (dwUser);
+#endif
+}
+
+/* Divide time in ms specified by IT by DENOM. Return 1 ms
+   if division results in zero */
+static UINT
+setitimer_helper_period (const struct itimerval* it, UINT denom)
+{
+  static TIMECAPS time_caps;
+
+  UINT res;
+  const struct timeval* tv = 
+    (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
+    ? &it->it_interval : &it->it_value;
+  
+  /* Zero means stop timer */
+  if (tv->tv_sec == 0 && tv->tv_usec == 0)
+    return 0;
+  
+  /* Convert to ms and divide by denom */
+  res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
+  
+  /* Converge to minimum timer resolution */
+  if (time_caps.wPeriodMin == 0)
+      timeGetDevCaps (&time_caps, sizeof(time_caps));
+
+  if (res < time_caps.wPeriodMin)
+    res = time_caps.wPeriodMin;
+
+  return res;
+}
+
+static int
+setitimer_helper (const struct itimerval* itnew,
+		  struct itimerval* itold, struct itimerval* itcurrent,
+		  MMRESULT* tid, DWORD sigkind)
+{
+  UINT delay, resolution, event_type;
+
+  /* First stop the old timer */
+  if (*tid)
+    {
+      timeKillEvent (*tid);
+      timeEndPeriod (setitimer_helper_period (itcurrent,
+					      setitimer_helper_timer_prec));
+      *tid = 0;
+    }
+
+  /* Return old itimerval if requested */
+  if (itold)
+    *itold = *itcurrent;
+
+  *itcurrent = *itnew;
+
+  /* Determine if to start new timer */
+  delay = setitimer_helper_period (itnew, 1);
+  if (delay)
+    {
+      resolution = setitimer_helper_period (itnew,
+					    setitimer_helper_timer_prec);
+      event_type = (itnew->it_value.tv_sec == 0 &&
+		    itnew->it_value.tv_usec == 0)
+	? TIME_ONESHOT : TIME_PERIODIC;
+      timeBeginPeriod (resolution);
+      *tid = timeSetEvent (delay, resolution, setitimer_helper_proc, sigkind,
+			   event_type);
+    }
+
+  return !delay || *tid;
+}
+ 
+int
+mswindows_setitimer (int kind, const struct itimerval *itnew,
+		     struct itimerval *itold)
+{
+  /* In this version, both interval and value are allowed
+     only if they are equal. */
+  assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
+	  || (itnew->it_interval.tv_sec == 0 &&
+	      itnew->it_interval.tv_usec == 0)
+	  || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
+	      itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
+
+  if (kind == ITIMER_REAL)
+    return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
+  else if (kind == ITIMER_PROF)
+    return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
+  else
+    return errno = EINVAL;
+}
+
+
 void
 syms_of_win32 (void)
 {