Additional information
Exit Codes:
- If the main thread calls
pthread_exit
, the process should terminate with exit code0
. - If any thread calls
exit(n)
, the process should terminate with exit coden
. - If the process terminates with an exception, it should exit with exit code
-1
. These are listed in priority order (with 3 being the highest priority), in the sense that if any of these occur simultaneously, the exit code should be the exit code corresponding termination with the highest prioirty. For example, if maincalls pthread_exit
and while it is waiting for user threads to finish, one of them terminates with an exception, the exit code should be set to-1
. Also, if multiple calls toexit(n)
are made at the same time with different values ofn
, any choice ofn
is valid. Treat exit code rules as secondary: we will not test you on them in design review, and you should only be concerned about them if you are failing a test because of the wrong exit code.
- If the main thread calls
Switching between user threads and switching between user processes require different actions on part of the kernel. Specifically, for switches between processes, the page table base pointer must be updated and any virtual caches (which for our purposes, is the TLB) should be invalidated. For switches between user threads, both of these things should be avoided. This is already done for you in
process_activate
, which is called every time a new thread is created inload
and every time a new thread is scheduled inthread_switch_tail
. Don’t forget to activate the process when you create a new user thread.You are not required to augment the scheduler for user threads; you can just let the scheduler treat all threads the same, even if they belong to the same process. As a pathological example, if a user program A has 100 threads, and a user program B has only 1 thread, most of the CPU will be dominated by A’s threads, and B’s thread will be starved. You are not required to augment the scheduler to make this scenario more fair.
User threads should be able to be implemented independently of the efficient alarm clock and strict priority scheduler. The alarm clock does not have an exposed interface via system calls, so the efficient alarm clock and user threads are completely independent. There is some overlap between the strict priority scheduler and user threads because user threads use both the scheduler and locks. However, the tasks should still be fairly independent of one another, since all user threads should have the same priority (
PRI_DEFAULT
).As our test programs are multithreaded, the
console_lock
defined intests/lib.c
is essential; threads can acquire this during printing calls to make sure print output of different threads is not interleaved. Currently, the test code only uses the console lock whensyn_msg
(defined intests/lib.c
) is set to true. The console lock is initialized intests/main.c
beforetest_main
is called in each of the tests. Because the console lock is a user-level lock, it will only work after you have implemented user-level locking. Until you’ve implemented user-level locking, all your tests will fail as a result of console lock initialization; you can comment out the linelock_init(&console_lock)
intests/main.c
to temporarily prevent this issue.In
threads/interrupt.c
, you will find the functionis_trap_from_userspace
which will return true if this interrupt represents a transition from user mode to kernel mode. You might find this helpful for this project.Workflow Recommendations: this task is most easily done in small steps. Start by implementing a barebones
pthread_create
andpthread_execute
so that you passtests/userprog/multithreading/create-simple
. Then, slowly add more and more features. It is easier to augment a working design than to fix a broken one. Make sure to carefully track resources. Everything that you allocate must be freed!