Itimer.c 6.06 KB
Newer Older
1
/* -----------------------------------------------------------------------------
andy's avatar
andy committed
2
 * $Id: Itimer.c,v 1.11 2000/03/20 09:42:49 andy Exp $
3
 *
4
 * (c) The GHC Team, 1995-1999
5 6 7 8
 *
 * Interval timer for profiling and pre-emptive scheduling.
 *
 * ---------------------------------------------------------------------------*/
9

10 11 12 13 14 15 16 17 18 19
/*
 * The interval timer is used for profiling and for context switching in the
 * threaded build.  Though POSIX 1003.1b includes a standard interface for
 * such things, no one really seems to be implementing them yet.  Even 
 * Solaris 2.3 only seems to provide support for @CLOCK_REAL@, whereas we're
 * keen on getting access to @CLOCK_VIRTUAL@.
 * 
 * Hence, we use the old-fashioned @setitimer@ that just about everyone seems
 * to support.  So much for standards.
 */
20

21
#if !defined(_AIX)
22
# define NON_POSIX_SOURCE
23
#endif
24

25 26
#include "Rts.h"
#include "Itimer.h"
27
#include "Schedule.h"
28 29 30 31 32 33 34 35 36 37 38 39

/* As recommended in the autoconf manual */
# ifdef TIME_WITH_SYS_TIME
#  include <sys/time.h>
#  include <time.h>
# else
#  ifdef HAVE_SYS_TIME_H
#   include <sys/time.h>
#  else
#   include <time.h>
#  endif
# endif
sof's avatar
sof committed
40 41 42 43

#if HAVE_WINDOWS_H
# include <windows.h>
#endif
sof's avatar
sof committed
44
 
45 46 47
lnat total_ticks = 0;
rtsBool do_prof_ticks = rtsFalse;

sof's avatar
sof committed
48 49 50 51 52 53
static
void
#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
CALLBACK
#endif
handle_tick(int unused STG_UNUSED);
54 55 56 57 58 59

/* -----------------------------------------------------------------------------
   Tick handler

   We use the ticker for two things: supporting threadDelay, and time
   profiling.
60 61 62 63

   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.
64 65
   -------------------------------------------------------------------------- */

sof's avatar
sof committed
66 67 68 69 70
static
void
#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
CALLBACK
#endif
71 72 73 74 75
handle_tick(int unused STG_UNUSED)
{
  total_ticks++;

#ifdef PROFILING
76
  if (do_prof_ticks == rtsTrue) {
77 78 79 80 81 82 83 84 85
    CCS_TICK(CCCS);
  }
#endif

  /* For threadDelay etc., see Select.c */
  ticks_since_select++;
}


86 87 88 89 90 91 92 93 94 95 96
/*
 * 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
 *
 * 11/98: if the cygwin DLL supports setitimer(), then use it instead.
 */

sof's avatar
sof committed
97
#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
sof's avatar
sof committed
98

sof's avatar
sof committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
/* 
 * 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);
sof's avatar
sof committed
115
/*
sof's avatar
sof committed
116
  vtalrm_handler is assigned and set up in Signals.c
sof's avatar
sof committed
117

sof's avatar
sof committed
118
  vtalrm_id (defined in Signals.c) holds
sof's avatar
sof committed
119
  the system id for the current timer (used to 
sof's avatar
sof committed
120
  later block/kill it.)
sof's avatar
sof committed
121
*/
122
extern nat vtalrm_id;
sof's avatar
sof committed
123
TIMECALLBACK *vtalrm_cback;
sof's avatar
sof committed
124
 
125 126
nat
initialize_virtual_timer(nat ms)
sof's avatar
sof committed
127
{
sof's avatar
sof committed
128 129 130 131 132 133 134 135 136 137
# 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.)
sof's avatar
sof committed
138 139 140 141 142 143 144 145 146 147 148 149 150
  */
  unsigned int delay,vtalrm_id;
 
  delay = timeBeginPeriod(1);
  if (delay == TIMERR_NOCANDO) { /* error of some sort. */
     return delay;
  }
  vtalrm_id =
    timeSetEvent(ms,     /* event every `delay' milliseconds. */
 	        1,       /* precision is within 5 millisecs. */
 	        (LPTIMECALLBACK)vtalrm_cback,
 		0,
 		TIME_PERIODIC);
sof's avatar
sof committed
151
# endif
sof's avatar
sof committed
152 153 154 155
  return 0;
}
 
#else
156

157 158
nat
initialize_virtual_timer(nat ms)
159 160
{
# ifndef HAVE_SETITIMER
andy's avatar
andy committed
161
  /*    fprintf(stderr, "No virtual timer on this system\n"); */
162 163 164 165 166 167 168 169 170 171 172
    return -1;
# else
    struct itimerval it;

    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));
# endif
}

sof's avatar
sof committed
173 174
#endif /* !cygwin32_TARGET_OS */

175 176
# if 0
/* This is a potential POSIX version */
177 178
nat
initialize_virtual_timer(nat ms)
179 180 181 182 183 184 185 186 187
{
    struct sigevent se;
    struct itimerspec it;
    timer_t tid;

    se.sigev_notify = SIGEV_SIGNAL;
    se.sigev_signo = SIGVTALRM;
    se.sigev_value.sival_int = SIGVTALRM;
    if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
188
	barf("can't create virtual timer");
189 190 191 192 193 194 195 196
    }
    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);
}
# endif

sof's avatar
sof committed
197 198
#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
int
199
install_vtalrm_handler(void)
sof's avatar
sof committed
200
{
201
  vtalrm_cback = handle_tick;
sof's avatar
sof committed
202 203 204 205
  return 0;
}

#else
206
int
207
install_vtalrm_handler(void)
208 209
{
    struct sigaction action;
210

211
    action.sa_handler = handle_tick;
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;

    return sigaction(SIGVTALRM, &action, NULL);
}

void
block_vtalrm_signal(void)
{
    sigset_t signals;
    
    sigemptyset(&signals);
    sigaddset(&signals, SIGVTALRM);

    (void) sigprocmask(SIG_BLOCK, &signals, NULL);
}

void
unblock_vtalrm_signal(void)
{
    sigset_t signals;
    
    sigemptyset(&signals);
    sigaddset(&signals, SIGVTALRM);

    (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
}
sof's avatar
sof committed
240
#endif
andy's avatar
andy committed
241 242 243 244 245 246 247 248

unsigned int 
getourtimeofday(void)
{
  struct timeval tv;
  gettimeofday(&tv, (struct timezone *) NULL);
  return (tv.tv_sec * 1000000 + tv.tv_usec);
}