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.
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::
@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
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
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.
/* 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])
{
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]);
}
{
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);
printf ("ok\n");
return (inb (reg_alt_status (c)) & STA_DRQ) != 0;
}
- timer_msleep (10);
+ timer_sleep (timer_ms2ticks (10));
}
printf ("failed\n");
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
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. */
#ifndef DEVICES_TIMER_H
#define DEVICES_TIMER_H
+#include <round.h>
#include <stdint.h>
/* Number of timer interrupts per second. */
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 */