Mail Archives: djgpp-workers/1998/12/27/09:56:58
Please try the version of itimer.c attached below. It is NOT TESTED (I
only had enough time to have a good look at the source), so it might not
work correctly, or I might be totally wrong with my conclusions. But I
would at least expect it to solve the problem of calling the profile-
gathering code only once.
Even if this version does work better, I still have several potential
problems in the original v2.02 source to explore. So please feel free to
contribute to this effort by digging some more under the hood on your own
(I won't be able to get back on line until Tuesday).
----------------------------------------------------------------------
/* Copyright (C) 1995 Charles Sandmann (sandmann AT clio DOT rice DOT edu)
setitimer implmentation - used for profiling and alarm
BUGS: ONLY ONE AT A TIME, first pass code
This software may be freely distributed, no warranty.
Changed to work with SIGALRM & SIGPROF by Tom Demmer.
Gotchas:
- It relies on uclock(), which does not work under Windows 95.
- It screws up debuggers for reasons I cannot figure out.
- Both is true for the old version, too.
*/
#include <libc/stubs.h>
#include <sys/time.h>
#include <errno.h>
#include <dpmi.h>
#include <signal.h>
#include <go32.h>
static uclock_t r_exp, r_rel, /* When REAL expires & reload value */
p_exp, p_rel; /* When PROF expires & reload value */
static uclock_t u_now;
int
getitimer(int which, struct itimerval *value)
{
uclock_t rel;
u_now = uclock();
if (which == ITIMER_REAL)
{
if (r_exp)
{
u_now = r_exp - uclock();
rel = r_rel;
}
else
r_exp = rel = 0;
}
else if (which == ITIMER_PROF)
{
if (p_exp)
{
u_now = p_exp - uclock();
rel = p_rel;
}
else
u_now = rel = 0;
}
else
{
errno = EINVAL;
return -1;
}
value->it_value.tv_sec = u_now / UCLOCKS_PER_SEC;
value->it_value.tv_usec= (u_now - value->it_value.tv_sec*3433)/4096;
value->it_interval.tv_sec = rel / UCLOCKS_PER_SEC;
value->it_interval.tv_usec= (u_now - value->it_interval.tv_sec*3433)/4096;
return 0;
}
extern unsigned __djgpp_timer_countdown;
extern __dpmi_paddr __djgpp_old_timer;
extern int __djgpp_timer_hdlr;
static char timer_on = 0;
/* Set back IRQ2 handler to default values and disable own signal
handler */
static void
stop_timer(void)
{
if(!timer_on)
return;
__djgpp_timer_countdown = -1;
__dpmi_set_protected_mode_interrupt_vector(8, &__djgpp_old_timer);
timer_on = 0;
signal(SIGTIMR, SIG_DFL);
}
/* Returns the time to the next event in UCLOCK_PER_SEC u_now must be
set by calling routine. Return 0 if no event pending. */
static inline uclock_t
GetNextEvent(void)
{
if (r_exp && p_exp)
return (r_exp < p_exp ? r_exp - u_now : p_exp - u_now );
else if (r_exp)
return r_exp - u_now;
else if (p_exp)
return p_exp - u_now;
else
return 0;
}
/* Handler for SIGTIMR */
static void
timer_action(int signum)
{
int do_tmr=0,do_prof=0;
uclock_t next;
u_now = uclock();
/* Check the real timer Add 64k, because the next timer interrupt
occurs after that time. A bit less would be sufficient, but what
can you do? */
if (r_exp && (r_exp + 65536L <= u_now) )
{
do_tmr = 1;
if (r_rel)
r_exp += r_rel;
else
r_exp = 0;
}
/* Check profile timer */
if (p_exp && (p_exp + 65536L <= u_now))
{
do_prof = 1;
if (p_rel)
p_exp += p_rel;
else
p_exp = 0;
}
/* Now we have to schedule the next interrupt, if any pending */
if ((next = GetNextEvent()) != 0)
{
next /= 65536L;
__djgpp_timer_countdown = next > 0 ? next : 1 ;
}
else
stop_timer();
if (do_tmr)
raise(SIGALRM);
if (do_prof)
raise(SIGPROF);
}
static void
start_timer(void)
{
uclock_t next;
__dpmi_paddr int8;
next = GetNextEvent();
next /= 65536L;
__djgpp_timer_countdown = next > 0 ? next : 1;
if (timer_on)
return;
timer_on = 1;
signal(SIGTIMR, timer_action);
__dpmi_get_protected_mode_interrupt_vector(8, &__djgpp_old_timer);
int8.selector = _my_cs();
int8.offset32 = (unsigned) &__djgpp_timer_hdlr;
__dpmi_set_protected_mode_interrupt_vector(8, &int8);
}
int
setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
{
uclock_t *t_exp, *t_rel;
if (ovalue)
{
if (getitimer(which,ovalue))
return -1; /* errno already set */
}
else
u_now = uclock();
if ((which != ITIMER_REAL) && ( which != ITIMER_PROF ) )
{
errno = EINVAL;
return -1;
}
t_exp = which == ITIMER_REAL ? &r_exp: &p_exp;
t_rel = which == ITIMER_REAL ? &r_rel: &p_rel;
if ((value->it_value.tv_sec|value->it_value.tv_usec)==0 )
{
/* Disable this timer */
*t_exp = *t_rel = 0;
/* If both stopped, stop timer */
if (( p_exp | r_exp ) == 0 )
{
stop_timer();
return 0;
}
}
/* Rounding errors ?? First multiply and then divide could give
Overflow. */
*t_exp = value-> it_value.tv_sec * UCLOCKS_PER_SEC
+ (value->it_value.tv_usec * 4096) / 3433;
*t_rel = value-> it_interval.tv_sec * UCLOCKS_PER_SEC
+ (value->it_interval.tv_usec * 4096) / 3433;
start_timer();
return 0;
}
- Raw text -