emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] /srv/bzr/emacs/trunk r110287: Support atimers and CPU prof


From: Eli Zaretskii
Subject: [Emacs-diffs] /srv/bzr/emacs/trunk r110287: Support atimers and CPU profiler via profile.c on MS-Windows.
Date: Sun, 30 Sep 2012 17:49:05 +0200
User-agent: Bazaar (2.5.0)

------------------------------------------------------------
revno: 110287
committer: Eli Zaretskii <address@hidden>
branch nick: trunk
timestamp: Sun 2012-09-30 17:49:05 +0200
message:
  Support atimers and CPU profiler via profile.c on MS-Windows.
  
   src/w32proc.c (sig_mask, crit_sig): New static variables.
   (sys_signal): Support SIGALRM and SIGPROF.
   (sigemptyset, sigaddset, sigfillset, sigprocmask)
   (pthread_sigmask, setpgrp): Moved here from w32.c.  sigaddset,
   sigfillset, and sigprocmask are no longer no-ops.
   (sigismember): New function.
   (struct itimer_data): New definition.
   (ticks_now, real_itimer, prof_itimer, clocks_min, crit_real)
   (crit_prof): New static variables.
   (MAX_SINGLE_SLEEP): New definition.
   (timer_loop, stop_timer_thread, term_timers, init_timers)
   (start_timer_thread, getitimer, setitimer): New functions.
   (alarm): No longer a no-op, calls setitimer.
   src/w32.c (term_ntproc): Call term_timers.
   (init_ntproc): Make sure all signals are unblocked at startup, to
   erase any traces of dumping.  Call init_timers.
   src/w32fns.c (hourglass_timer, HOURGLASS_ID): Remove.
   Windows-specific code to display the hourglass mouse pointer is no
   longer used.
   (w32_wnd_proc): Remove code that handled the WM_TIMER message due
   to hourglass timer expiration.
   (start_hourglass, cancel_hourglass, DEFAULT_HOURGLASS_DELAY):
   Remove, no longer used.
   (w32_note_current_window, show_hourglass, hide_hourglass): New
   functions, in support of hourglass cursor display similar to other
   window systems.
   (syms_of_w32fns): Don't initialize hourglass_timer.
   src/xdisp.c (start_hourglass, cancel_hourglass): Now used on
   WINDOWSNT as well.
   (start_hourglass) [WINDOWSNT]: Call w32_note_current_window.
   src/w32.h (init_timers, term_timers): Add prototypes.
  
   nt/inc/sys/time.h (ITIMER_REAL, ITIMER_PROF): Define.
   (struct itimerval): Define.
   (getitimer, setitimer): Add prototypes.
   nt/inc/ms-w32.h <sigset_t> [_MSVC_VER]: Make the typedef consistent
   with MinGW.
   (SA_RESTART, SIGPROF): Define.
   nt/config.nt (HAVE_SETITIMER): Define to 1.
modified:
  nt/ChangeLog
  nt/config.nt
  nt/inc/ms-w32.h
  nt/inc/sys/time.h
  src/ChangeLog
  src/profiler.c
  src/w32.c
  src/w32.h
  src/w32fns.c
  src/w32proc.c
  src/xdisp.c
=== modified file 'nt/ChangeLog'
--- a/nt/ChangeLog      2012-09-30 12:27:23 +0000
+++ b/nt/ChangeLog      2012-09-30 15:49:05 +0000
@@ -1,3 +1,15 @@
+2012-09-30  Eli Zaretskii  <address@hidden>
+
+       * inc/sys/time.h (ITIMER_REAL, ITIMER_PROF): Define.
+       (struct itimerval): Define.
+       (getitimer, setitimer): Add prototypes.
+
+       * inc/ms-w32.h <sigset_t> [_MSVC_VER]: Make the typedef consistent
+       with MinGW.
+       (SA_RESTART, SIGPROF): Define.
+
+       * config.nt (HAVE_SETITIMER): Define to 1.
+
 2012-09-30  Juanma Barranquero  <address@hidden>
 
        * config.nt: Sync with autogen/config.in.

=== modified file 'nt/config.nt'
--- a/nt/config.nt      2012-09-30 12:27:23 +0000
+++ b/nt/config.nt      2012-09-30 15:49:05 +0000
@@ -774,7 +774,7 @@
 #define HAVE_SENDTO 1
 
 /* Define to 1 if you have the `setitimer' function. */
-#undef HAVE_SETITIMER
+#define HAVE_SETITIMER 1
 
 /* Define to 1 if you have the `setlocale' function. */
 #define HAVE_SETLOCALE 1

=== modified file 'nt/inc/ms-w32.h'
--- a/nt/inc/ms-w32.h   2012-09-23 17:34:30 +0000
+++ b/nt/inc/ms-w32.h   2012-09-30 15:49:05 +0000
@@ -121,7 +121,7 @@
 #include <sys/types.h>
 
 #ifdef _MSC_VER
-typedef unsigned long sigset_t;
+typedef int sigset_t;
 typedef int ssize_t;
 #endif
 
@@ -130,6 +130,7 @@
   void (_CALLBACK_ *sa_handler)(int);
   sigset_t sa_mask;
 };
+#define SA_RESTART      0
 #define SIG_BLOCK       1
 #define SIG_SETMASK     2
 #define SIG_UNBLOCK     3
@@ -293,6 +294,7 @@
 #define SIGPIPE 13              /* Write on pipe with no readers */
 #define SIGALRM 14              /* Alarm */
 #define SIGCHLD 18              /* Death of child */
+#define SIGPROF 19              /* Profiling */
 
 #ifndef NSIG
 #define NSIG 23

=== modified file 'nt/inc/sys/time.h'
--- a/nt/inc/sys/time.h 2012-06-24 17:21:20 +0000
+++ b/nt/inc/sys/time.h 2012-09-30 15:49:05 +0000
@@ -2,7 +2,8 @@
 #define SYS_TIME_H_INCLUDED
 
 /*
- * sys/time.h doesn't exist on NT
+ * sys/time.h either doesn't exist on Windows, or doesn't necessarily
+ * have the below stuff.
  */
 
 struct timeval
@@ -19,6 +20,18 @@
 
 void gettimeofday (struct timeval *, struct timezone *);
 
+#define ITIMER_REAL      0
+#define ITIMER_PROF      1
+
+struct itimerval
+{
+  struct  timeval it_interval; /* timer interval */
+  struct  timeval it_value;    /* current value */
+};
+
+int getitimer (int, struct itimerval *);
+int setitimer (int, struct itimerval *, struct itimerval *);
+
 #endif /* SYS_TIME_H_INCLUDED */
 
 /* end of sys/time.h */

=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2012-09-30 14:44:30 +0000
+++ b/src/ChangeLog     2012-09-30 15:49:05 +0000
@@ -1,3 +1,42 @@
+2012-09-30  Eli Zaretskii  <address@hidden>
+
+       Support atimers and CPU profiler via profile.c on MS-Windows.
+       * w32proc.c (sig_mask, crit_sig): New static variables.
+       (sys_signal): Support SIGALRM and SIGPROF.
+       (sigemptyset, sigaddset, sigfillset, sigprocmask)
+       (pthread_sigmask, setpgrp): Moved here from w32.c.  sigaddset,
+       sigfillset, and sigprocmask are no longer no-ops.
+       (sigismember): New function.
+       (struct itimer_data): New definition.
+       (ticks_now, real_itimer, prof_itimer, clocks_min, crit_real)
+       (crit_prof): New static variables.
+       (MAX_SINGLE_SLEEP): New definition.
+       (timer_loop, stop_timer_thread, term_timers, init_timers)
+       (start_timer_thread, getitimer, setitimer): New functions.
+       (alarm): No longer a no-op, calls setitimer.
+
+       * w32.c (term_ntproc): Call term_timers.
+       (init_ntproc): Make sure all signals are unblocked at startup, to
+       erase any traces of dumping.  Call init_timers.
+
+       * w32fns.c (hourglass_timer, HOURGLASS_ID): Remove.
+       Windows-specific code to display the hourglass mouse pointer is no
+       longer used.
+       (w32_wnd_proc): Remove code that handled the WM_TIMER message due
+       to hourglass timer expiration.
+       (start_hourglass, cancel_hourglass, DEFAULT_HOURGLASS_DELAY):
+       Remove, no longer used.
+       (w32_note_current_window, show_hourglass, hide_hourglass): New
+       functions, in support of hourglass cursor display similar to other
+       window systems.
+       (syms_of_w32fns): Don't initialize hourglass_timer.
+
+       * xdisp.c (start_hourglass, cancel_hourglass): Now used on
+       WINDOWSNT as well.
+       (start_hourglass) [WINDOWSNT]: Call w32_note_current_window.
+
+       * w32.h (init_timers, term_timers): Add prototypes.
+
 2012-09-30  Kenichi Handa  <address@hidden>
 
        * coding.c (decode_coding_ccl, encode_coding_ccl): Pay attention

=== modified file 'src/profiler.c'
--- a/src/profiler.c    2012-09-30 07:26:32 +0000
+++ b/src/profiler.c    2012-09-30 15:49:05 +0000
@@ -200,8 +200,6 @@
 
 /* Sample profiler.  */
 
-/* FIXME: Add support for the CPU profiler in W32.  */
-
 #ifdef PROFILER_CPU_SUPPORT
 
 /* The profiler timer and whether it was properly initialized, if

=== modified file 'src/w32.c'
--- a/src/w32.c 2012-09-25 11:57:30 +0000
+++ b/src/w32.c 2012-09-30 15:49:05 +0000
@@ -1528,52 +1528,6 @@
   return 1;
 }
 
-/* Routines that are no-ops on NT but are defined to get Emacs to compile.  */
-int
-sigemptyset (sigset_t *set)
-{
-  *set = 0;
-  return 0;
-}
-
-int
-sigaddset (sigset_t *set, int signo)
-{
-  return 0;
-}
-
-int
-sigfillset (sigset_t *set)
-{
-  return 0;
-}
-
-int
-sigprocmask (int how, const sigset_t *set, sigset_t *oset)
-{
-  return 0;
-}
-
-int
-pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
-{
-  if (sigprocmask (how, set, oset) == -1)
-    return EINVAL;
-  return 0;
-}
-
-int
-setpgrp (int pid, int gid)
-{
-  return 0;
-}
-
-int
-alarm (int seconds)
-{
-  return 0;
-}
-
 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
 
 LPBYTE
@@ -6623,6 +6577,9 @@
 term_ntproc (int ignored)
 {
   (void)ignored;
+
+  term_timers ();
+
   /* shutdown the socket interface if necessary */
   term_winsock ();
 
@@ -6632,6 +6589,8 @@
 void
 init_ntproc (int dumping)
 {
+  sigset_t initial_mask = 0;
+
   /* Initialize the socket interface now if available and requested by
      the user by defining PRELOAD_WINSOCK; otherwise loading will be
      delayed until open-network-stream is called (w32-has-winsock can
@@ -6708,7 +6667,12 @@
   /* unfortunately, atexit depends on implementation of malloc */
   /* atexit (term_ntproc); */
   if (!dumping)
-    signal (SIGABRT, term_ntproc);
+    {
+      /* Make sure we start with all signals unblocked.  */
+      sigprocmask (SIG_SETMASK, &initial_mask, NULL);
+      signal (SIGABRT, term_ntproc);
+    }
+  init_timers ();
 
   /* determine which drives are fixed, for GetCachedVolumeInformation */
   {

=== modified file 'src/w32.h'
--- a/src/w32.h 2012-09-25 11:57:30 +0000
+++ b/src/w32.h 2012-09-30 15:49:05 +0000
@@ -142,6 +142,9 @@
 extern void syms_of_w32font (void);
 extern void check_windows_init_file (void);
 
+extern void term_timers (void);
+extern void init_timers (void);
+
 extern int _sys_read_ahead (int fd);
 extern int _sys_wait_accept (int fd);
 

=== modified file 'src/w32fns.c'
--- a/src/w32fns.c      2012-09-30 13:43:47 +0000
+++ b/src/w32fns.c      2012-09-30 15:49:05 +0000
@@ -79,9 +79,7 @@
 extern void w32_free_menu_strings (HWND);
 extern const char *map_w32_filename (const char *, const char **);
 
-/* If non-zero, a w32 timer that, when it expires, displays an
-   hourglass cursor on all frames.  */
-static unsigned hourglass_timer = 0;
+/* If non-NULL, a handle to a frame where to display the hourglass cursor.  */
 static HWND hourglass_hwnd = NULL;
 
 #ifndef IDC_HAND
@@ -175,7 +173,6 @@
 #define MOUSE_BUTTON_ID        1
 #define MOUSE_MOVE_ID  2
 #define MENU_FREE_ID 3
-#define HOURGLASS_ID 4
 /* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
    is received.  */
 #define MENU_FREE_DELAY 1000
@@ -3313,12 +3310,6 @@
               menubar_in_use = 0;
            }
        }
-      else if (wParam == hourglass_timer)
-       {
-         KillTimer (hwnd, hourglass_timer);
-         hourglass_timer = 0;
-         w32_show_hourglass (x_window_to_frame (dpyinfo, hwnd));
-       }
       return 0;
 
     case WM_NCACTIVATE:
@@ -5040,66 +5031,50 @@
                                Busy cursor
  ***********************************************************************/
 
-/* Default number of seconds to wait before displaying an hourglass
-   cursor.  Duplicated from xdisp.c, but cannot use the version there
-   due to lack of atimers on w32.  */
-#define DEFAULT_HOURGLASS_DELAY 1
-
-/* Cancel a currently active hourglass timer, and start a new one.  */
-
 void
-start_hourglass (void)
+w32_note_current_window (void)
 {
-  DWORD delay;
-  int secs, msecs = 0;
   struct frame * f = SELECTED_FRAME ();
 
-  /* No cursors on non GUI frames.  */
   if (!FRAME_W32_P (f))
     return;
 
-  cancel_hourglass ();
-
-  if (INTEGERP (Vhourglass_delay)
-      && XINT (Vhourglass_delay) > 0)
-    secs = XFASTINT (Vhourglass_delay);
-  else if (FLOATP (Vhourglass_delay)
-          && XFLOAT_DATA (Vhourglass_delay) > 0)
-    {
-      Lisp_Object tem;
-      tem = Ftruncate (Vhourglass_delay, Qnil);
-      secs = XFASTINT (tem);
-      msecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000;
-    }
-  else
-    secs = DEFAULT_HOURGLASS_DELAY;
-
-  delay = secs * 1000 + msecs;
   hourglass_hwnd = FRAME_W32_WINDOW (f);
-  hourglass_timer = SetTimer (hourglass_hwnd, HOURGLASS_ID, delay, NULL);
-}
-
-
-/* Cancel the hourglass cursor timer if active, hide an hourglass
-   cursor if shown.  */
-
-void
-cancel_hourglass (void)
-{
-  if (hourglass_timer)
-    {
-      KillTimer (hourglass_hwnd, hourglass_timer);
-      hourglass_timer = 0;
-    }
-
-  if (hourglass_shown_p)
-    w32_hide_hourglass ();
-}
-
-
-/* Timer function of hourglass_timer.
-
-   Display an hourglass cursor.  Set the hourglass_p flag in display info
+}
+
+void
+show_hourglass (struct atimer *timer)
+{
+  struct frame *f;
+
+  hourglass_atimer = NULL;
+
+  block_input ();
+  f = x_window_to_frame (&one_w32_display_info,
+                                      hourglass_hwnd);
+
+  if (f)
+    f->output_data.w32->hourglass_p = 0;
+  else
+    f = SELECTED_FRAME ();
+
+  if (!FRAME_W32_P (f))
+    return;
+
+  w32_show_hourglass (f);
+  unblock_input ();
+}
+
+void
+hide_hourglass (void)
+{
+  block_input ();
+  w32_hide_hourglass ();
+  unblock_input ();
+}
+
+
+/* Display an hourglass cursor.  Set the hourglass_p flag in display info
    to indicate that an hourglass cursor is shown.  */
 
 static void
@@ -7123,8 +7098,6 @@
 
   check_window_system_func = check_w32;
 
-
-  hourglass_timer = 0;
   hourglass_hwnd = NULL;
 
   defsubr (&Sx_show_tip);

=== modified file 'src/w32proc.c'
--- a/src/w32proc.c     2012-09-25 11:50:01 +0000
+++ b/src/w32proc.c     2012-09-30 15:49:05 +0000
@@ -86,18 +86,23 @@
 /* Signal handlers...SIG_DFL == 0 so this is initialized correctly.  */
 static signal_handler sig_handlers[NSIG];
 
+static sigset_t sig_mask;
+
+static CRITICAL_SECTION crit_sig;
+
 /* Improve on the CRT 'signal' implementation so that we could record
-   the SIGCHLD handler.  */
+   the SIGCHLD handler and fake interval timers.  */
 signal_handler
 sys_signal (int sig, signal_handler handler)
 {
   signal_handler old;
 
   /* SIGCHLD is needed for supporting subprocesses, see sys_kill
-     below.  All the others are the only ones supported by the MS
-     runtime.  */
+     below.  SIGALRM and SIGPROF are used by setitimer.  All the
+     others are the only ones supported by the MS runtime.  */
   if (!(sig == SIGCHLD || sig == SIGSEGV || sig == SIGILL
-       || sig == SIGFPE || sig == SIGABRT || sig == SIGTERM))
+       || sig == SIGFPE || sig == SIGABRT || sig == SIGTERM
+       || sig == SIGALRM || sig == SIGPROF))
     {
       errno = EINVAL;
       return SIG_ERR;
@@ -111,7 +116,7 @@
   if (!(sig == SIGABRT && old == term_ntproc))
     {
       sig_handlers[sig] = handler;
-      if (sig != SIGCHLD)
+      if (!(sig == SIGCHLD || sig == SIGALRM || sig == SIGPROF))
        signal (sig, handler);
     }
   return old;
@@ -143,6 +148,523 @@
   return retval;
 }
 
+/* Emulate signal sets and blocking of signals used by timers.  */
+
+int
+sigemptyset (sigset_t *set)
+{
+  *set = 0;
+  return 0;
+}
+
+int
+sigaddset (sigset_t *set, int signo)
+{
+  if (!set)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  if (signo < 0 || signo >= NSIG)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  *set |= (1U << signo);
+
+  return 0;
+}
+
+int
+sigfillset (sigset_t *set)
+{
+  if (!set)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  *set = 0xFFFFFFFF;
+  return 0;
+}
+
+int
+sigprocmask (int how, const sigset_t *set, sigset_t *oset)
+{
+  if (!(how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  if (oset)
+    *oset = sig_mask;
+
+  if (!set)
+    return 0;
+
+  switch (how)
+    {
+    case SIG_BLOCK:
+      sig_mask |= *set;
+      break;
+    case SIG_SETMASK:
+      sig_mask = *set;
+      break;
+    case SIG_UNBLOCK:
+      /* FIXME: Catch signals that are blocked and reissue them when
+        they are unblocked.  Important for SIGALRM and SIGPROF only.  */
+      sig_mask &= ~(*set);
+      break;
+    }
+
+  return 0;
+}
+
+int
+pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
+{
+  if (sigprocmask (how, set, oset) == -1)
+    return EINVAL;
+  return 0;
+}
+
+int
+sigismember (const sigset_t *set, int signo)
+{
+  if (signo < 0 || signo >= NSIG)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  if (signo > sizeof (*set) * BITS_PER_CHAR)
+    emacs_abort ();
+
+  return (*set & (1U << signo)) != 0;
+}
+
+int
+setpgrp (int pid, int gid)
+{
+  return 0;
+}
+
+/* Emulations of interval timers.
+
+   Limitations: only ITIMER_REAL and ITIMER_PROF are supported.
+
+   Implementation: a separate thread is started for each timer type,
+   the thread calls the appropriate signal handler when the timer
+   expires, after stopping the thread which installed the timer.  */
+
+/* FIXME: clock_t counts overflow after 49 days, need to handle the
+   wrap-around.  */
+struct itimer_data {
+  clock_t expire;
+  clock_t reload;
+  int terminate;
+  int type;
+  HANDLE caller_thread;
+  HANDLE timer_thread;
+};
+
+static clock_t ticks_now;
+static struct itimer_data real_itimer, prof_itimer;
+static clock_t clocks_min;
+
+static CRITICAL_SECTION crit_real, crit_prof;
+
+#define MAX_SINGLE_SLEEP 30
+
+static DWORD WINAPI
+timer_loop (LPVOID arg)
+{
+  struct itimer_data *itimer = (struct itimer_data *)arg;
+  int which = itimer->type;
+  int sig = (which == ITIMER_REAL) ? SIGALRM : SIGPROF;
+  CRITICAL_SECTION *crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
+  const DWORD max_sleep = MAX_SINGLE_SLEEP * 1000 / CLOCKS_PER_SEC;
+  int new_count = 0;
+
+  while (1)
+    {
+      DWORD sleep_time;
+      signal_handler handler;
+      clock_t now, expire, reload;
+
+      /* Load new values if requested by setitimer.  */
+      EnterCriticalSection (crit);
+      expire = itimer->expire;
+      reload = itimer->reload;
+      LeaveCriticalSection (crit);
+      if (itimer->terminate)
+       return 0;
+
+      if (itimer->expire == 0)
+       {
+         /* We are idle.  */
+         Sleep (max_sleep);
+         continue;
+       }
+
+      expire = itimer->expire;
+      if (expire > (now = clock ()))
+       sleep_time = expire - now;
+      else
+       sleep_time = 0;
+      /* Don't sleep too long at a time, to be able to see the
+        termination flag without too long a delay.  */
+      while (sleep_time > max_sleep)
+       {
+         if (itimer->terminate)
+           return 0;
+         Sleep (max_sleep);
+         expire = itimer->expire;
+         sleep_time = (expire > (now = clock ())) ? expire - now : 0;
+       }
+      if (itimer->terminate)
+       return 0;
+      if (sleep_time > 0)
+       {
+         Sleep (sleep_time * 1000 / CLOCKS_PER_SEC);
+         /* Always sleep past the expiration time, to make sure we
+            never call the handler _before_ the expiration time,
+            always slightly after it.  Sleep(0) relinquishes the rest
+            of the scheduled slot, so that we let other threads
+            work.  */
+         while (clock () < expire)
+           Sleep (0);
+       }
+
+      if (itimer->expire == 0)
+       continue;
+
+      /* Time's up.  */
+      handler = sig_handlers[sig];
+      if (!(handler == SIG_DFL || handler == SIG_IGN || handler == SIG_ERR)
+         /* FIXME: Don't ignore masked signals.  Instead, record that
+            they happened and reissue them when the signal is
+            unblocked.  */
+         && !sigismember (&sig_mask, sig)
+         /* Simulate masking of SIGALRM and SIGPROF when processing
+            fatal signals.  */
+         && !fatal_error_in_progress
+         && itimer->caller_thread)
+       {
+         /* Simulate a signal delivered to the thread which installed
+            the timer, by suspending that thread while the handler
+            runs.  */
+         DWORD result = SuspendThread (itimer->caller_thread);
+
+         if (result == (DWORD)-1)
+           {
+             DebPrint (("Thread %d exiting with status 2\n", which));
+             return 2;
+           }
+         handler (sig);
+         ResumeThread (itimer->caller_thread);
+       }
+
+      if (itimer->expire == 0)
+       continue;
+
+      /* Update expiration time and loop.  */
+      EnterCriticalSection (crit);
+      expire = itimer->expire;
+      reload = itimer->reload;
+      if (reload > 0)
+       {
+         now = clock ();
+         if (expire <= now)
+           {
+             clock_t lag = now - expire;
+
+             /* If we missed some opportunities (presumably while
+                sleeping or while the signal handler ran), skip
+                them.  */
+             if (lag > reload)
+               expire = now - (lag % reload);
+
+             expire += reload;
+           }
+       }
+      else
+       expire = 0;     /* become idle */
+      itimer->expire = expire;
+      LeaveCriticalSection (crit);
+    }
+  return 0;
+}
+
+static void
+stop_timer_thread (int which)
+{
+  struct itimer_data *itimer =
+    (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
+  int i;
+  DWORD exit_code = 255;
+  BOOL status, err;
+
+  /* Signal the thread that it should terminate.  */
+  itimer->terminate = 1;
+
+  if (itimer->timer_thread == NULL)
+    return;
+
+  /* Wait for the timer thread to terminate voluntarily, then kill it
+     if it doesn't.  This loop waits twice more than the maximum
+     amount of time a timer thread sleeps, see above.  */
+  for (i = 0; i < MAX_SINGLE_SLEEP / 5; i++)
+    {
+      if (!((status = GetExitCodeThread (itimer->timer_thread, &exit_code))
+           && exit_code == STILL_ACTIVE))
+       break;
+      Sleep (10);
+    }
+  if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE)
+      || exit_code == STILL_ACTIVE)
+    {
+      if (!(status == FALSE && err == ERROR_INVALID_HANDLE))
+       TerminateThread (itimer->timer_thread, 0);
+    }
+
+  /* Clean up.  */
+  CloseHandle (itimer->timer_thread);
+  itimer->timer_thread = NULL;
+  if (itimer->caller_thread)
+    {
+      CloseHandle (itimer->caller_thread);
+      itimer->caller_thread = NULL;
+    }
+}
+
+/* This is called at shutdown time from term_ntproc.  */
+void
+term_timers (void)
+{
+  if (real_itimer.timer_thread)
+    stop_timer_thread (ITIMER_REAL);
+  if (prof_itimer.timer_thread)
+    stop_timer_thread (ITIMER_PROF);
+
+  DeleteCriticalSection (&crit_real);
+  DeleteCriticalSection (&crit_prof);
+  DeleteCriticalSection (&crit_sig);
+}
+
+/* This is called at initialization time from init_ntproc.  */
+void
+init_timers (void)
+{
+  /* Make sure we start with zeroed out itimer structures, since
+     dumping may have left there traces of threads long dead.  */
+  memset (&real_itimer, 0, sizeof real_itimer);
+  memset (&prof_itimer, 0, sizeof prof_itimer);
+
+  InitializeCriticalSection (&crit_real);
+  InitializeCriticalSection (&crit_prof);
+  InitializeCriticalSection (&crit_sig);
+}
+
+static int
+start_timer_thread (int which)
+{
+  DWORD exit_code;
+  struct itimer_data *itimer =
+    (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
+
+  if (itimer->timer_thread
+      && GetExitCodeThread (itimer->timer_thread, &exit_code)
+      && exit_code == STILL_ACTIVE)
+    return 0;
+
+  /* Start a new thread.  */
+  if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
+                       GetCurrentProcess (), &itimer->caller_thread, 0,
+                       FALSE, DUPLICATE_SAME_ACCESS))
+    {
+      errno = ESRCH;
+      return -1;
+    }
+
+  itimer->terminate = 0;
+  itimer->type = which;
+  /* Request that no more than 64KB of stack be reserved for this
+     thread, to avoid reserving too much memory, which would get in
+     the way of threads we start to wait for subprocesses.  See also
+     new_child below.  */
+  itimer->timer_thread = CreateThread (NULL, 64 * 1024, timer_loop,
+                                      (void *)itimer, 0x00010000, NULL);
+
+  if (!itimer->timer_thread)
+    {
+      CloseHandle (itimer->caller_thread);
+      itimer->caller_thread = NULL;
+      errno = EAGAIN;
+      return -1;
+    }
+
+  /* This is needed to make sure that the timer thread running for
+     profiling gets CPU as soon as the Sleep call terminates. */
+  if (which == ITIMER_PROF)
+    SetThreadPriority (itimer->caller_thread, THREAD_PRIORITY_TIME_CRITICAL);
+
+  return 0;
+}
+
+/* Most of the code of getitimer and setitimer (but not of their
+   subroutines) was shamelessly stolen from itimer.c in the DJGPP
+   library, see www.delorie.com/djgpp.  */
+int
+getitimer (int which, struct itimerval *value)
+{
+  volatile clock_t *t_expire;
+  volatile clock_t *t_reload;
+  clock_t expire, reload;
+  __int64 usecs;
+  CRITICAL_SECTION *crit;
+
+  ticks_now = clock ();
+
+  if (!value)
+    {
+      errno = EFAULT;
+      return -1;
+    }
+
+  if (which != ITIMER_REAL && which != ITIMER_PROF)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  t_expire = (which == ITIMER_REAL) ? &real_itimer.expire: &prof_itimer.expire;
+  t_reload = (which == ITIMER_REAL) ? &real_itimer.reload: &prof_itimer.reload;
+  crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
+
+  EnterCriticalSection (crit);
+  reload = *t_reload;
+  expire = *t_expire;
+  LeaveCriticalSection (crit);
+
+  if (expire)
+    expire -= ticks_now;
+
+  value->it_value.tv_sec    = expire / CLOCKS_PER_SEC;
+  usecs = (expire % CLOCKS_PER_SEC) * (__int64)1000000 / CLOCKS_PER_SEC;
+  value->it_value.tv_usec   = usecs;
+  value->it_interval.tv_sec = reload / CLOCKS_PER_SEC;
+  usecs = (reload % CLOCKS_PER_SEC) * (__int64)1000000 / CLOCKS_PER_SEC;
+  value->it_interval.tv_usec= usecs;
+
+  return 0;
+}
+
+int
+setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
+{
+  volatile clock_t *t_expire, *t_reload;
+  clock_t expire, reload, expire_old, reload_old;
+  __int64 usecs;
+  CRITICAL_SECTION *crit;
+
+  /* Posix systems expect timer values smaller than the resolution of
+     the system clock be rounded up to the clock resolution.  First
+     time we are called, measure the clock tick resolution.  */
+  if (!clocks_min)
+    {
+      clock_t t1, t2;
+
+      for (t1 = clock (); (t2 = clock ()) == t1; )
+       ;
+      clocks_min = t2 - t1;
+    }
+
+  if (ovalue)
+    {
+      if (getitimer (which, ovalue)) /* also sets ticks_now */
+       return -1;                   /* errno already set */
+    }
+  else
+    ticks_now = clock ();
+
+  if (which != ITIMER_REAL && which != ITIMER_PROF)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  t_expire =
+    (which == ITIMER_REAL) ? &real_itimer.expire : &prof_itimer.expire;
+  t_reload =
+    (which == ITIMER_REAL) ? &real_itimer.reload : &prof_itimer.reload;
+
+  crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
+
+  if (!value
+      || (value->it_value.tv_sec == 0 && value->it_value.tv_usec == 0))
+    {
+      EnterCriticalSection (crit);
+      /* Disable the timer.  */
+      *t_expire = 0;
+      *t_reload = 0;
+      LeaveCriticalSection (crit);
+      return 0;
+    }
+
+  reload = value->it_interval.tv_sec * CLOCKS_PER_SEC;
+
+  usecs = value->it_interval.tv_usec;
+  if (value->it_interval.tv_sec == 0
+      && usecs && usecs * CLOCKS_PER_SEC < clocks_min * 1000000)
+    reload = clocks_min;
+  else
+    {
+      usecs *= CLOCKS_PER_SEC;
+      reload += usecs / 1000000;
+    }
+
+  expire = value->it_value.tv_sec * CLOCKS_PER_SEC;
+  usecs = value->it_value.tv_usec;
+  if (value->it_value.tv_sec == 0
+      && usecs * CLOCKS_PER_SEC < clocks_min * 1000000)
+    expire = clocks_min;
+  else
+    {
+      usecs *= CLOCKS_PER_SEC;
+      expire += usecs / 1000000;
+    }
+
+  expire += ticks_now;
+
+  EnterCriticalSection (crit);
+  expire_old = *t_expire;
+  reload_old = *t_reload;
+  if (!(expire == expire_old && reload == reload_old))
+    {
+      *t_reload = reload;
+      *t_expire = expire;
+    }
+  LeaveCriticalSection (crit);
+
+  return start_timer_thread (which);
+}
+
+int
+alarm (int seconds)
+{
+  struct itimerval new_values;
+
+  new_values.it_value.tv_sec = seconds;
+  new_values.it_value.tv_usec = 0;
+  new_values.it_interval.tv_sec = new_values.it_interval.tv_usec = 0;
+
+  setitimer (ITIMER_REAL, &new_values, NULL);
+
+  return seconds;
+}
+
 /* Defined in <process.h> which conflicts with the local copy */
 #define _P_NOWAIT 1
 

=== modified file 'src/xdisp.c'
--- a/src/xdisp.c       2012-09-29 02:02:34 +0000
+++ b/src/xdisp.c       2012-09-30 15:49:05 +0000
@@ -29357,10 +29357,6 @@
   help_echo_showing_p = 0;
 }
 
-/* Since w32 does not support atimers, it defines its own implementation of
-   the following three functions in w32fns.c.  */
-#ifndef WINDOWSNT
-
 /* Platform-independent portion of hourglass implementation.  */
 
 /* Cancel a currently active hourglass timer, and start a new one.  */
@@ -29383,6 +29379,10 @@
   else
     delay = make_emacs_time (DEFAULT_HOURGLASS_DELAY, 0);
 
+#ifdef WINDOWSNT
+  w32_note_current_window ();
+#endif
+
   hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
                                   show_hourglass, NULL);
 #endif
@@ -29405,4 +29405,3 @@
     hide_hourglass ();
 #endif
 }
-#endif /* ! WINDOWSNT  */


reply via email to

[Prev in Thread] Current Thread [Next in Thread]