X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2Fposix%2FItimer.c;h=e46bb12546fb54fa31a8f61d2c23b942eb3cf4e6;hb=cf5905ea24904cf73a041fd7535e8723a668cb9a;hp=0f0b1e977ee769df23979e09527260e8f15c131f;hpb=93db1991b5cacf8357493a2e17fbbfb485f3205b;p=ghc-hetmet.git diff --git a/rts/posix/Itimer.c b/rts/posix/Itimer.c index 0f0b1e9..e46bb12 100644 --- a/rts/posix/Itimer.c +++ b/rts/posix/Itimer.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------------- * - * (c) The GHC Team, 1995-1999 + * (c) The GHC Team, 1995-2007 * * Interval timer for profiling and pre-emptive scheduling. * @@ -16,14 +16,15 @@ * Hence, we use the old-fashioned @setitimer@ that just about everyone seems * to support. So much for standards. */ + +#include "PosixSource.h" #include "Rts.h" -#include "RtsFlags.h" -#include "Timer.h" + #include "Ticker.h" -#include "posix/Itimer.h" +#include "Itimer.h" #include "Proftimer.h" #include "Schedule.h" -#include "posix/Select.h" +#include "Select.h" /* As recommended in the autoconf manual */ # ifdef TIME_WITH_SYS_TIME @@ -41,6 +42,8 @@ # include #endif +#include + /* Major bogosity: * * In the threaded RTS, we can't set the virtual timer because the @@ -51,9 +54,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 @@ -67,16 +68,43 @@ * * 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(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) + +# if defined(THREADED_RTS) || !defined(HAVE_SETITIMER_VIRTUAL) +// 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. +// We also use it if we don't have a virtual timer (trac #2883). +# 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) +static timer_t timer; #endif +static nat itimer_interval = 50; + static -int +void install_vtalrm_handler(TickProc handle_tick) { struct sigaction action; @@ -97,120 +125,109 @@ 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 -startTicker(nat ms, TickProc handle_tick) +void +initTicker (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 -} + itimer_interval = ms; -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 defined(USE_TIMER_CREATE) + { + struct sigevent ev; -# if 0 -/* This is a potential POSIX version */ -int -startTicker(nat ms) -{ - struct sigevent se; - struct itimerspec it; - timer_t tid; + // Keep programs like valgrind happy + memset(&ev, 0, sizeof(ev)); -#if !defined(THREADED_RTS) - timestamp = getourtimeofday(); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = ITIMER_SIGNAL; + + if (timer_create(TIMER_FLAVOUR, &ev, &timer) != 0) { + sysErrorBelch("timer_create"); + stg_exit(EXIT_FAILURE); + } + } #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"); +void +startTicker(void) +{ +#if defined(USE_TIMER_CREATE) + { + struct itimerspec it; + + it.it_value.tv_sec = itimer_interval / 1000; + it.it_value.tv_nsec = (itimer_interval % 1000) * 1000000; + it.it_interval = it.it_value; + + 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 = itimer_interval / 1000; + it.it_value.tv_usec = (itimer_interval % 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 - 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"); - } it.it_value.tv_sec = 0; it.it_value.tv_nsec = 0; it.it_interval = it.it_value; - return timer_settime(tid, TIMER_RELTIME, &it, NULL); -} -# endif -#if 0 -/* Currently unused */ -void -block_vtalrm_signal(void) -{ - sigset_t signals; - - sigemptyset(&signals); - sigaddset(&signals, ITIMER_SIGNAL); + if (timer_settime(timer, 0, &it, NULL) != 0) { + sysErrorBelch("timer_settime"); + stg_exit(EXIT_FAILURE); + } +#else + struct itimerval it; - (void) sigprocmask(SIG_BLOCK, &signals, NULL); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 0; + it.it_interval = it.it_value; + + if (setitimer(ITIMER_FLAVOUR, &it, NULL) != 0) { + sysErrorBelch("setitimer"); + stg_exit(EXIT_FAILURE); + } +#endif } void -unblock_vtalrm_signal(void) +exitTicker (rtsBool wait STG_UNUSED) { - sigset_t signals; - - sigemptyset(&signals); - sigaddset(&signals, ITIMER_SIGNAL); - - (void) sigprocmask(SIG_UNBLOCK, &signals, NULL); -} +#if defined(USE_TIMER_CREATE) + timer_delete(timer); + // ignore errors - we don't really care if it fails. #endif +} /* gettimeofday() takes around 1us on our 500MHz PIII. Since we're * only calling it 50 times/s, it shouldn't have any great impact. @@ -219,8 +236,18 @@ lnat getourtimeofday(void) { struct timeval tv; + nat interval; + interval = RtsFlags.MiscFlags.tickInterval; + if (interval == 0) { interval = 50; } gettimeofday(&tv, (struct timezone *) NULL); - // cast to lnat because nat may be 64 bit when int is only 32 bit - return ((lnat)tv.tv_sec * 1000 / RtsFlags.MiscFlags.tickInterval + - (lnat)tv.tv_usec / (RtsFlags.MiscFlags.tickInterval * 1000)); + + // Avoid overflow when we multiply seconds by 1000. See #2848 + return (lnat)((StgWord64)tv.tv_sec * 1000 / interval + + (StgWord64)tv.tv_usec / (interval * 1000)); +} + +int +rtsTimerSignal(void) +{ + return ITIMER_SIGNAL; }