home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ixemul-45.0-src.tgz / tar.out / contrib / ixemul / library / ix_timer.c < prev    next >
C/C++ Source or Header  |  1996-10-01  |  4KB  |  144 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *  Portions Copyright (C) 1994 Rafael W. Luebbert
  5.  *
  6.  *  This library is free software; you can redistribute it and/or
  7.  *  modify it under the terms of the GNU Library General Public
  8.  *  License as published by the Free Software Foundation; either
  9.  *  version 2 of the License, or (at your option) any later version.
  10.  *
  11.  *  This library is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  *  Library General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU Library General Public
  17.  *  License along with this library; if not, write to the Free
  18.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *  $Id: ix_timer.c,v 1.3 1994/06/19 15:13:28 rluebbert Exp $
  21.  *
  22.  *  $Log: ix_timer.c,v $
  23.  *  Revision 1.3  1994/06/19  15:13:28  rluebbert
  24.  *  *** empty log message ***
  25.  *
  26.  *  Revision 1.1  1992/05/14  19:55:40  mwild
  27.  *  Initial revision
  28.  *
  29.  */
  30.  
  31. #define _KERNEL
  32. #include "ixemul.h"
  33. #include "kprintf.h"
  34.  
  35. /*
  36.  * this is the interrupt code that distributes those itimer signals and
  37.  * collects resource information
  38.  */
  39.  
  40. /*
  41.  * For all you "moralists" out there in Amiga land...
  42.  * This code uses exec private information about what the stack frame looks
  43.  * like inside an interrupt. However, this information is used read-only, and
  44.  * it really doesn't matter whether it will be wrong in the future, in that
  45.  * case system-time will be measured in other ways, but so what ? ;-))
  46.  */
  47.  
  48. /*
  49.  * by specifying the function as taking varargs parameter, we force gcc
  50.  * to generate a framepointer...
  51.  */
  52.  
  53. int
  54. ix_timer (char *foobar, ...)
  55. {
  56.   register struct Task    *t_pass    asm ("a1");
  57.   struct Task        *me;
  58.   struct user        *p;
  59.   /* not necessarily "me" */
  60.   struct Task        *current_task = SysBase->ThisTask;
  61.   u_int            current_pc;
  62.   register u_int    a5 asm ("a5");
  63.   u_int            sp;
  64.   struct itimerval    *tim;
  65.  
  66.   me = t_pass;
  67.   p = (struct user *) me->tc_TrapData;
  68.  
  69.   /* find out value of sp on invocation of this function. This is easy,
  70.    * since gcc generates a 
  71.    *   link a5,#..
  72.    * at the beginning. So we find sp with a5+4
  73.    */
  74.   sp = a5 + 4;
  75.  
  76.   tim = p->u_timer;
  77.  
  78.   /* The main work. Decrement the timers, and if they hit zero, generate
  79.    * the approprate signal */
  80.  
  81.   /* real timer counts in real time */
  82.   if (timerisset (&tim->it_value) && !itimerdecr (tim, ITIMER_RESOLUTION))
  83.     _psignal (me, SIGALRM);
  84.  
  85.   /* virtual timer only counts, when current_task == me AND the task is
  86.    * not executing in system time. To get at the current PC, remember (or learn;-))
  87.    * that the stack in an interrupt handler looks like follows:
  88.    *   0(sp)  rts into ExitIntr
  89.    *   4(sp),8(sp),12(sp),16(sp),20(sp),24(sp) -> d0/d1/a0/a1/a5/a6
  90.    *    now the stuff for the correct rte instruction
  91.    *   28(sp) -> SR
  92.    *   30(sp) -> PC <- that's what we're interested in
  93.    */
  94.   /* heuristics for 2.0.. */
  95.   current_pc = *(u_int *)(sp + 46);
  96.  
  97.   if (me == current_task)
  98.     {
  99.       struct timeval *tv;
  100.       int is_user = current_pc >= p->u_start_pc && current_pc < p->u_end_pc;
  101.  
  102.       ++tim;
  103.       if (is_user && timerisset(&tim->it_value) &&
  104.           !itimerdecr (tim, ITIMER_RESOLUTION))
  105.         _psignal (me, SIGVTALRM);
  106.       ++tim;
  107.  
  108.       /* profiling timer, runs while this process is executing, no matter
  109.        * whether in system time or not */
  110.       if (timerisset(&tim->it_value) &&
  111.           !itimerdecr (tim, ITIMER_RESOLUTION))
  112.         _psignal (me, SIGPROF);
  113.  
  114.       /* now that we're done with the timers, if this is our task executing,
  115.        * update it's rusage fields */
  116.       tv = is_user ? &p->u_ru.ru_utime : &p->u_ru.ru_stime;
  117.       tv->tv_usec += ITIMER_RESOLUTION;
  118.       if (tv->tv_usec >= 1000000)
  119.         {
  120.       tv->tv_usec -= 1000000; /* - is much cheaper than % */
  121.       tv->tv_sec++;
  122.         }
  123.     }
  124.  
  125.   switch (ix.ix_flags & ix_profile_method_mask)
  126.   {
  127.     case IX_PROFILE_PROGRAM:
  128.       if (p->u_prof.pr_scale) {
  129.         addupc (current_pc, &p->u_prof, 1);
  130.       }
  131.       break;
  132.     case IX_PROFILE_TASK:
  133.       if (me == current_task && p->u_prof.pr_scale) {
  134.         addupc (p->u_prof_last_pc, &p->u_prof, 1);
  135.       }
  136.       break;
  137.     case IX_PROFILE_ALWAYS:
  138.       if (p->u_prof.pr_scale)
  139.         addupc (p->u_prof_last_pc, &p->u_prof, 1);
  140.       break;
  141.   }
  142.   return 0;
  143. }
  144.