X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FItimer.c;h=50be88dd799a68605bb14085b69b9d21db44e2c2;hb=61ccfec175e1f51b2c89559faf91d9bee0b3b601;hp=2ec3ea97c8e60024eef457b7bb178acbd925357d;hpb=b88636e4adb08964c77467b70858ee5bc6bcf4e5;p=ghc-hetmet.git diff --git a/ghc/rts/Itimer.c b/ghc/rts/Itimer.c index 2ec3ea9..50be88d 100644 --- a/ghc/rts/Itimer.c +++ b/ghc/rts/Itimer.c @@ -1,5 +1,4 @@ /* ----------------------------------------------------------------------------- - * $Id: Itimer.c,v 1.25 2001/11/21 20:55:10 sof Exp $ * * (c) The GHC Team, 1995-1999 * @@ -17,12 +16,9 @@ * Hence, we use the old-fashioned @setitimer@ that just about everyone seems * to support. So much for standards. */ - -/* This is not posix compliant. */ -/* #include "PosixSource.h" */ - #include "Rts.h" #include "RtsFlags.h" +#include "Timer.h" #include "Itimer.h" #include "Proftimer.h" #include "Schedule.h" @@ -39,138 +35,98 @@ # endif # endif -#if HAVE_WINDOWS_H -# include -#endif - -lnat total_ticks = 0; - -/* ticks left before next pre-emptive context switch */ -int ticks_to_ctxt_switch = 0; - -/* ----------------------------------------------------------------------------- - Tick handler - - We use the ticker for time profiling. - - SMP note: this signal could be delivered to *any* thread. We have - to ensure that it doesn't matter which thread actually runs the - signal handler. - -------------------------------------------------------------------------- */ - -static -void -#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER)) -CALLBACK -handle_tick(UINT uID STG_UNUSED, UINT uMsg STG_UNUSED, DWORD dwUser STG_UNUSED, - DWORD dw1 STG_UNUSED, DWORD d STG_UNUSED) -#else -handle_tick(int unused STG_UNUSED) -#endif -{ - total_ticks++; - -#ifdef PROFILING - handleProfTick(); +#ifdef HAVE_SIGNAL_H +# include #endif - if (RtsFlags.ConcFlags.ctxtSwitchTicks > 0) { - ticks_to_ctxt_switch--; - if (ticks_to_ctxt_switch <= 0) { - ticks_to_ctxt_switch = RtsFlags.ConcFlags.ctxtSwitchTicks; - context_switch = 1; /* schedule a context switch */ - } - } -} - - -/* - * Handling timer events under cygwin32 is not done with signal/setitimer. - * Instead of the two steps of first registering a signal handler to handle - * \tr{SIGVTALRM} and then start generating them via @setitimer()@, we use - * the Multimedia API (MM) and its @timeSetEvent@. (Internally, the MM API - * creates a separate thread that will notify the main thread of timer - * expiry). -- SOF 7/96 +/* Major bogosity: + * + * In the threaded RTS, we can't set the virtual timer because the + * thread which has the virtual timer might be sitting waiting for a + * capability, and the virtual timer only ticks in CPU time. * - * 11/98: if the cygwin DLL supports setitimer(), then use it instead. + * So, possible solutions: + * + * (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. + * + * (2) save/restore the virtual timer around excursions into STG land. + * Sounds great, but I tried it and the resolution of the virtual timer + * isn't good enough (on Linux) - most of our excursions fall + * within the timer's resolution and we never make any progress. + * + * (3) have a virtual timer in every OS thread. Might be reasonable, + * because most of the time there is only ever one of these + * threads running, so it approximates a single virtual timer. + * But still quite bogus (and I got crashes when I tried this). + * + * For now, we're using (1), but this needs a better solution. --SDM */ +#ifdef RTS_SUPPORTS_THREADS +#define ITIMER_FLAVOUR ITIMER_REAL +#define ITIMER_SIGNAL SIGALRM +#else +#define ITIMER_FLAVOUR ITIMER_VIRTUAL +#define ITIMER_SIGNAL SIGVTALRM +#endif -#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER)) - -LPTIMECALLBACK vtalrm_cback; - +static int -initialize_virtual_timer(nat ms) +install_vtalrm_handler(TickProc handle_tick) { - /* On Win32 setups that don't have support for - setitimer(), we use the MultiMedia API's timer - support. - - The delivery of ticks isn't free; the performance hit should be checked. - */ - unsigned int delay; - static unsigned int vtalrm_id = 0; - static unsigned int period = -1; - - /* A zero argument value means shutdown. */ - if (ms != 0) { - TIMECAPS tc; - - if ( timeGetDevCaps(&tc, sizeof(TIMECAPS)) == TIMERR_NOERROR) { - period = tc.wPeriodMin; - delay = timeBeginPeriod(period); - if (delay == TIMERR_NOCANDO) { /* error of some sort. */ - return -1; - } - } else { - return -1; - } - - vtalrm_id = - timeSetEvent(ms, /* event every `delay' milliseconds. */ - 1, /* precision is within 1 ms */ - vtalrm_cback, - TIME_CALLBACK_FUNCTION, /* ordinary callback */ - TIME_PERIODIC); - } else { - /* Shutdown the MM timer */ - if ( vtalrm_id != 0 ) { - timeKillEvent(vtalrm_id); - } - if (period > 0) { - timeEndPeriod(period); - } - } + struct sigaction action; + + action.sa_handler = handle_tick; + + sigemptyset(&action.sa_mask); + action.sa_flags = 0; - return 0; + return sigaction(ITIMER_SIGNAL, &action, NULL); } - -#else int -initialize_virtual_timer(nat ms) +startTicker(nat ms, TickProc handle_tick) { # ifndef HAVE_SETITIMER - /* fprintf(stderr, "No virtual timer on this system\n"); */ + /* debugBelch("No virtual timer on this system\n"); */ return -1; # else struct itimerval it; + install_vtalrm_handler(handle_tick); + timestamp = getourtimeofday(); 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_VIRTUAL, &it, NULL)); + return (setitimer(ITIMER_FLAVOUR, &it, NULL)); # endif } -#endif /* !{mingw,cygwin32}_TARGET_OS */ +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 -initialize_virtual_timer(nat ms) +startTicker(nat ms) { struct sigevent se; struct itimerspec it; @@ -179,8 +135,8 @@ initialize_virtual_timer(nat ms) timestamp = getourtimeofday(); se.sigev_notify = SIGEV_SIGNAL; - se.sigev_signo = SIGVTALRM; - se.sigev_value.sival_int = SIGVTALRM; + 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"); } @@ -189,37 +145,38 @@ initialize_virtual_timer(nat ms) it.it_interval = it.it_value; return timer_settime(tid, TIMER_RELTIME, &it, NULL); } -# endif - -#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER)) -int -install_vtalrm_handler(void) -{ - vtalrm_cback = handle_tick; - return 0; -} -#else int -install_vtalrm_handler(void) +stopTicker() { - struct sigaction action; - - action.sa_handler = handle_tick; + struct sigevent se; + struct itimerspec it; + timer_t tid; - sigemptyset(&action.sa_mask); - action.sa_flags = 0; + timestamp = getourtimeofday(); - return sigaction(SIGVTALRM, &action, NULL); + 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, SIGVTALRM); + sigaddset(&signals, ITIMER_SIGNAL); (void) sigprocmask(SIG_BLOCK, &signals, NULL); } @@ -230,7 +187,7 @@ unblock_vtalrm_signal(void) sigset_t signals; sigemptyset(&signals); - sigaddset(&signals, SIGVTALRM); + sigaddset(&signals, ITIMER_SIGNAL); (void) sigprocmask(SIG_UNBLOCK, &signals, NULL); } @@ -239,19 +196,13 @@ unblock_vtalrm_signal(void) /* gettimeofday() takes around 1us on our 500MHz PIII. Since we're * only calling it 50 times/s, it shouldn't have any great impact. */ -#if !defined(mingw32_TARGET_OS) -unsigned int +nat getourtimeofday(void) { struct timeval tv; gettimeofday(&tv, (struct timezone *) NULL); - return (tv.tv_sec * TICK_FREQUENCY + - tv.tv_usec * TICK_FREQUENCY / 1000000); + // cast to nat because nat may be 64 bit when int is only 32 bit + return ((nat)tv.tv_sec * TICK_FREQUENCY + + (nat)tv.tv_usec * TICK_FREQUENCY / 1000000); } -#else -unsigned int -getourtimeofday(void) -{ - return ((unsigned int)GetTickCount() * TICK_FREQUENCY) / 1000; -} -#endif +