X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FItimer.c;h=98d8ddb29ee4c8ca2abe8c0e38833a75a6880f5f;hb=dbef766ce79e37a74468a07a93b15ba1f06fe8f8;hp=99811c7a0359dc181d65ca957d9de434cc1880fc;hpb=438596897ebbe25a07e1c82085cfbc5bdb00f09e;p=ghc-hetmet.git diff --git a/ghc/rts/Itimer.c b/ghc/rts/Itimer.c index 99811c7..98d8ddb 100644 --- a/ghc/rts/Itimer.c +++ b/ghc/rts/Itimer.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- - * $Id: Itimer.c,v 1.2 1998/12/02 13:28:27 simonm Exp $ + * $Id: Itimer.c,v 1.27 2001/11/26 12:58:17 simonpj Exp $ * - * (c) The GHC Team, 1995-1998 + * (c) The GHC Team, 1995-1999 * * Interval timer for profiling and pre-emptive scheduling. * @@ -18,12 +18,14 @@ * 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 */ # ifdef TIME_WITH_SYS_TIME @@ -36,7 +38,52 @@ # include # 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(); +#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 @@ -48,55 +95,77 @@ * 11/98: if the cygwin DLL supports setitimer(), then use it instead. */ -#if defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER) +#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER)) -#include /* OK, bring it all in... */ +LPTIMECALLBACK vtalrm_cback; -/* - vtalrm_handler is assigned and set up in - main/Signals.lc. - - vtalrm_id (defined in main/Signals.lc) holds - the system id for the current timer (used to - later block/kill the timer) -*/ -extern nat vtalrm_id; -extern TIMECALLBACK *vtalrm_cback; - -nat +int initialize_virtual_timer(nat ms) { - /* VTALRM is currently not supported by cygwin32, - so we use the Timer support provided by the - MultiMedia API that is part of Win32. The - parameters to timeSetEvent may require some tweaking. + /* 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,vtalrm_id; + unsigned int delay; + static unsigned int vtalrm_id = 0; + static unsigned int period = -1; - delay = timeBeginPeriod(1); - if (delay == TIMERR_NOCANDO) { /* error of some sort. */ - return delay; + /* 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); + } } - vtalrm_id = - timeSetEvent(ms, /* event every `delay' milliseconds. */ - 1, /* precision is within 5 millisecs. */ - (LPTIMECALLBACK)vtalrm_cback, - 0, - TIME_PERIODIC); + +#ifdef PROFILING + initProfTimer(); +#endif + return 0; } #else -nat +int initialize_virtual_timer(nat ms) { # ifndef HAVE_SETITIMER - fprintf(stderr, "No virtual timer on this system\n"); + /* fprintf(stderr, "No virtual timer on this system\n"); */ return -1; # else struct itimerval it; + 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; @@ -104,37 +173,49 @@ initialize_virtual_timer(nat ms) # endif } -#endif /* !cygwin32_TARGET_OS */ +#endif /* !{mingw,cygwin32}_TARGET_OS */ # if 0 /* This is a potential POSIX version */ -nat +int initialize_virtual_timer(nat ms) { struct sigevent se; struct itimerspec it; timer_t tid; + timestamp = getourtimeofday(); + + initProfTimer(); + se.sigev_notify = SIGEV_SIGNAL; se.sigev_signo = SIGVTALRM; se.sigev_value.sival_int = SIGVTALRM; if (timer_create(CLOCK_VIRTUAL, &se, &tid)) { - fprintf(stderr, "Can't create virtual timer.\n"); - EXIT(EXIT_FAILURE); + barf("can't create virtual timer"); } 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) +{ + vtalrm_cback = handle_tick; + return 0; +} + +#else int -install_vtalrm_handler(void (*handler)(int)) +install_vtalrm_handler(void) { struct sigaction action; - action.sa_handler = handler; + action.sa_handler = handle_tick; sigemptyset(&action.sa_mask); action.sa_flags = 0; @@ -163,3 +244,24 @@ unblock_vtalrm_signal(void) (void) sigprocmask(SIG_UNBLOCK, &signals, NULL); } +#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 * TICK_FREQUENCY + + tv.tv_usec * TICK_FREQUENCY / 1000000); +} +#else +unsigned int +getourtimeofday(void) +{ + return ((unsigned int)GetTickCount() * TICK_FREQUENCY) / 1000; +} +#endif