Itimer.c 5.82 KB
Newer Older
1
/* -----------------------------------------------------------------------------
2
 * $Id: Itimer.c,v 1.16 2000/08/03 11:28:35 simonmar 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
#include "Rts.h"
26
#include "RtsFlags.h"
27
#include "Itimer.h"
28
#include "Proftimer.h"
29
#include "Schedule.h"
30 31 32 33 34 35 36 37 38 39 40 41

/* 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
42 43 44 45

#if HAVE_WINDOWS_H
# include <windows.h>
#endif
sof's avatar
sof committed
46
 
47 48
lnat total_ticks = 0;

49 50 51
/* ticks left before next pre-emptive context switch */
int ticks_to_ctxt_switch = 0;

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

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

   We use the ticker for two things: supporting threadDelay, and time
   profiling.
64 65 66 67

   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.
68 69
   -------------------------------------------------------------------------- */

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

#ifdef PROFILING
80
  handleProfTick();
81 82 83 84
#endif

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

86 87 88 89 90
  ticks_to_ctxt_switch--;
  if (ticks_to_ctxt_switch <= 0) {
      ticks_to_ctxt_switch = RtsFlags.ConcFlags.ctxtSwitchTicks;
      context_switch = 1;	/* schedule a context switch */
  }
91 92 93
}


94 95 96 97 98 99 100 101 102 103 104
/*
 * 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
105
#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
sof's avatar
sof committed
106 107

/*
sof's avatar
sof committed
108
  vtalrm_handler is assigned and set up in Signals.c
sof's avatar
sof committed
109

sof's avatar
sof committed
110
  vtalrm_id (defined in Signals.c) holds
sof's avatar
sof committed
111
  the system id for the current timer (used to 
sof's avatar
sof committed
112
  later block/kill it.)
sof's avatar
sof committed
113
*/
114
extern nat vtalrm_id;
sof's avatar
sof committed
115
TIMECALLBACK *vtalrm_cback;
sof's avatar
sof committed
116
 
117 118
nat
initialize_virtual_timer(nat ms)
sof's avatar
sof committed
119
{
sof's avatar
sof committed
120 121 122 123 124 125 126 127 128 129
# 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
130 131 132 133 134 135 136 137 138 139 140 141 142
  */
  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
143
# endif
144

sof's avatar
sof committed
145 146 147 148
  return 0;
}
 
#else
149

150 151
nat
initialize_virtual_timer(nat ms)
152 153
{
# ifndef HAVE_SETITIMER
andy's avatar
andy committed
154
  /*    fprintf(stderr, "No virtual timer on this system\n"); */
155 156 157 158 159 160 161 162 163 164 165
    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
166 167
#endif /* !cygwin32_TARGET_OS */

168 169
# if 0
/* This is a potential POSIX version */
170 171
nat
initialize_virtual_timer(nat ms)
172 173 174 175 176 177 178 179 180
{
    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)) {
181
	barf("can't create virtual timer");
182 183 184 185 186 187 188 189
    }
    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
190 191
#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
int
192
install_vtalrm_handler(void)
sof's avatar
sof committed
193
{
194
  vtalrm_cback = handle_tick;
sof's avatar
sof committed
195 196 197 198
  return 0;
}

#else
199
int
200
install_vtalrm_handler(void)
201 202
{
    struct sigaction action;
203

204
    action.sa_handler = handle_tick;
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232

    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
233
#endif
andy's avatar
andy committed
234

rrt's avatar
rrt committed
235
#if !defined(HAVE_SETITIMER) && !defined(mingw32_TARGET_OS)
andy's avatar
andy committed
236 237 238 239 240 241 242
unsigned int 
getourtimeofday(void)
{
  struct timeval tv;
  gettimeofday(&tv, (struct timezone *) NULL);
  return (tv.tv_sec * 1000000 + tv.tv_usec);
}
rrt's avatar
rrt committed
243
#endif