[Top][All Lists]
[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 */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Emacs-diffs] /srv/bzr/emacs/trunk r110287: Support atimers and CPU profiler via profile.c on MS-Windows.,
Eli Zaretskii <=