-The argument to @code{timer_sleep()} is expressed in timer ticks, not
-in milliseconds or some other unit.
-
-@node Problem 1-2 Join
-@section Problem 1-2: Join
-
-Implement @code{thread_join(tid_t)} in @file{threads/thread.c}. There
-is already a prototype for it in @file{threads/thread.h}, which you
-should not change. This function causes the currently running thread
-to block until the thread whose thread id is passed as an argument
-exits. If A is the running thread and B is the argument, then we say
-that ``A joins B'' in this case.
-
-Incidentally, we don't use @code{struct thread *} as
-@file{thread_join()}'s parameter type because a thread pointer is not
-unique over time. That is, when a thread dies, its memory may be,
-whether immediately or much later, reused for another thread. If
-thread A over time had two children B and C that were stored at the
-same address, then @code{thread_join(@r{B})} and
-@code{thread_join(@r{C})} would be ambiguous. Introducing a thread id
-or @dfn{tid}, represented by type @code{tid_t}, that is intentionally
-unique over time solves the problem. The provided code uses an
-@code{int} for @code{tid_t}, but you may decide you prefer to use some
-other type.
-
-The model for @code{thread_join()} is the @command{wait} system call
-in Unix-like systems. (Try reading the manpages.) That system call
-can only be used by a parent process to wait for a child's death. You
-should implement @code{thread_join()} to have the same restriction.
-That is, a thread may only join its immediate children.
-
-A thread need not ever be joined. Your solution should properly free
-all of a thread's resources, including its @code{struct thread},
-whether it is ever joined or not, and regardless of whether the child
-exits before or after its parent. That is, a thread should be freed
-exactly once in all cases.
-
-Joining a given thread is idempotent. That is, joining a thread T
-multiple times is equivalent to joining it once, because T has already
-exited at the time of the later joins. Thus, joins on T after the
-first should return immediately.
-
-Calling @code{thread_join()} on an thread that is not the caller's
-child should cause the caller to return immediately.
-
-Consider all the ways a join can occur: nested joins (A joins B when B
-is joined on C), multiple joins (A joins B, then A joins C), and so
-on. Does your join work if @code{thread_join()} is called on a thread
-that has not yet been scheduled for the first time? You should handle
-all of these cases. Write test code that demonstrates the cases your
-join works for. Don't overdo the output volume, please!
-
-Be careful to program this function correctly. You will need its
-functionality for project 2.
-
-Once you've implemented @code{thread_join()}, define
-@code{THREAD_JOIN_IMPLEMENTED} in @file{constants.h}.
-@xref{Conditional Compilation}, for more information.
-
-@node Problem 1-3 Priority Scheduling
-@section Problem 1-3: Priority Scheduling
+The argument to @func{timer_sleep} is expressed in timer ticks, not in
+milliseconds or any another unit. There are @code{TIMER_FREQ} timer
+ticks per second, where @code{TIMER_FREQ} is a macro defined in
+@code{devices/timer.h}.
+
+Separate functions @func{timer_msleep}, @func{timer_usleep}, and
+@func{timer_nsleep} do exist for sleeping a specific number of
+milliseconds, microseconds, or nanoseconds, respectively, but these will
+call @func{timer_sleep} automatically when necessary. You do not need
+to modify them.
+
+If your delays seem too short or too long, reread the explanation of the
+@option{-r} option to @command{pintos} (@pxref{Debugging versus
+Testing}).
+
+@node Problem 1-2 Priority Scheduling
+@section Problem 1-2: Priority Scheduling