Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Additional information

  • Exit Codes:

    1. If the main thread calls pthread_exit, the process should terminate with exit code 0.
    2. If any thread calls exit(n), the process should terminate with exit code n.
    3. 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 main calls 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 to exit(n) are made at the same time with different values of n, any choice of n 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.
  • 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 in load and every time a new thread is scheduled in thread_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 in tests/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 when syn_msg (defined in tests/lib.c) is set to true. The console lock is initialized in tests/main.c before test_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 line lock_init(&console_lock) in tests/main.c to temporarily prevent this issue.

  • In threads/interrupt.c, you will find the function is_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 and pthread_execute so that you pass tests/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!