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