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.
This commit is contained in:
Eli Zaretskii 2012-09-30 17:49:05 +02:00
parent 8223b1d233
commit c06c382ae4
11 changed files with 643 additions and 118 deletions

View file

@ -1,3 +1,15 @@
2012-09-30 Eli Zaretskii <eliz@gnu.org>
* 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 <lekktu@gmail.com>
* config.nt: Sync with autogen/config.in.

View file

@ -774,7 +774,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#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

View file

@ -121,7 +121,7 @@ extern char *getenv ();
#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 @@ struct sigaction {
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 @@ struct timespec
#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

View file

@ -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 @@ struct timezone
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 */

View file

@ -1,3 +1,42 @@
2012-09-30 Eli Zaretskii <eliz@gnu.org>
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 <handa@gnu.org>
* coding.c (decode_coding_ccl, encode_coding_ccl): Pay attention

View file

@ -200,8 +200,6 @@ record_backtrace (log_t *log, EMACS_INT count)
/* 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

View file

@ -1528,52 +1528,6 @@ is_unc_volume (const char *filename)
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 @@ void
term_ntproc (int ignored)
{
(void)ignored;
term_timers ();
/* shutdown the socket interface if necessary */
term_winsock ();
@ -6632,6 +6589,8 @@ term_ntproc (int ignored)
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 @@ init_ntproc (int dumping)
/* 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 */
{

View file

@ -142,6 +142,9 @@ extern void syms_of_fontset (void);
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);

View file

@ -79,9 +79,7 @@ extern void w32_menu_display_help (HWND, HMENU, UINT, UINT);
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 @@ unsigned int msh_mousewheel = 0;
#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 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
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 @@ no value of TYPE (always string in the MS Windows case). */)
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)
show_hourglass (struct atimer *timer)
{
if (hourglass_timer)
{
KillTimer (hourglass_hwnd, hourglass_timer);
hourglass_timer = 0;
}
struct frame *f;
if (hourglass_shown_p)
w32_hide_hourglass ();
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 ();
}
/* Timer function of hourglass_timer.
Display an hourglass cursor. Set the hourglass_p flag in display info
/* 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 @@ only be necessary if the default setting causes problems. */);
check_window_system_func = check_w32;
hourglass_timer = 0;
hourglass_hwnd = NULL;
defsubr (&Sx_show_tip);

View file

@ -86,18 +86,23 @@ typedef void (_CALLBACK_ *signal_handler) (int);
/* 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 @@ sys_signal (int sig, signal_handler handler)
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 @@ sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
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

View file

@ -29357,10 +29357,6 @@ init_xdisp (void)
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 @@ start_hourglass (void)
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 @@ cancel_hourglass (void)
hide_hourglass ();
#endif
}
#endif /* ! WINDOWSNT */