]> git.saurik.com Git - apple/xnu.git/blobdiff - libsyscall/wrappers/__commpage_gettimeofday.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / libsyscall / wrappers / __commpage_gettimeofday.c
index 4967a2f8d375c04069bbea77d2b8522b408f94d0..0ebfc53180a7952e338de559a3fd79a84996c04f 100644 (file)
 #include <sys/time.h>
 #include <mach/mach_time.h>
 #include <machine/cpu_capabilities.h>
+#include <os/overflow.h>
+#include <kern/arithmetic_128.h>
 
 int __commpage_gettimeofday(struct timeval *);
 
 __attribute__((visibility("hidden")))
 int __commpage_gettimeofday_internal(struct timeval *tp, uint64_t *tbr_out);
 
-#if   defined(__x86_64__) || defined(__i386__)
+int
+__commpage_gettimeofday(struct timeval *tp)
+{
+       return __commpage_gettimeofday_internal(tp, NULL);
+}
 
-// XXX: must be kept in sync with __commpage_gettimeofday.s
 int
 __commpage_gettimeofday_internal(struct timeval *tp, uint64_t *tbr_out)
 {
-       volatile uint32_t *gtod_generation_p = _COMM_PAGE_GTOD_GENERATION;
-       volatile uint64_t *gtod_sec_base_p = _COMM_PAGE_GTOD_SEC_BASE;
-       volatile uint64_t *gtod_ns_base_p = _COMM_PAGE_GTOD_NS_BASE;
-
-       uint64_t tbr, gen, tod_secs, tod_nsecs, elapsed;
-       while(1) {
-               gen = *gtod_generation_p;
-               tbr = mach_absolute_time();
-               tod_secs = *gtod_sec_base_p;
-               tod_nsecs = *gtod_ns_base_p;
-               uint64_t gen2 = *gtod_generation_p;
-               if(__builtin_expect(gen, gen2) == gen2)
-                       break;
+       uint64_t now, over;
+       uint64_t delta,frac;
+       uint64_t TimeStamp_tick;
+       uint64_t TimeStamp_sec;
+       uint64_t TimeStamp_frac;
+       uint64_t Tick_scale;
+       uint64_t Ticks_per_sec;
+
+       volatile uint64_t *gtod_TimeStamp_tick_p;
+       volatile uint64_t *gtod_TimeStamp_sec_p;
+       volatile uint64_t *gtod_TimeStamp_frac_p;
+       volatile uint64_t *gtod_Ticks_scale_p;
+       volatile uint64_t *gtod_Ticks_per_sec_p;
+
+       new_commpage_timeofday_data_t *commpage_timeofday_datap;
+
+       commpage_timeofday_datap =  (new_commpage_timeofday_data_t *)_COMM_PAGE_NEWTIMEOFDAY_DATA;
+
+       gtod_TimeStamp_tick_p = &commpage_timeofday_datap->TimeStamp_tick;
+       gtod_TimeStamp_sec_p = &commpage_timeofday_datap->TimeStamp_sec;
+       gtod_TimeStamp_frac_p = &commpage_timeofday_datap->TimeStamp_frac;
+       gtod_Ticks_scale_p = &commpage_timeofday_datap->Ticks_scale;
+       gtod_Ticks_per_sec_p = &commpage_timeofday_datap->Ticks_per_sec;
+
+       do {
+               TimeStamp_tick = *gtod_TimeStamp_tick_p;
+               TimeStamp_sec = *gtod_TimeStamp_sec_p;
+               TimeStamp_frac = *gtod_TimeStamp_frac_p;
+               Tick_scale = *gtod_Ticks_scale_p;
+               Ticks_per_sec = *gtod_Ticks_per_sec_p;
+
+               /*
+                * This call contains an instruction barrier which will ensure that the
+                * second read of the abs time isn't speculated above the reads of the
+                * other values above
+                */
+               now = mach_absolute_time();
+       } while (TimeStamp_tick != *gtod_TimeStamp_tick_p);
+
+       if (TimeStamp_tick == 0)
+               return(1);
+
+       delta = now - TimeStamp_tick;
+
+       /* If more than one second force a syscall */
+       if (delta >= Ticks_per_sec)
+               return(1);
+
+       tp->tv_sec = TimeStamp_sec;
+
+       over = multi_overflow(Tick_scale, delta);
+       if(over){
+               tp->tv_sec += over;
        }
-       if (gen == 0) return KERN_FAILURE;
-       elapsed = tbr - tod_nsecs;
-
-       unsigned long secs;
-       uint32_t nsec;
-#if defined(__x86_64__)
-       secs = elapsed/NSEC_PER_SEC;
-       nsec = elapsed % NSEC_PER_SEC;
-#elif defined(__i386__)
-       uint32_t secs1, secs2;
-       secs1 = elapsed >> 32;
-       secs2 = elapsed;
-       __asm__ (
-         "divl %4"
-         : "=a" (secs), "=d" (nsec)
-         : "0" (secs2), "1" (secs1), "rm" (NSEC_PER_SEC)
-       );
-#endif /* __i386 or __x86_64__ */
-       tp->tv_sec = tod_secs + secs;
-       tp->tv_usec = nsec / NSEC_PER_USEC;
-
-       if (tbr_out) *tbr_out = tbr;
-
-       return KERN_SUCCESS;
-}
 
-#endif
+       /* Sum scale*delta to TimeStamp_frac, if it overflows increment sec */
+       frac = TimeStamp_frac;
+       frac += Tick_scale * delta;
+       if( TimeStamp_frac > frac )
+               tp->tv_sec++;
+
+       /*
+        * Convert frac (64 bit frac of a sec) to usec
+        * usec = frac * USEC_PER_SEC / 2^64
+        */
+       tp->tv_usec = ((uint64_t)1000000 * (uint32_t)(frac >> 32)) >> 32;
+
+       if (tbr_out) {
+               *tbr_out = now;
+       }
+
+       return(0);
+}