The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/tod.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "../port/error.h"
    7 
    8 /*
    9  * Compute nanosecond epoch time from the fastest ticking clock
   10  * on the system.  Converting the time to nanoseconds requires
   11  * the following formula
   12  *
   13  *      t = (((1000000000<<31)/f)*ticks)>>31
   14  *
   15  *  where
   16  *
   17  *      'f'             is the clock frequency
   18  *      'ticks'         are clock ticks
   19  *
   20  *  to avoid too much calculation in todget(), we calculate
   21  *
   22  *      mult = (1000000000<<32)/f
   23  *
   24  *  each time f is set.  f is normally set by a user level
   25  *  program writing to /dev/fastclock.  mul64fract will then
   26  *  take that fractional multiplier and a 64 bit integer and
   27  *  return the resulting integer product.
   28  *
   29  *  We assume that the cpu's of a multiprocessor are synchronized.
   30  *  This assumption needs to be questioned with each new architecture.
   31  */
   32 
   33 /* frequency of the tod clock */
   34 #define TODFREQ         1000000000ULL
   35 #define MicroFREQ       1000000ULL
   36 
   37 struct {
   38         int     init;           /* true if initialized */
   39         ulong   cnt;
   40         Lock;
   41         uvlong  multiplier;     /* ns = off + (multiplier*ticks)>>31 */
   42         uvlong  divider;        /* ticks = (divider*(ns-off))>>31 */
   43         uvlong  umultiplier;    /* µs = (µmultiplier*ticks)>>31 */
   44         uvlong  udivider;       /* ticks = (µdivider*µs)>>31 */
   45         vlong   hz;             /* frequency of fast clock */
   46         vlong   last;           /* last reading of fast clock */
   47         vlong   off;            /* offset from epoch to last */
   48         vlong   lasttime;       /* last return value from todget */
   49         vlong   delta;  /* add 'delta' each slow clock tick from sstart to send */
   50         ulong   sstart;         /* ... */
   51         ulong   send;           /* ... */
   52 } tod;
   53 
   54 static void todfix(void);
   55 
   56 void
   57 todinit(void)
   58 {
   59         if(tod.init)
   60                 return;
   61         ilock(&tod);
   62         tod.last = fastticks((uvlong *)&tod.hz);
   63         iunlock(&tod);
   64         todsetfreq(tod.hz);
   65         tod.init = 1;
   66         addclock0link(todfix, 100);
   67 }
   68 
   69 /*
   70  *  calculate multiplier
   71  */
   72 void
   73 todsetfreq(vlong f)
   74 {
   75         ilock(&tod);
   76         tod.hz = f;
   77 
   78         /* calculate multiplier for time conversion */
   79         tod.multiplier = mk64fract(TODFREQ, f);
   80         tod.divider = mk64fract(f, TODFREQ) + 1;
   81         tod.umultiplier = mk64fract(MicroFREQ, f);
   82         tod.udivider = mk64fract(f, MicroFREQ) + 1;
   83         iunlock(&tod);
   84 }
   85 
   86 /*
   87  *  Set the time of day struct
   88  */
   89 void
   90 todset(vlong t, vlong delta, int n)
   91 {
   92         if(!tod.init)
   93                 todinit();
   94 
   95         ilock(&tod);
   96         if(t >= 0){
   97                 tod.off = t;
   98                 tod.last = fastticks(nil);
   99                 tod.lasttime = 0;
  100                 tod.delta = 0;
  101                 tod.sstart = tod.send;
  102         } else {
  103                 if(n <= 0)
  104                         n = 1;
  105                 n *= HZ;
  106                 if(delta < 0 && n > -delta)
  107                         n = -delta;
  108                 if(delta > 0 && n > delta)
  109                         n = delta;
  110                 delta = delta/n;
  111                 tod.sstart = MACHP(0)->ticks;
  112                 tod.send = tod.sstart + n;
  113                 tod.delta = delta;
  114         }
  115         iunlock(&tod);
  116 }
  117 
  118 /*
  119  *  get time of day
  120  */
  121 vlong
  122 todget(vlong *ticksp)
  123 {
  124         uvlong x;
  125         vlong ticks, diff;
  126         ulong t;
  127 
  128         if(!tod.init)
  129                 todinit();
  130 
  131         /*
  132          * we don't want time to pass twixt the measuring of fastticks
  133          * and grabbing tod.last.  Also none of the vlongs are atomic so
  134          * we have to look at them inside the lock.
  135          */
  136         ilock(&tod);
  137         tod.cnt++;
  138         ticks = fastticks(nil);
  139 
  140         /* add in correction */
  141         if(tod.sstart != tod.send){
  142                 t = MACHP(0)->ticks;
  143                 if(t >= tod.send)
  144                         t = tod.send;
  145                 tod.off = tod.off + tod.delta*(t - tod.sstart);
  146                 tod.sstart = t;
  147         }
  148 
  149         /* convert to epoch */
  150         diff = ticks - tod.last;
  151         if(diff < 0)
  152                 diff = 0;
  153         mul64fract(&x, diff, tod.multiplier);
  154         x += tod.off;
  155 
  156         /* time can't go backwards */
  157         if(x < tod.lasttime)
  158                 x = tod.lasttime;
  159         else
  160                 tod.lasttime = x;
  161 
  162         iunlock(&tod);
  163 
  164         if(ticksp != nil)
  165                 *ticksp = ticks;
  166 
  167         return x;
  168 }
  169 
  170 /*
  171  *  convert time of day to ticks
  172  */
  173 uvlong
  174 tod2fastticks(vlong ns)
  175 {
  176         uvlong x;
  177 
  178         ilock(&tod);
  179         mul64fract(&x, ns-tod.off, tod.divider);
  180         x += tod.last;
  181         iunlock(&tod);
  182         return x;
  183 }
  184 
  185 /*
  186  *  called regularly to avoid calculation overflows
  187  */
  188 static void
  189 todfix(void)
  190 {
  191         vlong ticks, diff;
  192         uvlong x;
  193 
  194         ticks = fastticks(nil);
  195 
  196         diff = ticks - tod.last;
  197         if(diff > tod.hz){
  198                 ilock(&tod);
  199 
  200                 /* convert to epoch */
  201                 mul64fract(&x, diff, tod.multiplier);
  202 if(x > 30000000000ULL) print("todfix %llud\n", x);
  203                 x += tod.off;
  204 
  205                 /* protect against overflows */
  206                 tod.last = ticks;
  207                 tod.off = x;
  208 
  209                 iunlock(&tod);
  210         }
  211 }
  212 
  213 long
  214 seconds(void)
  215 {
  216         vlong x;
  217         int i;
  218 
  219         x = todget(nil);
  220         x = x/TODFREQ;
  221         i = x;
  222         return i;
  223 }
  224 
  225 uvlong
  226 fastticks2us(uvlong ticks)
  227 {
  228         uvlong res;
  229 
  230         if(!tod.init)
  231                 todinit();
  232         mul64fract(&res, ticks, tod.umultiplier);
  233         return res;
  234 }
  235 
  236 uvlong
  237 us2fastticks(uvlong us)
  238 {
  239         uvlong res;
  240 
  241         if(!tod.init)
  242                 todinit();
  243         mul64fract(&res, us, tod.udivider);
  244         return res;
  245 }
  246 
  247 /*
  248  *  convert milliseconds to fast ticks
  249  */
  250 uvlong
  251 ms2fastticks(ulong ms)
  252 {
  253         if(!tod.init)
  254                 todinit();
  255         return (tod.hz*ms)/1000ULL;
  256 }
  257 
  258 /*
  259  *  convert nanoseconds to fast ticks
  260  */
  261 uvlong
  262 ns2fastticks(uvlong ns)
  263 {
  264         uvlong res;
  265 
  266         if(!tod.init)
  267                 todinit();
  268         mul64fract(&res, ns, tod.divider);
  269         return res;
  270 }
  271 
  272 /*
  273  *  convert fast ticks to ns
  274  */
  275 uvlong
  276 fastticks2ns(uvlong ticks)
  277 {
  278         uvlong res;
  279 
  280         if(!tod.init)
  281                 todinit();
  282         mul64fract(&res, ticks, tod.multiplier);
  283         return res;
  284 }
  285 
  286 /*
  287  * Make a 64 bit fixed point number that has a decimal point
  288  * to the left of the low order 32 bits.  This is used with
  289  * mul64fract for converting twixt nanoseconds and fastticks.
  290  *
  291  *      multiplier = (to<<32)/from
  292  */
  293 uvlong
  294 mk64fract(uvlong to, uvlong from)
  295 {
  296 /*
  297         int shift;
  298 
  299         if(to == 0ULL)
  300                 return 0ULL;
  301 
  302         shift = 0;
  303         while(shift < 32 && to < (1ULL<<(32+24))){
  304                 to <<= 8;
  305                 shift += 8;
  306         }
  307         while(shift < 32 && to < (1ULL<<(32+31))){
  308                 to <<= 1;
  309                 shift += 1;
  310         }
  311 
  312         return (to/from)<<(32-shift);
  313  */
  314         return (to<<32) / from;
  315 }

Cache object: 2d157b833f87b7c4f1d025d9cab6b9f4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.