delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1998/12/27/09:56:58

Date: Sun, 27 Dec 1998 16:56:41 +0200 (IST)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
X-Sender: eliz AT is
To: Peter Palotas <blizzar AT hem1 DOT passagen DOT se>,
Robert Hoehne <robert DOT hoehne AT gmx DOT net>
cc: djgpp-workers AT delorie DOT com
Subject: Re: Profiling Problems.
In-Reply-To: <Pine.SUN.3.91.981227140418.434A-100000@is>
Message-ID: <Pine.SUN.3.91.981227164842.3529C-100000@is>
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019