Itimer.c 3.89 KB
Newer Older
1
/* -----------------------------------------------------------------------------
sof's avatar
sof committed
2
 * $Id: Itimer.c,v 1.32 2003/02/22 04:51:50 sof 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 20
/*
 * 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.
 */
#include "Rts.h"
sof's avatar
sof committed
21
#if !defined(mingw32_TARGET_OS) /* to the end */
22
#include "RtsFlags.h"
sof's avatar
sof committed
23
#include "Timer.h"
24
#include "Itimer.h"
25
#include "Proftimer.h"
26
#include "Schedule.h"
27 28 29 30 31 32 33 34 35 36 37 38

/* 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
39

40 41 42 43
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif

sof's avatar
sof committed
44 45 46 47 48 49 50 51 52 53 54 55 56
static
int
install_vtalrm_handler(void)
{
    struct sigaction action;

    action.sa_handler = handle_tick;

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

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

sof's avatar
sof committed
58
int
sof's avatar
sof committed
59
startTicker(nat ms)
60 61
{
# ifndef HAVE_SETITIMER
andy's avatar
andy committed
62
  /*    fprintf(stderr, "No virtual timer on this system\n"); */
63 64 65 66
    return -1;
# else
    struct itimerval it;

sof's avatar
sof committed
67
    install_vtalrm_handler();
sof's avatar
sof committed
68

69 70
    timestamp = getourtimeofday();

71 72 73 74 75 76 77
    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
78
int
sof's avatar
sof committed
79
stopTicker()
sof's avatar
sof committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93
{
# 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
}

94 95
# if 0
/* This is a potential POSIX version */
sof's avatar
sof committed
96
int
sof's avatar
sof committed
97
startTicker(nat ms)
98 99 100 101 102
{
    struct sigevent se;
    struct itimerspec it;
    timer_t tid;

103 104
    timestamp = getourtimeofday();

105 106 107 108
    se.sigev_notify = SIGEV_SIGNAL;
    se.sigev_signo = SIGVTALRM;
    se.sigev_value.sival_int = SIGVTALRM;
    if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
109
	barf("can't create virtual timer");
110 111 112 113
    }
    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;
sof's avatar
sof committed
114
    return timer_settime(tid, TIMER_RELTIME, &it, NULL);
115 116
}

sof's avatar
sof committed
117
int
sof's avatar
sof committed
118
stopTicker()
sof's avatar
sof committed
119
{
sof's avatar
sof committed
120 121 122
    struct sigevent se;
    struct itimerspec it;
    timer_t tid;
123

sof's avatar
sof committed
124
    timestamp = getourtimeofday();
125

sof's avatar
sof committed
126 127 128 129 130 131 132 133 134 135
    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);
136
}
sof's avatar
sof committed
137 138
# endif

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
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);
}
andy's avatar
andy committed
160

161 162 163
/* gettimeofday() takes around 1us on our 500MHz PIII.  Since we're
 * only calling it 50 times/s, it shouldn't have any great impact.
 */
andy's avatar
andy committed
164 165 166 167 168
unsigned int 
getourtimeofday(void)
{
  struct timeval tv;
  gettimeofday(&tv, (struct timezone *) NULL);
169 170
  return (tv.tv_sec * TICK_FREQUENCY +
	  tv.tv_usec * TICK_FREQUENCY / 1000000);
andy's avatar
andy committed
171
}
sof's avatar
sof committed
172 173

#endif /* !mingw32_TARGET_OS */