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