Add timer_sleep() that takes an argument in timer ticks.
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 10 Sep 2004 00:19:06 +0000 (00:19 +0000)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 10 Sep 2004 00:19:06 +0000 (00:19 +0000)
Remove timer_msleep(), timer_usleep(), timer_nsleep()
and add corresponding timer_ms2ticks(), timer_us2ticks(), and
timer_ns2ticks() to make the conversions.

doc/filesys.texi
doc/threads.texi
src/devices/disk.c
src/devices/timer.c
src/devices/timer.h

index 36d92e32903480b79bd7adc5a991dc04bc24d780..7652a8424b262481d64f36237cd29e24cf5d52a7 100644 (file)
@@ -218,7 +218,7 @@ demonstrate the performance improvement.
 Note that write-behind makes your filesystem more fragile in the face
 of crashes.  Therefore, you should implement some manner to
 periodically write all cached blocks to disk.  If you have
-@code{timer_msleep()} from the first project working, this is an
+@code{timer_sleep()} from the first project working, this is an
 excellent application for it.
 
 Likewise, read-ahead is only really useful when done asynchronously.
index c1fb41d34929a831e4a464bef00f74cadbcb8dd5..c604b9635127543cb040df3905c2bca6e64f5160 100644 (file)
@@ -7,9 +7,9 @@ better understanding of synchronization problems. Additionally, you
 will use at least part of this increased functionality in future
 assignments.
 
-You will be working in the @file{threads} and @file{devices}
-directories for this assignment.  Compilation should be done in the
-@file{threads} directory.
+You will be working in primarily in the @file{threads} directory for
+this assignment, with some work in the @file{devices} directory on the
+side.  Compilation should be done in the @file{threads} directory.
 
 @menu
 * Understanding Threads::       
@@ -157,9 +157,9 @@ Problem 4.
 @section Problem 1-2: Alarm Clock
 
 Improve the implementation of the timer device defined in
-@file{devices/timer.c} by reimplementing @code{timer_msleep(0}.
-Threads call @code{timer_msleep(@var{x})} to suspend execution until
-time has advanced by at least @w{@var{x} milliseconds}.  This is
+@file{devices/timer.c} by reimplementing @code{timer_sleep()}.
+Threads call @code{timer_sleep(@var{x})} to suspend execution until
+time has advanced by at least @w{@var{x} timer ticks}.  This is
 useful for threads that operate in real-time, for example, for
 blinking the cursor once per second.  There is no requirement that
 threads start running immediately after waking up; just put them on
@@ -173,9 +173,8 @@ advanced far enough.  This is undesirable because it wastes time that
 could potentially be used more profitably by another thread.  Your
 solution should not busy wait.
 
-The argument to @code{timer_msleep()} is expressed in milliseconds.
-You must convert it into timer ticks, rounding up.  The code provided
-does this acceptably; there is no need to change it.
+The argument to @code{timer_sleep()} is expressed in timer ticks, not
+in milliseconds or some other unit.
 
 @node Problem 1-2 Join, Problem 1-3 Priority Scheduling, Problem 1-1 Alarm Clock, Project 1--Threads
 @section Problem 1-2: Join
@@ -357,17 +356,17 @@ attempt to sleep, you won't be able to call those in
 
 Having said that, you need to make sure that global data does not get
 updated by multiple threads simultaneously executing
-@code{timer_msleep()}.  Here are some pieces of information to think
+@code{timer_sleep()}.  Here are some pieces of information to think
 about:
 
 @enumerate a
 @item
 Interrupts are turned off while @code{timer_interrupt()} runs.  This
 means that @code{timer_interrupt()} will not be interrupted by a
-thread running in @code{timer_msleep()}.
+thread running in @code{timer_sleep()}.
 
 @item
-A thread in @code{timer_msleep()}, however, can be interrupted by a
+A thread in @code{timer_sleep()}, however, can be interrupted by a
 call to @code{timer_interrupt()}, except when that thread has turned
 off interrupts.
 
index d8bed65343e16a2b91c6d41aea8b7771877444fc..234d5a952d3a03b27295b9c6bcb62a11d0b238e4 100644 (file)
@@ -255,12 +255,12 @@ reset_channel (struct channel *c)
   /* Issue soft reset sequence, which selects device 0 as a side effect.
      Also enable interrupts. */
   outb (reg_ctl (c), 0);
-  timer_usleep (10);
+  timer_sleep (timer_us2ticks (10));
   outb (reg_ctl (c), CTL_SRST);
-  timer_usleep (10);
+  timer_sleep (timer_us2ticks (10));
   outb (reg_ctl (c), 0);
 
-  timer_msleep (150);
+  timer_sleep (timer_ms2ticks (150));
 
   /* Wait for device 0 to clear BSY. */
   if (present[0]) 
@@ -279,7 +279,7 @@ reset_channel (struct channel *c)
         {
           if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1)
             break;
-          timer_msleep (10);
+          timer_sleep (timer_ms2ticks (10));
         }
       wait_while_busy (&c->devices[1]);
     }
@@ -445,7 +445,7 @@ wait_until_idle (const struct disk *d)
     {
       if ((inb (reg_status (d->channel)) & (STA_BSY | STA_DRQ)) == 0)
         return;
-      timer_usleep (10);
+      timer_sleep (timer_us2ticks (10));
     }
 
   printf ("%s: idle timeout\n", d->name);
@@ -471,7 +471,7 @@ wait_while_busy (const struct disk *d)
             printf ("ok\n");
           return (inb (reg_alt_status (c)) & STA_DRQ) != 0;
         }
-      timer_msleep (10);
+      timer_sleep (timer_ms2ticks (10));
     }
 
   printf ("failed\n");
@@ -488,7 +488,7 @@ select_device (const struct disk *d)
     dev |= DEV_DEV;
   outb (reg_device (c), dev);
   inb (reg_alt_status (c));
-  timer_nsleep (400);
+  timer_sleep (timer_ns2ticks (400));
 }
 
 /* Select disk D in its channel, as select_device(), but wait for
index 951c2a6d0b17d5ce375f0a7246c5da2714a92dbf..8f4838f048e04ec80d0060fc10cd1a3d77da3216 100644 (file)
@@ -55,31 +55,39 @@ timer_elapsed (int64_t then)
   return timer_ticks () - then;
 }
 
-/* Suspends execution for approximately MS milliseconds. */
+/* Suspends executions for approximately TICKS timer ticks. */
 void
-timer_msleep (int64_t ms) 
+timer_sleep (int64_t ticks) 
 {
-  int64_t ticks = (int64_t) DIV_ROUND_UP (ms * TIMER_FREQ, 1000);
   int64_t start = timer_ticks ();
 
   while (timer_elapsed (start) < ticks) 
     continue;
 }
 
-/* Suspends execution for approximately US microseconds.
-   Note: this is ridiculously inaccurate. */
-void
-timer_usleep (int64_t us) 
+/* Returns MS milliseconds in timer ticks, rounding up. */
+int64_t
+timer_ms2ticks (int64_t ms) 
 {
-  timer_msleep (us / 1000 + 1);
+  /*       MS / 1000 s          
+     ------------------------ = MS * TIMER_FREQ / 1000 ticks. 
+     (1 / TIMER_FREQ) ticks/s
+  */
+  return DIV_ROUND_UP (ms * TIMER_FREQ, 1000);
 }
 
-/* Suspends execution for approximately NS nanoseconds.
-   Note: this is ridiculously inaccurate. */
-void
-timer_nsleep (int64_t ns) 
+/* Returns US microseconds in timer ticks, rounding up. */
+int64_t
+timer_us2ticks (int64_t us) 
+{
+  return DIV_ROUND_UP (us * TIMER_FREQ, 1000000);
+}
+
+/* Returns NS nanoseconds in timer ticks, rounding up. */
+int64_t
+timer_ns2ticks (int64_t ns) 
 {
-  timer_msleep (ns / 1000000 + 1);
+  return DIV_ROUND_UP (ns * TIMER_FREQ, 1000000000);
 }
 \f
 /* Timer interrupt handler. */
index 5807b0fb253d1dace47cd211990b0cc6d4dffe99..db76f6d3456345f9380dfdf880f314210cbe4b81 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef DEVICES_TIMER_H
 #define DEVICES_TIMER_H
 
+#include <round.h>
 #include <stdint.h>
 
 /* Number of timer interrupts per second. */
@@ -10,8 +11,10 @@ void timer_init (void);
 int64_t timer_ticks (void);
 int64_t timer_elapsed (int64_t);
 
-void timer_msleep (int64_t ms);
-void timer_usleep (int64_t us);
-void timer_nsleep (int64_t ns);
+void timer_sleep (int64_t ticks);
+
+int64_t timer_ms2ticks (int64_t ms);
+int64_t timer_us2ticks (int64_t us);
+int64_t timer_ns2ticks (int64_t ns);
 
 #endif /* devices/timer.h */