Commit e30aca19 authored by Simon Marlow's avatar Simon Marlow
Browse files

Use timer_create() for the interval timer, if available

This lets the threaded RTS use SIGVTALRM rather than SIGALRM for its
interval timer signal, so the threaded and non-threaded RTS are
compatible.  It unfortunately doesn't completely fix #850/#1156, for
that we really have to use a restartable sleep instead of usleep().

Also I cleaned up the timer API a little: instead of returning an
error value that ultimately gets ignored, we now report errors from
system calls and exit.
parent 090bff7e
......@@ -1196,7 +1196,7 @@ AC_COMPILE_IFELSE(
dnl ** check for librt
AC_CHECK_LIB(rt, clock_gettime)
AC_CHECK_FUNCS(clock_gettime)
AC_CHECK_FUNCS(clock_gettime timer_create timer_settime)
dnl ** check for Apple's "interesting" long double compatibility scheme
AC_MSG_CHECKING(for printf\$LDBLStub)
......
......@@ -9,7 +9,7 @@
#ifndef TICKER_H
#define TICKER_H
extern int startTicker( nat ms, TickProc handle_tick );
extern int stopTicker ( void );
extern void startTicker( nat ms, TickProc handle_tick );
extern void stopTicker ( void );
#endif /* TICKER_H */
......@@ -83,18 +83,18 @@ handle_tick(int unused STG_UNUSED)
#endif
}
int
void
startTimer(void)
{
#ifdef PROFILING
initProfTimer();
#endif
return startTicker(RtsFlags.MiscFlags.tickInterval, handle_tick);
startTicker(RtsFlags.MiscFlags.tickInterval, handle_tick);
}
int
void
stopTimer(void)
{
return stopTicker();
stopTicker();
}
......@@ -11,7 +11,7 @@
typedef void (*TickProc)(int);
extern int startTimer(void);
extern int stopTimer(void);
extern void startTimer(void);
extern void stopTimer(void);
#endif /* TIMER_H */
......@@ -52,9 +52,7 @@
*
* (1) tick in realtime. Not very good, because this ticker is used for
* profiling, and this will give us unreliable time profiling
* results. Furthermore, this requires picking a single OS thread
* to be the timekeeper, which is a bad idea because the thread in
* question might just be making a temporary call into Haskell land.
* results.
*
* (2) save/restore the virtual timer around excursions into STG land.
* Sounds great, but I tried it and the resolution of the virtual timer
......@@ -68,16 +66,42 @@
*
* For now, we're using (1), but this needs a better solution. --SDM
*/
#ifdef THREADED_RTS
#define ITIMER_FLAVOUR ITIMER_REAL
#define ITIMER_SIGNAL SIGALRM
#if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
# define USE_TIMER_CREATE
# define ITIMER_SIGNAL SIGVTALRM
# ifdef THREADED_RTS
# define TIMER_FLAVOUR CLOCK_REALTIME
# else
# define TIMER_FLAVOUR CLOCK_PROCESS_CPUTIME_ID
# endif
#elif defined(HAVE_SETITIMER)
# define USE_ITIMER
# ifdef THREADED_RTS
// Oh dear, we have to use SIGALRM if there's no timer_create and
// we're using the THREADED_RTS. This leads to problems, see bug #850.
# define ITIMER_SIGNAL SIGALRM
# define ITIMER_FLAVOUR ITIMER_REAL
# else
# define ITIMER_SIGNAL SIGVTALRM
# define ITIMER_FLAVOUR ITIMER_VIRTUAL
# endif
#else
#define ITIMER_FLAVOUR ITIMER_VIRTUAL
#define ITIMER_SIGNAL SIGVTALRM
# error No way to set an interval timer.
#endif
#if defined(USE_TIMER_CREATE)
timer_t timer;
#endif
static
int
void
install_vtalrm_handler(TickProc handle_tick)
{
struct sigaction action;
......@@ -98,95 +122,86 @@ install_vtalrm_handler(TickProc handle_tick)
action.sa_flags = 0;
#endif
return sigaction(ITIMER_SIGNAL, &action, NULL);
if (sigaction(ITIMER_SIGNAL, &action, NULL) == -1) {
sysErrorBelch("sigaction");
stg_exit(EXIT_FAILURE);
}
}
int
void
startTicker(nat ms, TickProc handle_tick)
{
# ifndef HAVE_SETITIMER
/* debugBelch("No virtual timer on this system\n"); */
return -1;
# else
struct itimerval it;
install_vtalrm_handler(handle_tick);
#if !defined(THREADED_RTS)
timestamp = getourtimeofday();
#endif
it.it_value.tv_sec = ms / 1000;
it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
it.it_interval = it.it_value;
return (setitimer(ITIMER_FLAVOUR, &it, NULL));
# endif
}
int
stopTicker()
{
# ifndef HAVE_SETITIMER
/* debugBelch("No virtual timer on this system\n"); */
return -1;
# else
struct itimerval it;
it.it_value.tv_sec = 0;
it.it_value.tv_usec = 0;
it.it_interval = it.it_value;
return (setitimer(ITIMER_FLAVOUR, &it, NULL));
# endif
}
# if 0
/* This is a potential POSIX version */
int
startTicker(nat ms)
{
struct sigevent se;
struct itimerspec it;
timer_t tid;
#if !defined(THREADED_RTS)
timestamp = getourtimeofday();
#endif
se.sigev_notify = SIGEV_SIGNAL;
se.sigev_signo = ITIMER_SIGNAL;
se.sigev_value.sival_int = ITIMER_SIGNAL;
if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
barf("can't create virtual timer");
#if defined(USE_TIMER_CREATE)
{
struct itimerspec it;
struct sigevent ev;
ev.sigev_notify = SIGEV_SIGNAL;
ev.sigev_signo = ITIMER_SIGNAL;
it.it_value.tv_sec = ms / 1000;
it.it_value.tv_nsec = (ms % 1000) * 1000000;
it.it_interval = it.it_value;
if (timer_create(TIMER_FLAVOUR, &ev, &timer) != 0) {
sysErrorBelch("timer_create");
stg_exit(EXIT_FAILURE);
}
if (timer_settime(timer, 0, &it, NULL) != 0) {
sysErrorBelch("timer_settime");
stg_exit(EXIT_FAILURE);
}
}
it.it_value.tv_sec = ms / 1000;
it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
it.it_interval = it.it_value;
return timer_settime(tid, TIMER_RELTIME, &it, NULL);
#else
{
struct itimerval it;
it.it_value.tv_sec = ms / 1000;
it.it_value.tv_usec = (ms % 1000) * 1000;
it.it_interval = it.it_value;
if (setitimer(ITIMER_FLAVOUR, &it, NULL) != 0) {
sysErrorBelch("setitimer");
stg_exit(EXIT_FAILURE);
}
}
#endif
}
int
stopTicker()
void
stopTicker(void)
{
struct sigevent se;
#if defined(USE_TIMER_CREATE)
struct itimerspec it;
timer_t tid;
#if !defined(THREADED_RTS)
timestamp = getourtimeofday();
#endif
it.it_value.tv_sec = 0;
it.it_value.tv_nsec = 0;
it.it_interval = it.it_value;
se.sigev_notify = SIGEV_SIGNAL;
se.sigev_signo = ITIMER_SIGNAL;
se.sigev_value.sival_int = ITIMER_SIGNAL;
if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
barf("can't create virtual timer");
if (timer_settime(timer, 0, &it, NULL) != 0) {
sysErrorBelch("timer_settime");
stg_exit(EXIT_FAILURE);
}
#else
struct itimerval it;
it.it_value.tv_sec = 0;
it.it_value.tv_nsec = 0;
it.it_value.tv_usec = 0;
it.it_interval = it.it_value;
return timer_settime(tid, TIMER_RELTIME, &it, NULL);
if (setitimer(ITIMER_FLAVOUR, &it, NULL) != 0) {
sysErrorBelch("setitimer");
stg_exit(EXIT_FAILURE);
}
#endif
}
# endif
#if 0
/* Currently unused */
......
......@@ -74,7 +74,7 @@ TimerProc(PVOID param)
}
int
void
startTicker(nat ms, TickProc handle_tick)
{
unsigned threadId;
......@@ -95,10 +95,14 @@ startTicker(nat ms, TickProc handle_tick)
(LPVOID)ms,
0,
&threadId);
return (tickThread != 0);
if (tickThread == 0) {
sysErrorBelch("_beginthreadex");
stg_exit(EXIT_FAILURE);
}
}
int
void
stopTicker(void)
{
// We must wait for the ticker thread to terminate, since if we
......@@ -125,5 +129,4 @@ stopTicker(void)
TerminateThread(tickThread, 0);
}
}
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment