+ real_time_sleep (ns, 1000 * 1000 * 1000);
+}
+
+/* Busy-waits for approximately MS milliseconds. Interrupts need
+ not be turned on.
+
+ Busy waiting wastes CPU cycles, and busy waiting with
+ interrupts off for the interval between timer ticks or longer
+ will cause timer ticks to be lost. Thus, use timer_msleep()
+ instead if interrupts are enabled. */
+void
+timer_mdelay (int64_t ms)
+{
+ real_time_delay (ms, 1000);
+}
+
+/* Sleeps for approximately US microseconds. Interrupts need not
+ be turned on.
+
+ Busy waiting wastes CPU cycles, and busy waiting with
+ interrupts off for the interval between timer ticks or longer
+ will cause timer ticks to be lost. Thus, use timer_usleep()
+ instead if interrupts are enabled. */
+void
+timer_udelay (int64_t us)
+{
+ real_time_delay (us, 1000 * 1000);
+}
+
+/* Sleeps execution for approximately NS nanoseconds. Interrupts
+ need not be turned on.
+
+ Busy waiting wastes CPU cycles, and busy waiting with
+ interrupts off for the interval between timer ticks or longer
+ will cause timer ticks to be lost. Thus, use timer_nsleep()
+ instead if interrupts are enabled.*/
+void
+timer_ndelay (int64_t ns)
+{
+ real_time_delay (ns, 1000 * 1000 * 1000);
+}
+
+/* Prints timer statistics. */
+void
+timer_print_stats (void)
+{
+ printf ("Timer: %"PRId64" ticks\n", timer_ticks ());
+}
+\f
+/* Timer interrupt handler. */
+static void
+timer_interrupt (struct intr_frame *args UNUSED)
+{
+ ticks++;
+ thread_tick ();
+}
+
+/* Returns true if LOOPS iterations waits for more than one timer
+ tick, otherwise false. */
+static bool
+too_many_loops (unsigned loops)
+{
+ /* Wait for a timer tick. */
+ int64_t start = ticks;
+ while (ticks == start)
+ barrier ();
+
+ /* Run LOOPS loops. */
+ start = ticks;
+ busy_wait (loops);
+
+ /* If the tick count changed, we iterated too long. */
+ barrier ();
+ return start != ticks;
+}
+
+/* Iterates through a simple loop LOOPS times, for implementing
+ brief delays.
+
+ Marked NO_INLINE because code alignment can significantly
+ affect timings, so that if this function was inlined
+ differently in different places the results would be difficult
+ to predict. */
+static void NO_INLINE
+busy_wait (int64_t loops)
+{
+ while (loops-- > 0)
+ barrier ();
+}
+
+/* Sleep for approximately NUM/DENOM seconds. */
+static void
+real_time_sleep (int64_t num, int32_t denom)
+{
+ /* Convert NUM/DENOM seconds into timer ticks, rounding down.
+
+ (NUM / DENOM) s
+ ---------------------- = NUM * TIMER_FREQ / DENOM ticks.
+ 1 s / TIMER_FREQ ticks
+ */
+ int64_t ticks = num * TIMER_FREQ / denom;
+
+ ASSERT (intr_get_level () == INTR_ON);
+ if (ticks > 0)
+ {
+ /* We're waiting for at least one full timer tick. Use
+ timer_sleep() because it will yield the CPU to other
+ processes. */
+ timer_sleep (ticks);
+ }
+ else
+ {
+ /* Otherwise, use a busy-wait loop for more accurate
+ sub-tick timing. */
+ real_time_delay (num, denom);
+ }
+}
+
+/* Busy-wait for approximately NUM/DENOM seconds. */
+static void
+real_time_delay (int64_t num, int32_t denom)
+{
+ /* Scale the numerator and denominator down by 1000 to avoid
+ the possibility of overflow. */
+ ASSERT (denom % 1000 == 0);
+ busy_wait (loops_per_tick * num / 1000 * TIMER_FREQ / (denom / 1000));