Update docs.
[pintos-anon] / doc / threads.texi
1 @node Project 1--Threads, Project 2--User Programs, Pintos Tour, Top
2 @chapter Project 1: Threads
3
4 In this assignment, we give you a minimally functional thread system.
5 Your job is to extend the functionality of this system to gain a
6 better understanding of synchronization problems. Additionally, you
7 will use at least part of this increased functionality in future
8 assignments.
9
10 You will be working in primarily in the @file{threads} directory for
11 this assignment, with some work in the @file{devices} directory on the
12 side.  Compilation should be done in the @file{threads} directory.
13
14 Before you read the description of this project, you should read all
15 of the following sections: @ref{Introduction}, @ref{Coding Standards},
16 @ref{Project Documentation}, @ref{Debugging Tools}, and
17 @ref{Development Tools}.  You should at least skim the material in
18 @ref{Threads Tour}.  To complete this project you will also need to
19 read @ref{Multilevel Feedback Scheduling}.
20
21 @menu
22 * Understanding Threads::       
23 * Project 1 Code::              
24 * Debugging versus Testing::    
25 * Tips::                        
26 * Problem 1-1 Alarm Clock::     
27 * Problem 1-2 Join::            
28 * Problem 1-3 Priority Scheduling::  
29 * Problem 1-4 Advanced Scheduler::  
30 * Threads FAQ::                 
31 @end menu
32
33 @node Understanding Threads
34 @section Understanding Threads
35
36 The first step is to read and understand the initial thread system.
37 Pintos, by default, implements thread creation and thread completion,
38 a simple scheduler to switch between threads, and synchronization
39 primitives (semaphores, locks, and condition variables). 
40
41 However, there's a lot of magic going on in some of this code, so if
42 you haven't already compiled and run the base system, as described in
43 the introduction (@pxref{Introduction}), you should do so now.  You
44 can read through parts of the source code by hand to see what's going
45 on.  If you like, you can add calls to @func{printf} almost
46 anywhere, then recompile and run to see what happens and in what
47 order.  You can also run the kernel in a debugger and set breakpoints
48 at interesting spots, single-step through code and examine data, and
49 so on.  @xref{i386-elf-gdb}, for more information.
50
51 When a thread is created, you are creating a new context to be
52 scheduled. You provide a function to be run in this context as an
53 argument to @func{thread_create}. The first time the thread is
54 scheduled and runs, it will start from the beginning of that function
55 and execute it in the context. When that function returns, that thread
56 completes. Each thread, therefore, acts like a mini-program running
57 inside Pintos, with the function passed to @func{thread_create}
58 acting like @func{main}.
59
60 At any given time, Pintos is running exactly one thread, with the
61 others switched out.  The scheduler decides which thread to run next
62 when it needs to switch between them.  (If no thread is ready to run
63 at any given time, then the special ``idle'' thread runs.)  The
64 synchronization primitives are used to force context switches when one
65 thread needs to wait for another thread to do something.
66
67 The exact mechanics of a context switch are pretty gruesome and have
68 been provided for you in @file{threads/switch.S} (this is 80@var{x}86
69 assembly; don't worry about understanding it).  It involves saving the
70 state of the currently running thread and restoring the state of the
71 thread we're switching to.
72
73 Using the @command{gdb} debugger, slowly trace through a context
74 switch to see what happens (@pxref{i386-elf-gdb}).  You can set a
75 breakpoint on the @func{schedule} function to start out, and then
76 single-step from there.  Be sure to keep track of each thread's
77 address and state, and what procedures are on the call stack for each
78 thread.  You will notice that when one thread calls
79 @func{switch_threads}, another thread starts running, and the first
80 thing the new thread does is to return from
81 @func{switch_threads}.  We realize this comment will seem cryptic to
82 you at this point, but you will understand threads once you understand
83 why the @func{switch_threads} that gets called is different from the
84 @func{switch_threads} that returns.
85
86 @strong{Warning}: In Pintos, each thread is assigned a small,
87 fixed-size execution stack just under @w{4 kB} in size.  The kernel
88 does try to detect stack overflow, but it cannot always succeed.  You
89 may cause bizarre problems, such as mysterious kernel panics, if you
90 declare large data structures as non-static local variables,
91 e.g. @samp{int buf[1000];}.  Alternatives to stack allocation include
92 the page allocator in @file{threads/palloc.c} and the block allocator
93 in @file{threads/malloc.c}.  Note that the page allocator doles out
94 @w{4 kB} chunks and that @func{malloc} has a @w{2 kB} block size
95 limit.  If you need larger chunks, consider using a linked structure
96 instead.
97
98 @node Project 1 Code
99 @section Code
100
101 Here is a brief overview of the files in the @file{threads}
102 directory.  You will not need to modify most of this code, but the
103 hope is that presenting this overview will give you a start on what
104 code to look at.
105
106 @table @file
107 @item loader.S
108 @itemx loader.h
109 The kernel loader.  Assembles to 512 bytes of code and data that the
110 PC BIOS loads into memory and which in turn loads the kernel into
111 memory, does basic processor initialization, and jumps to the
112 beginning of the kernel.  You should not need to look at this code or
113 modify it.
114
115 @item kernel.lds.S
116 The linker script used to link the kernel.  Sets the load address of
117 the kernel and arranges for @file{start.S} to be at the very beginning
118 of the kernel image.  Again, you should not need to look at this code
119 or modify it, but it's here in case you're curious.
120
121 @item start.S
122 Jumps to @func{main}.
123
124 @item init.c
125 @itemx init.h
126 Kernel initialization, including @func{main}, the kernel's ``main
127 program.''  You should look over @func{main} at least to see what
128 gets initialized.
129
130 @item thread.c
131 @itemx thread.h
132 Basic thread support.  Much of your work will take place in these
133 files.  @file{thread.h} defines @struct{thread}, which you will
134 modify in the first three projects.
135
136 @item switch.S
137 @itemx switch.h
138 Assembly language routine for switching threads.  Already discussed
139 above.
140
141 @item palloc.c
142 @itemx palloc.h
143 Page allocator, which hands out system memory in multiples of 4 kB
144 pages.
145
146 @item malloc.c
147 @itemx malloc.h
148 A very simple implementation of @func{malloc} and @func{free} for
149 the kernel.
150
151 @item interrupt.c
152 @itemx interrupt.h
153 Basic interrupt handling and functions for turning interrupts on and
154 off.
155
156 @item intr-stubs.pl
157 @itemx intr-stubs.h
158 A Perl program that outputs assembly for low-level interrupt handling.
159
160 @item synch.c
161 @itemx synch.h
162 Basic synchronization primitives: semaphores, locks, and condition
163 variables.  You will need to use these for synchronization through all
164 four projects.
165
166 @item test.c
167 @itemx test.h
168 Test code.  For project 1, you will replace this file with your test
169 cases.
170
171 @item io.h
172 Functions for I/O port access.  This is mostly used by source code in
173 the @file{devices} directory that you won't have to touch.
174
175 @item mmu.h
176 Functions and macros related to memory management, including page
177 directories and page tables.  This will be more important to you in
178 project 3.  For now, you can ignore it.
179 @end table
180
181 @menu
182 * devices code::                
183 * lib files::                   
184 @end menu
185
186 @node devices code
187 @subsection @file{devices} code
188
189 The basic threaded kernel also includes these files in the
190 @file{devices} directory:
191
192 @table @file
193 @item timer.c
194 @itemx timer.h
195 System timer that ticks, by default, 100 times per second.  You will
196 modify this code in Problem 1-1.
197
198 @item vga.c
199 @itemx vga.h
200 VGA display driver.  Responsible for writing text to the screen.
201 You should have no need to look at this code.  @func{printf} will
202 call into the VGA display driver for you, so there's little reason to
203 call this code yourself.
204
205 @item serial.c
206 @itemx serial.h
207 Serial port driver.  Again, @func{printf} calls this code for you,
208 so you don't need to do so yourself.  Feel free to look through it if
209 you're curious.
210
211 @item disk.c
212 @itemx disk.h
213 Supports reading and writing sectors on up to 4 IDE disks.  This won't
214 actually be used until project 2.
215
216 @item intq.c
217 @itemx intq.h
218 Interrupt queue, for managing a circular queue that both kernel
219 threads and interrupt handlers want to access.  Used by the keyboard
220 and serial drivers.
221 @end table
222
223 @node lib files
224 @subsection @file{lib} files
225
226 Finally, @file{lib} and @file{lib/kernel} contain useful library
227 routines.  (@file{lib/user} will be used by user programs, starting in
228 project 2, but it is not part of the kernel.)  Here's a few more
229 details:
230
231 @table @file
232 @item ctype.h
233 @itemx inttypes.h
234 @itemx limits.h
235 @itemx stdarg.h
236 @itemx stdbool.h
237 @itemx stddef.h
238 @itemx stdint.h
239 @itemx stdio.c
240 @itemx stdio.h
241 @itemx stdlib.c
242 @itemx stdlib.h
243 @itemx string.c
244 @itemx string.h
245 Implementation of the standard C library.  @xref{C99}, for information
246 on a few recently introduced pieces of the C library that you might
247 not have encountered before.  @xref{Unsafe String Functions}, for
248 information on what's been intentionally left out for safety.
249
250 @item debug.c
251 @itemx debug.h
252 Functions and macros to aid debugging.  @xref{Debugging Tools}, for
253 more information.
254
255 @item random.c
256 @itemx random.h
257 Pseudo-random number generator.
258
259 @item round.h
260 Macros for rounding.
261
262 @item syscall-nr.h
263 System call numbers.  Not used until project 2.
264
265 @item kernel/list.c
266 @itemx kernel/list.h
267 Doubly linked list implementation.  Used all over the Pintos code, and
268 you'll probably want to use it a few places yourself in project 1.
269
270 @item kernel/bitmap.c
271 @itemx kernel/bitmap.h
272 Bitmap implementation.  You can use this in your code if you like, but
273 you probably won't have any need for project 1.
274
275 @item kernel/hash.c
276 @itemx kernel/hash.h
277 Hash table implementation.  Likely to come in handy for project 3.
278
279 @item kernel/console.c
280 @itemx kernel/console.h
281 Implements @func{printf} and a few other functions.
282 @end table
283
284 @node Debugging versus Testing
285 @section Debugging versus Testing
286
287 When you're debugging code, it's useful to be able to be able to run a
288 program twice and have it do exactly the same thing.  On second and
289 later runs, you can make new observations without having to discard or
290 verify your old observations.  This property is called
291 ``reproducibility.''  The simulator we use, Bochs, can be set up for
292 reproducibility, and that's the way that @command{pintos} invokes it.
293
294 Of course, a simulation can only be reproducible from one run to the
295 next if its input is the same each time.  For simulating an entire
296 computer, as we do, this means that every part of the computer must be
297 the same.  For example, you must use the same disks, the same version
298 of Bochs, and you must not hit any keys on the keyboard (because you
299 could not be sure to hit them at exactly the same point each time)
300 during the runs.
301
302 While reproducibility is useful for debugging, it is a problem for
303 testing thread synchronization, an important part of this project.  In
304 particular, when Bochs is set up for reproducibility, timer interrupts
305 will come at perfectly reproducible points, and therefore so will
306 thread switches.  That means that running the same test several times
307 doesn't give you any greater confidence in your code's correctness
308 than does running it only once.
309
310 So, to make your code easier to test, we've added a feature to Bochs
311 that makes timer interrupts come at random intervals, but in a
312 perfectly predictable way.  In particular, if you invoke
313 @command{pintos} with the option @option{-j @var{seed}}, timer
314 interrupts will come at irregularly spaced intervals.  Within a single
315 @var{seed} value, execution will still be reproducible, but timer
316 behavior will change as @var{seed} is varied.  Thus, for the highest
317 degree of confidence you should test your code with many seed values.
318
319 @node Tips
320 @section Tips
321
322 There should be no busy-waiting in any of your solutions to this
323 assignment.  Furthermore, resist the temptation to directly disable
324 interrupts in your solution by calling @func{intr_disable} or
325 @func{intr_set_level}, although you may find doing so to be useful
326 while debugging.  Instead, use semaphores, locks and condition
327 variables to solve synchronization problems.  Hint: read the comments
328 in @file{threads/synch.h} if you're unsure what synchronization
329 primitives may be used in what situations.
330
331 Given some designs of some problems, there may be one or two instances
332 in which it is appropriate to directly change the interrupt levels
333 instead of relying on the given synchroniztion primitives.  This must
334 be justified in your @file{DESIGNDOC} file.  If you're not sure you're
335 justified, ask!
336
337 While all parts of this assignment are required if you intend to earn
338 full credit on this project, keep in mind that Problem 1-2 (Join) will
339 be needed for future assignments, so you'll want to get this one
340 right.  We don't give out solutions, so you're stuck with your Join
341 code for the whole quarter.  Problem 1-1 (Alarm Clock) could be very
342 handy, but not strictly required in the future.  The upshot of all
343 this is that you should focus heavily on making sure that your
344 implementation of @func{thread_join} works correctly, since if it's
345 broken, you will need to fix it for future assignments.  The other
346 parts can be turned off in the future if you find you can't make them
347 work quite right.
348
349 Also keep in mind that Problem 1-4 (the MLFQS) builds on the features you
350 implement in Problem 1-3, so to avoid unnecessary code duplication, it
351 would be a good idea to divide up the work among your team members
352 such that you have Problem 1-3 fully working before you begin to tackle
353 Problem 1-4.
354
355 @node Problem 1-1 Alarm Clock
356 @section Problem 1-1: Alarm Clock
357
358 Improve the implementation of the timer device defined in
359 @file{devices/timer.c} by reimplementing @func{timer_sleep}.
360 Threads call @code{timer_sleep(@var{x})} to suspend execution until
361 time has advanced by at least @w{@var{x} timer ticks}.  This is
362 useful for threads that operate in real-time, for example, for
363 blinking the cursor once per second.  There is no requirement that
364 threads start running immediately after waking up; just put them on
365 the ready queue after they have waited for approximately the right
366 amount of time.
367
368 A working implementation of this function is provided.  However, the
369 version provided is poor, because it ``busy waits,'' that is, it spins
370 in a tight loop checking the current time until the current time has
371 advanced far enough.  This is undesirable because it wastes time that
372 could potentially be used more profitably by another thread.  Your
373 solution should not busy wait.
374
375 The argument to @func{timer_sleep} is expressed in timer ticks, not
376 in milliseconds or another unit.  There are @code{TIMER_FREQ} timer
377 ticks per second, where @code{TIMER_FREQ} is a macro defined in
378 @code{devices/timer.h}.
379
380 @node Problem 1-2 Join
381 @section Problem 1-2: Join
382
383 Implement @code{thread_join(tid_t)} in @file{threads/thread.c}.  There
384 is already a prototype for it in @file{threads/thread.h}, which you
385 should not change.  This function causes the currently running thread
386 to block until the thread whose thread id is passed as an argument
387 exits.  If @var{A} is the running thread and @var{B} is the argument,
388 then we say that ``@var{A} joins @var{B}.''
389
390 Incidentally, we don't use @code{struct thread *} as
391 @func{thread_join}'s parameter type because a thread pointer is not
392 unique over time.  That is, when a thread dies, its memory may be,
393 whether immediately or much later, reused for another thread.  If
394 thread A over time had two children B and C that were stored at the
395 same address, then @code{thread_join(@var{B})} and
396 @code{thread_join(@var{C})} would be ambiguous.  Introducing a thread
397 id or @dfn{tid}, represented by type @code{tid_t}, that is
398 intentionally unique over time solves the problem.  The provided code
399 uses an @code{int} for @code{tid_t}, but you may decide you prefer to
400 use some other type.
401
402 The model for @func{thread_join} is the @command{wait} system call
403 in Unix-like systems.  (Try reading the manpages.)  That system call
404 can only be used by a parent process to wait for a child's death.  You
405 should implement @func{thread_join} to have the same restriction.
406 That is, a thread may only join its immediate children.
407
408 A thread need not ever be joined.  Your solution should properly free
409 all of a thread's resources, including its @struct{thread},
410 whether it is ever joined or not, and regardless of whether the child
411 exits before or after its parent.  That is, a thread should be freed
412 exactly once in all cases.
413
414 Joining a given thread is idempotent.  That is, joining a thread T
415 multiple times is equivalent to joining it once, because T has already
416 exited at the time of the later joins.  Thus, joins on T after the
417 first should return immediately.
418
419 Calling @func{thread_join} on an thread that is not the caller's
420 child should cause the caller to return immediately.
421
422 Consider all the ways a join can occur: nested joins (@var{A} joins
423 @var{B}, then @var{B} joins @var{C}), multiple joins (@var{A} joins
424 @var{B}, then @var{A} joins @var{C}), and so on.  Does your join work
425 if @func{thread_join} is called on a thread that has not yet been
426 scheduled for the first time?  You should handle all of these cases.
427 Write test code that demonstrates the cases your join works for.
428 Don't overdo the output volume, please!
429
430 Be careful to program this function correctly.  You will need its
431 functionality for project 2.
432
433 Once you've implemented @func{thread_join}, define
434 @code{THREAD_JOIN_IMPLEMENTED} in @file{constants.h}.
435 @xref{Conditional Compilation}, for more information.
436
437 @node Problem 1-3 Priority Scheduling
438 @section Problem 1-3: Priority Scheduling
439
440 Implement priority scheduling in Pintos.  Priority scheduling is a key
441 building block for real-time systems.  Implement functions
442 @func{thread_set_priority} to set the priority of the running thread
443 and @func{thread_get_priority} to get the running thread's priority.
444 (A thread can examine and modify only its own priority.)  There are
445 already prototypes for these functions in @file{threads/thread.h},
446 which you should not change.
447
448 Thread priority ranges from @code{PRI_MIN} (0) to @code{PRI_MAX} (59).
449 The initial thread priority is passed as an argument to
450 @func{thread_create}.  If there's no reason to choose another
451 priority, use @code{PRI_DEFAULT} (29).  The @code{PRI_} macros are
452 defined in @file{threads/thread.h}, and you should not change their
453 values.
454
455 When a thread is added to the ready list that has a higher priority
456 than the currently running thread, the current thread should
457 immediately yield the processor to the new thread.  Similarly, when
458 threads are waiting for a lock, semaphore or condition variable, the
459 highest priority waiting thread should be woken up first.  A thread's
460 priority may be set at any time, including while the thread is waiting
461 on a lock, semaphore, or condition variable.
462
463 One issue with priority scheduling is ``priority inversion'': if a
464 high priority thread needs to wait for a low priority thread (for
465 instance, for a lock held by a low priority thread, or in
466 @func{thread_join} for a thread to complete), and a middle priority
467 thread is on the ready list, then the high priority thread will never
468 get the CPU because the low priority thread will not get any CPU time.
469 A partial fix for this problem is to have the waiting thread
470 ``donate'' its priority to the low priority thread while it is holding
471 the lock, then recall the donation once it has acquired the lock.
472 Implement this fix.
473
474 You will need to account for all different orders that priority
475 donation and inversion can occur.  Be sure to handle multiple
476 donations, in which multiple priorities are donated to a thread.  You
477 must also handle nested donation: given high, medium, and low priority
478 threads @var{H}, @var{M}, and @var{L}, respectively, if @var{H} is
479 waiting on a lock that @var{M} holds and @var{M} is waiting on a lock
480 that @var{L} holds, then both @var{M} and @var{L} should be boosted to
481 @var{H}'s priority.
482
483 You only need to implement priority donation when a thread is waiting
484 for a lock held by a lower-priority thread.  You do not need to
485 implement this fix for semaphores, condition variables or joins.
486 However, you do need to implement priority scheduling in all cases.
487
488 @node Problem 1-4 Advanced Scheduler
489 @section Problem 1-4: Advanced Scheduler
490
491 Implement Solaris's multilevel feedback queue scheduler (MLFQS) to
492 reduce the average response time for running jobs on your system.
493 @xref{Multilevel Feedback Scheduling}, for a detailed description of
494 the MLFQS requirements.
495
496 Demonstrate that your scheduling algorithm reduces response time
497 relative to the original Pintos scheduling algorithm (round robin) for
498 at least one workload of your own design (i.e.@: in addition to the
499 provided test).
500
501 You may assume a static priority for this problem. It is not necessary
502 to ``re-donate'' a thread's priority if it changes (although you are
503 free to do so).
504
505 You must write your code so that we can turn the MLFQS on and off at
506 compile time.  By default, it must be off, but we must be able to turn
507 it on by inserting the line @code{#define MLFQS 1} in
508 @file{constants.h}.  @xref{Conditional Compilation}, for details.
509
510 @node Threads FAQ
511 @section FAQ
512
513 @enumerate 1
514 @item
515 @b{I am adding a new @file{.h} or @file{.c} file.  How do I fix the
516 @file{Makefile}s?}@anchor{Adding c or h Files}
517
518 To add a @file{.c} file, edit the top-level @file{Makefile.build}.
519 You'll want to add your file to variable @samp{@var{dir}_SRC}, where
520 @var{dir} is the directory where you added the file.  For this
521 project, that means you should add it to @code{threads_SRC}, or
522 possibly @code{devices_SRC} if you put in the @file{devices}
523 directory.  Then run @code{make}.  If your new file doesn't get
524 compiled, run @code{make clean} and then try again.
525
526 When you modify the top-level @file{Makefile.build}, the modified
527 version should be automatically copied to
528 @file{threads/build/Makefile} when you re-run make.  The opposite is
529 not true, so any changes will be lost the next time you run @code{make
530 clean} from the @file{threads} directory.  Therefore, you should
531 prefer to edit @file{Makefile.build} (unless your changes are meant to
532 be truly temporary).
533
534 There is no need to edit the @file{Makefile}s to add a @file{.h} file.
535
536 @item
537 @b{How do I write my test cases?}
538
539 Test cases should be replacements for the existing @file{test.c}
540 file.  Put them in a @file{threads/testcases} directory.
541 @xref{TESTCASE}, for more information.
542
543 @item
544 @b{Why can't I disable interrupts?}
545
546 Turning off interrupts should only be done for short amounts of time,
547 or else you end up losing important things such as disk or input
548 events.  Turning off interrupts also increases the interrupt handling
549 latency, which can make a machine feel sluggish if taken too far.
550 Therefore, in general, setting the interrupt level should be used
551 sparingly.  Also, any synchronization problem can be easily solved by
552 turning interrupts off, since while interrupts are off, there is no
553 concurrency, so there's no possibility for race condition.
554
555 To make sure you understand concurrency well, we are discouraging you
556 from taking this shortcut at all in your solution.  If you are unable
557 to solve a particular synchronization problem with semaphores, locks,
558 or conditions, or think that they are inadequate for a particular
559 reason, you may turn to disabling interrupts.  If you want to do this,
560 we require in your design document a complete justification and
561 scenario (i.e.@: exact sequence of events) to show why interrupt
562 manipulation is the best solution.  If you are unsure, the TAs can
563 help you determine if you are using interrupts too haphazardly.  We
564 want to emphasize that there are only limited cases where this is
565 appropriate.
566
567 You might find @file{devices/intq.h} and its users to be an
568 inspiration or source of rationale.
569
570 @item
571 @b{Where might interrupt-level manipulation be appropriate?}
572
573 You might find it necessary in some solutions to the Alarm problem.
574
575 You might want it at one small point for the priority scheduling
576 problem.  Note that it is not required to use interrupts for these
577 problems.  There are other, equally correct solutions that do not
578 require interrupt manipulation.  However, if you do manipulate
579 interrupts and @strong{correctly and fully document it} in your design
580 document, we will allow limited use of interrupt disabling.
581
582 @item
583 @b{What does ``warning: no previous prototype for `@var{function}''
584 mean?}
585
586 It means that you defined a non-@code{static} function without
587 preceding it by a prototype.  Because non-@code{static} functions are
588 intended for use by other @file{.c} files, for safety they should be
589 prototyped in a header file included before their definition.  To fix
590 the problem, add a prototype in a header file that you include, or, if
591 the function isn't actually used by other @file{.c} files, make it
592 @code{static}.
593 @end enumerate
594
595 @menu
596 * Problem 1-1 Alarm Clock FAQ::  
597 * Problem 1-2 Join FAQ::        
598 * Problem 1-3 Priority Scheduling FAQ::  
599 * Problem 1-4 Advanced Scheduler FAQ::  
600 @end menu
601
602 @node Problem 1-1 Alarm Clock FAQ
603 @subsection Problem 1-1: Alarm Clock FAQ
604
605 @enumerate 1
606 @item
607 @b{Why can't I use most synchronization primitives in an interrupt
608 handler?}
609
610 As you've discovered, you cannot sleep in an external interrupt
611 handler.  Since many lock, semaphore, and condition variable functions
612 attempt to sleep, you won't be able to call those in
613 @func{timer_interrupt}.  You may still use those that never sleep.
614
615 Having said that, you need to make sure that global data does not get
616 updated by multiple threads simultaneously executing
617 @func{timer_sleep}.  Here are some pieces of information to think
618 about:
619
620 @enumerate a
621 @item
622 Interrupts are turned off while @func{timer_interrupt} runs.  This
623 means that @func{timer_interrupt} will not be interrupted by a
624 thread running in @func{timer_sleep}.
625
626 @item
627 A thread in @func{timer_sleep}, however, can be interrupted by a
628 call to @func{timer_interrupt}, except when that thread has turned
629 off interrupts.
630
631 @item
632 Examples of synchronization mechanisms have been presented in lecture.
633 Going over these examples should help you understand when each type is
634 useful or needed.
635 @end enumerate
636
637 @item
638 @b{What about timer overflow due to the fact that times are defined as
639 integers? Do I need to check for that?}
640
641 Don't worry about the possibility of timer values overflowing.  Timer
642 values are expressed as signed 63-bit numbers, which at 100 ticks per
643 second should be good for almost 2,924,712,087 years.
644 @end enumerate
645
646 @node Problem 1-2 Join FAQ
647 @subsection Problem 1-2: Join FAQ
648
649 @enumerate 1
650 @item
651 @b{Am I correct to assume that once a thread is deleted, it is no
652 longer accessible by the parent (i.e.@: the parent can't call
653 @code{thread_join(child)})?}
654
655 A parent joining a child that has completed should be handled
656 gracefully and should act as a no-op.
657 @end enumerate
658
659 @node Problem 1-3 Priority Scheduling FAQ
660 @subsection Problem 1-3: Priority Scheduling FAQ
661
662 @enumerate 1
663 @item
664 @b{Doesn't the priority scheduling lead to starvation? Or do I have to
665 implement some sort of aging?}
666
667 It is true that strict priority scheduling can lead to starvation
668 because thread may not run if a higher-priority thread is runnable.
669 In this problem, don't worry about starvation or any sort of aging
670 technique.  Problem 4 will introduce a mechanism for dynamically
671 changing thread priorities.
672
673 This sort of scheduling is valuable in real-time systems because it
674 offers the programmer more control over which jobs get processing
675 time.  High priorities are generally reserved for time-critical
676 tasks. It's not ``fair,'' but it addresses other concerns not
677 applicable to a general-purpose operating system.
678
679 @item
680 @b{After a lock has been released, does the program need to switch to
681 the highest priority thread that needs the lock (assuming that its
682 priority is higher than that of the current thread)?}
683
684 When a lock is released, the highest priority thread waiting for that
685 lock should be unblocked and put on the ready to run list.  The
686 scheduler should then run the highest priority thread on the ready
687 list.
688
689 @item
690 @b{If a thread calls @func{thread_yield} and then it turns out that
691 it has higher priority than any other threads, does the high-priority
692 thread continue running?}
693
694 Yes.  If there is a single highest-priority thread, it continues
695 running until it blocks or finishes, even if it calls
696 @func{thread_yield}.
697
698 @item
699 @b{If the highest priority thread is added to the ready to run list it
700 should start execution immediately.  Is it immediate enough if I
701 wait until next timer interrupt occurs?}
702
703 The highest priority thread should run as soon as it is runnable,
704 preempting whatever thread is currently running.
705
706 @item
707 @b{What happens to the priority of the donating thread?  Do the priorities
708 get swapped?}
709
710 No.  Priority donation only changes the priority of the low-priority
711 thread.  The donating thread's priority stays unchanged.  Also note
712 that priorities aren't additive: if thread A (with priority 5) donates
713 to thread B (with priority 3), then B's new priority is 5, not 8.
714
715 @item 
716 @b{Can a thread's priority be changed while it is sitting on the ready
717 queue?}
718
719 Yes.  Consider this case: low-priority thread L currently has a lock
720 that high-priority thread H wants.  H donates its priority to L (the
721 lock holder).  L finishes with the lock, and then loses the CPU and is
722 moved to the ready queue.  Now L's old priority is restored while it
723 is in the ready queue.
724
725 @item
726 @b{Can a thread's priority change while it is sitting on the queue of a
727 semaphore?}
728
729 Yes.  Same scenario as above except L gets blocked waiting on a new
730 lock when H restores its priority.
731
732 @item
733 @b{Why is pubtest3's FIFO test skipping some threads! I know my scheduler
734 is round-robin'ing them like it's supposed to!  Our output is like this:}
735
736 @example
737 Thread 0 goes.
738 Thread 2 goes.
739 Thread 3 goes.
740 Thread 4 goes.
741 Thread 0 goes.
742 Thread 1 goes.
743 Thread 2 goes.
744 Thread 3 goes.
745 Thread 4 goes.
746 @end example
747
748 @noindent @b{which repeats 5 times and then}
749
750 @example
751 Thread 1 goes.
752 Thread 1 goes.
753 Thread 1 goes.
754 Thread 1 goes.
755 Thread 1 goes.
756 @end example
757
758 This happens because context switches are being invoked by the test
759 when it explicitly calls @func{thread_yield}.  However, the time
760 slice timer is still alive and so, every tick (by default), thread 1
761 gets switched out (caused by @func{timer_interrupt} calling
762 @func{intr_yield_on_return}) before it gets a chance to run its
763 mainline.  It is by coincidence that Thread 1 is the one that gets
764 skipped in our example.  If we use a different jitter value, the same
765 behavior is seen where a thread gets started and switched out
766 completely.
767
768 Solution: Increase the value of @code{TIME_SLICE} in
769 @file{devices/timer.c} to a very high value, such as 10000, to see
770 that the threads will round-robin if they aren't interrupted.
771
772 @item
773 @b{What happens when a thread is added to the ready list which has
774 higher priority than the currently running thread?}
775
776 The correct behavior is to immediately yield the processor.  Your
777 solution must act this way.
778
779 @item
780 @b{What should @func{thread_get_priority} return in a thread while
781 its priority has been increased by a donation?}
782
783 The higher (donated) priority.
784 @end enumerate
785
786 @node Problem 1-4 Advanced Scheduler FAQ
787 @subsection Problem 1-4: Advanced Scheduler FAQ
788
789 @enumerate 1
790 @item
791 @b{What is the interval between timer interrupts?}
792
793 Timer interrupts occur @code{TIMER_FREQ} times per second.  You can
794 adjust this value by editing @file{devices/timer.h}.  The default is
795 100 Hz.
796
797 You can also adjust the number of timer ticks per time slice by
798 modifying @code{TIME_SLICE} in @file{devices/timer.c}.
799
800 @item
801 @b{Do I have to modify the dispatch table?}
802
803 No, although you are allowed to. It is possible to complete
804 this problem (i.e.@: demonstrate response time improvement)
805 without doing so.
806
807 @item
808 @b{When the scheduler changes the priority of a thread, how does this
809 affect priority donation?}
810
811 Short (official) answer: Don't worry about it. Your priority donation
812 code may assume static priority assignment.
813
814 Longer (unofficial) opinion: If you wish to take this into account,
815 however, your design may end up being ``cleaner.''  You have
816 considerable freedom in what actually takes place. I believe what
817 makes the most sense is for scheduler changes to affect the
818 ``original'' (non-donated) priority.  This change may actually be
819 masked by the donated priority.  Priority changes should only
820 propagate with donations, not ``backwards'' from donees to donors.
821
822 @item
823 @b{What is meant by ``static priority''?}
824
825 Once thread A has donated its priority to thread B, if thread A's
826 priority changes (due to the scheduler) while the donation still
827 exists, you do not have to change thread B's donated priority.
828 However, you are free to do so.
829
830 @item
831 @b{Do I have to make my dispatch table user-configurable?}
832
833 No.  Hard-coding the dispatch table values is fine.
834 @end enumerate