X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FItimer.c;h=bbc87384e0bd648448d35685ecba57c062412f70;hb=dac19c07b199bcce81cd29a8f858af7f97e9a21e;hp=cb7df627ed030c53946f5d86a336e646ac4a6a65;hpb=90a6918a3cb4901ecc64d810a6a4eb54d572c0bf;p=ghc-hetmet.git diff --git a/ghc/rts/Itimer.c b/ghc/rts/Itimer.c index cb7df62..bbc8738 100644 --- a/ghc/rts/Itimer.c +++ b/ghc/rts/Itimer.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Itimer.c,v 1.11 2000/03/20 09:42:49 andy Exp $ + * $Id: Itimer.c,v 1.31 2002/08/16 13:29:06 simonmar Exp $ * * (c) The GHC Team, 1995-1999 * @@ -18,12 +18,13 @@ * to support. So much for standards. */ -#if !defined(_AIX) -# define NON_POSIX_SOURCE -#endif +/* This is not posix compliant. */ +/* #include "PosixSource.h" */ #include "Rts.h" +#include "RtsFlags.h" #include "Itimer.h" +#include "Proftimer.h" #include "Schedule.h" /* As recommended in the autoconf manual */ @@ -42,21 +43,19 @@ # include #endif -lnat total_ticks = 0; -rtsBool do_prof_ticks = rtsFalse; - -static -void -#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER)) -CALLBACK +#ifdef HAVE_SIGNAL_H +# include #endif -handle_tick(int unused STG_UNUSED); + +static lnat total_ticks = 0; + +/* ticks left before next pre-emptive context switch */ +static int ticks_to_ctxt_switch = 0; /* ----------------------------------------------------------------------------- Tick handler - We use the ticker for two things: supporting threadDelay, and time - profiling. + 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 @@ -66,20 +65,27 @@ handle_tick(int unused STG_UNUSED); static void #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER)) + CALLBACK -#endif +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 - if (do_prof_ticks == rtsTrue) { - CCS_TICK(CCCS); - } + handleProfTick(); #endif - /* For threadDelay etc., see Select.c */ - ticks_since_select++; + 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 */ + } + } } @@ -96,66 +102,79 @@ handle_tick(int unused STG_UNUSED) #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER)) -/* - * Sigh - to avoid requiring anyone that wants to build ghc to have - * to augment the Win32 header files that comes with cygwinb20.1, - * include the missing MM API decls here inline. - * - * ToDo: check and remove these once the next version of cygwin is - * released. - */ -#define TIMERR_NOERROR 0 -#define TIMERR_NOCANDO 97 -#define TIME_PERIODIC 1 - -typedef UINT MMRESULT; -typedef void CALLBACK (*TIMECALLBACK) (UINT, UINT, DWORD, DWORD, DWORD); -typedef TIMECALLBACK *LPTIMECALLBACK; -MMRESULT STDCALL timeSetEvent(UINT, UINT, LPTIMECALLBACK, DWORD, UINT); -/* - vtalrm_handler is assigned and set up in Signals.c - - vtalrm_id (defined in Signals.c) holds - the system id for the current timer (used to - later block/kill it.) -*/ -extern nat vtalrm_id; -TIMECALLBACK *vtalrm_cback; - -nat -initialize_virtual_timer(nat ms) +static LPTIMECALLBACK vtalrm_cback; +static unsigned int vtalrm_id = 0; +static unsigned int period = -1; + +int +startVirtTimer(nat ms) { -# ifdef PROFILING /* On Win32 setups that don't have support for setitimer(), we use the MultiMedia API's timer support. - As the delivery of ticks isn't free, we only - enable it if we really needed, i.e., when profiling. - (the RTS now also needs timer ticks to implement - threadDelay in non-profiling mode, but the pure - Win32 port doesn't support that.....yet.) + The delivery of ticks isn't free; the performance hit should be checked. */ - unsigned int delay,vtalrm_id; - - delay = timeBeginPeriod(1); - if (delay == TIMERR_NOCANDO) { /* error of some sort. */ - return delay; + unsigned int delay; + TIMECAPS tc; + + vtalrm_cback = handle_tick; + + 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; } + +#ifdef PROFILING + initProfTimer(); +#endif + vtalrm_id = - timeSetEvent(ms, /* event every `delay' milliseconds. */ - 1, /* precision is within 5 millisecs. */ - (LPTIMECALLBACK)vtalrm_cback, - 0, - TIME_PERIODIC); -# endif + timeSetEvent(ms, /* event every `delay' milliseconds. */ + 1, /* precision is within 1 ms */ + vtalrm_cback, + TIME_CALLBACK_FUNCTION, /* ordinary callback */ + TIME_PERIODIC); + + return 0; +} + +int +stopVirtTimer() +{ + /* Shutdown the MM timer */ + if ( vtalrm_id != 0 ) { + timeKillEvent(vtalrm_id); + } + if (period > 0) { + timeEndPeriod(period); + } + return 0; } #else +static +int +install_vtalrm_handler(void) +{ + struct sigaction action; -nat -initialize_virtual_timer(nat ms) + action.sa_handler = handle_tick; + + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + + return sigaction(SIGVTALRM, &action, NULL); +} + +int +startVirtTimer(nat ms) { # ifndef HAVE_SETITIMER /* fprintf(stderr, "No virtual timer on this system\n"); */ @@ -163,6 +182,14 @@ initialize_virtual_timer(nat ms) # else struct itimerval it; + install_vtalrm_handler(); + + timestamp = getourtimeofday(); + +#ifdef PROFILING + initProfTimer(); +#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; @@ -170,17 +197,39 @@ initialize_virtual_timer(nat ms) # endif } -#endif /* !cygwin32_TARGET_OS */ +int +stopVirtTimer() +{ +# ifndef HAVE_SETITIMER + /* fprintf(stderr, "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_VIRTUAL, &it, NULL)); +# endif +} + +#endif /* !{mingw,cygwin32}_TARGET_OS */ # if 0 /* This is a potential POSIX version */ -nat -initialize_virtual_timer(nat ms) +int +startVirtTimer(nat ms) { struct sigevent se; struct itimerspec it; timer_t tid; + timestamp = getourtimeofday(); + +#ifdef PROFILING + initProfTimer(); +#endif + se.sigev_notify = SIGEV_SIGNAL; se.sigev_signo = SIGVTALRM; se.sigev_value.sival_int = SIGVTALRM; @@ -190,32 +239,34 @@ initialize_virtual_timer(nat ms) 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; - timer_settime(tid, TIMER_RELTIME, &it, NULL); + 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) +stopVirtTimer() { - vtalrm_cback = handle_tick; - return 0; -} - -#else -int -install_vtalrm_handler(void) -{ - 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 = SIGVTALRM; + se.sigev_value.sival_int = SIGVTALRM; + 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 defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER)) +#else void block_vtalrm_signal(void) { @@ -239,10 +290,22 @@ unblock_vtalrm_signal(void) } #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. + */ +#if !defined(mingw32_TARGET_OS) unsigned int getourtimeofday(void) { struct timeval tv; gettimeofday(&tv, (struct timezone *) NULL); - return (tv.tv_sec * 1000000 + tv.tv_usec); + return (tv.tv_sec * TICK_FREQUENCY + + tv.tv_usec * TICK_FREQUENCY / 1000000); +} +#else +unsigned int +getourtimeofday(void) +{ + return ((unsigned int)GetTickCount() * TICK_FREQUENCY) / 1000; } +#endif