Remove timer_msleep(), timer_usleep(), timer_nsleep()
and add corresponding timer_ms2ticks(), timer_us2ticks(), and
timer_ns2ticks() to make the conversions.
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
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.
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.
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::
@menu
* Understanding Threads::
@section Problem 1-2: Alarm Clock
Improve the implementation of the timer device defined in
@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
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.
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
@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
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
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()}.
-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.
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);
/* Issue soft reset sequence, which selects device 0 as a side effect.
Also enable interrupts. */
outb (reg_ctl (c), 0);
+ timer_sleep (timer_us2ticks (10));
outb (reg_ctl (c), CTL_SRST);
outb (reg_ctl (c), CTL_SRST);
+ timer_sleep (timer_us2ticks (10));
+ timer_sleep (timer_ms2ticks (150));
/* Wait for device 0 to clear BSY. */
if (present[0])
/* Wait for device 0 to clear BSY. */
if (present[0])
{
if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1)
break;
{
if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1)
break;
+ timer_sleep (timer_ms2ticks (10));
}
wait_while_busy (&c->devices[1]);
}
}
wait_while_busy (&c->devices[1]);
}
{
if ((inb (reg_status (d->channel)) & (STA_BSY | STA_DRQ)) == 0)
return;
{
if ((inb (reg_status (d->channel)) & (STA_BSY | STA_DRQ)) == 0)
return;
+ timer_sleep (timer_us2ticks (10));
}
printf ("%s: idle timeout\n", d->name);
}
printf ("%s: idle timeout\n", d->name);
printf ("ok\n");
return (inb (reg_alt_status (c)) & STA_DRQ) != 0;
}
printf ("ok\n");
return (inb (reg_alt_status (c)) & STA_DRQ) != 0;
}
+ timer_sleep (timer_ms2ticks (10));
dev |= DEV_DEV;
outb (reg_device (c), dev);
inb (reg_alt_status (c));
dev |= DEV_DEV;
outb (reg_device (c), dev);
inb (reg_alt_status (c));
+ timer_sleep (timer_ns2ticks (400));
}
/* Select disk D in its channel, as select_device(), but wait for
}
/* Select disk D in its channel, as select_device(), but wait for
return timer_ticks () - then;
}
return timer_ticks () - then;
}
-/* Suspends execution for approximately MS milliseconds. */
+/* Suspends executions for approximately TICKS timer ticks. */
-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;
}
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. */
}
\f
/* Timer interrupt handler. */
#ifndef DEVICES_TIMER_H
#define DEVICES_TIMER_H
#ifndef DEVICES_TIMER_H
#define DEVICES_TIMER_H
#include <stdint.h>
/* Number of timer interrupts per second. */
#include <stdint.h>
/* Number of timer interrupts per second. */
int64_t timer_ticks (void);
int64_t timer_elapsed (int64_t);
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 */
#endif /* devices/timer.h */