diff src/nt.c @ 223:2c611d1463a6 r20-4b10

Import from CVS: tag r20-4b10
author cvs
date Mon, 13 Aug 2007 10:10:54 +0200
parents 78f53ef88e17
children 41f2f0e326e9
line wrap: on
line diff
--- a/src/nt.c	Mon Aug 13 10:10:03 2007 +0200
+++ b/src/nt.c	Mon Aug 13 10:10:54 2007 +0200
@@ -33,10 +33,12 @@
 #include <fcntl.h>
 #include <ctype.h>
 #include <signal.h>
-#include <sys/time.h>
 
 /* must include CRT headers *before* config.h */
 #include "config.h"
+#include "systime.h"
+#include "syssignal.h"
+
 #undef access
 #undef chdir
 #undef chmod
@@ -66,6 +68,7 @@
 #include <pwd.h>
 
 #include <windows.h>
+#include <mmsystem.h>
 
 #ifdef HAVE_SOCKETS	/* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
@@ -555,28 +558,11 @@
 /* Routines that are no-ops on NT but are defined to get Emacs to compile.  */
 
 int 
-sigsetmask (int signal_mask) 
-{ 
-  return 0;
-}
-
-int 
-sigblock (int sig) 
-{ 
-  return 0;
-}
-
-int 
 setpgrp (int pid, int gid) 
 { 
   return 0;
 }
 
-int 
-alarm (int seconds) 
-{ 
-  return 0;
-}
 
 int 
 unrequest_sigio (void) 
@@ -2804,4 +2790,226 @@
 }
 #endif
 
+/*--------------------------------------------------------------------*/
+/* Signal support                                                     */
+/*--------------------------------------------------------------------*/
+
+/* We need MS-defined signal and raise here */
+#undef signal
+#undef raise
+
+#define sigmask(nsig) (1U << nsig)
+
+/* We can support as many signals as fit into word */
+#define SIG_MAX 32
+
+/* Signal handlers. Initial value = 0 = SIG_DFL */
+static void (__cdecl *signal_handlers[SIG_MAX])(int) = {0};
+
+/* Signal block mask: bit set to 1 means blocked */
+unsigned signal_block_mask = 0;
+
+/* Signal pending mask: bit set to 1 means sig is pending */
+unsigned signal_pending_mask = 0;
+
+msw_sighandler msw_sigset (int nsig, msw_sighandler handler)
+{
+  /* We delegate some signals to the system function */
+  if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
+    {
+      signal (nsig, handler);
+      return;
+    }
+
+  if (nsig < 0 || nsig > SIG_MAX)
+    {
+      errno = EINVAL;
+      return;
+    }
+
+  /* Store handler ptr */
+  signal_handlers[nsig] = handler;
+}
+  
+int msw_sighold (int nsig)
+{
+  if (nsig < 0 || nsig > SIG_MAX)
+    return errno = EINVAL;
+
+  signal_block_mask |= sigmask(nsig);
+  return 0;
+}
+
+int msw_sigrelse (int nsig)
+{
+  if (nsig < 0 || nsig > SIG_MAX)
+    return errno = EINVAL;
+
+  signal_block_mask &= ~sigmask(nsig);
+
+  if (signal_pending_mask & sigmask(nsig))
+    msw_raise (nsig);
+
+  return 0;
+}
+
+int msw_sigpause (int nsig)
+{
+  /* This is currently not called, because the only
+     call to sigpause inside XEmacs is with SIGCHLD
+     parameter. Just in case, we put an assert here,
+     so anyone who will add a call to sigpause will
+     be surprised (or surprise someone else...) */
+  assert (0);
+  return 0;
+}
+
+int msw_raise (int nsig)
+{
+  /* We delegate some raises to the system routine */
+  if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
+    return raise (nsig);
+
+  if (nsig < 0 || nsig > SIG_MAX)
+    return errno = EINVAL;
+
+  /* If the signal is blocked, remember to issue later */
+  if (signal_block_mask & sigmask(nsig))
+    {
+      signal_pending_mask |= sigmask(nsig);
+      return 0;
+    }
+
+  if (signal_handlers[nsig] == SIG_IGN)
+    return 0;
+
+  if (signal_handlers[nsig] != SIG_DFL)
+    {
+      (*signal_handlers[nsig])(nsig);
+      return 0;
+    }
+
+  /* Default signal actions */
+  if (nsig == SIGALRM || nsig == SIGPROF)
+    exit (3);
+
+  /* Other signals are ignored by default */
+}
+
+/*--------------------------------------------------------------------*/
+/* Async 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 timer_prec = 10;
+
+/* Last itimevals, 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 timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
+				 DWORD dw1, DWORD dw2)
+{
+  /* Just raise a signal indicated by dwUser parameter */
+  msw_raise (dwUser);
+}
+
+/* Divide time in ms specified by IT by DENOM. Return 1 ms
+   if division results in zero */
+static UINT 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;
+  
+  /* Conver 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 (period (itcurrent, timer_prec));
+      *tid = 0;
+    }
+
+  /* Return old itimerval if requested */
+  if (itold)
+    *itold = *itcurrent;
+
+  *itcurrent = *itnew;
+
+  /* Determine if to start new timer */
+  delay = period (itnew, 1);
+  if (delay)
+    {
+      resolution = period (itnew, 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, timer_proc, sigkind, event_type);
+    }
+
+  return !delay || *tid;
+}
+ 
+int 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;
+}
+
 /* end of nt.c */