Nothing real interesting here. clone(): A new system call clone() is implemented with minimal changes and minimal safeguards :) . There are only two differences betwen clone() and fork(). First, clone() just copies the pgdir pointer from its parents rather than creating/copying the entire process space. For this reason, clone() also needs to explicitly set up its stack. We simply copy the parent's stack into the memory provided and update the new process's trap frame esp value to point to the correct place. To handle the stack copying, we need each process to explicitly track where its stack begins (we get the end from the parent's trap frame esp value). The only places where a new stack frame is created are then in clone() itself, in exec(), and in userinit(). In these three places we simply store beginning of the stack frame. The other small change is made to wait() where ZOMBIE processes are killed. Here we need to ensure that a page directory is not freed while it is still in use. Our decision was to share this responsibility with the user. That is, the initial parent always frees the page directory (if your page directory pointer is the same as your parents then you don't free it). Also, since a processes memory size is not shared between threads, it is undefined behavior for a child thread to access (including allocating) any memory beyond what its parent had allocated when the child was created. threading and locking: The thread_create() call simply calls clone and in the parent returns the new pid and in the child calls the provided function. The spinlocks are very simple, just an int and a simple xchg. thread-safe list; The thread-safe list is very simple. It only allows insertion (as that is all that is required). Due to the memory allocation requirements described above, the ts-list uses a very simple method of allocation. That is, the parent allocates all the nodes that will be needed before any child threads are created. The ts-list will hold these nodes in a free list, and on each insertion call it will do the following: acquire lock. take node off free list. put node at front of actual list. release lock. update value in node. Two small details here, we must keep a pointer to the specific node we want and not just the head of the list to do the update since it is outside of the critical section (which doesn't really gain us anything, but oh well). The other thing is that all insertions are at the head of the list; this is just simpler and insertion place was unspecified. Testing: Testing started with xv6's usertests to make sure that there were no regressions. Then testcounts was checked since we're actually using the code from p5, so may as well test it. Then the testthreads test was run with different values making sure that result was as expected... nothing too interesting. testthreads was run with values up to 20 threads and 10000 loop iterations.