For this machine problem you will be adding more system calls to xv6 that:
You will implement the following system calls to support thread creation and management:
int thread_create(void (*tmain)(void *), void *stack, void *arg);
This creates a new thread that starts execution at the function
is called with the argument
arg. The caller is responsible for allocating
malloc, given in the file "umalloc.c") a new user stack before
thread_create and passing the address of the top of this memory
region in as the
stack argument. Returns the thread ID (which is really just
a process ID) of the new thread.
Its implementation will closely mimic that of
fork, except that the newly
created process will share the address space of its parent and will
therefore have automatic access to all of its parent's code and data segments.
int thread_join(void **stack);
This will cause the caller to block until a child thread has terminated, upon
which its ID will be returned and a pointer to its stack placed in
that the latter can be freed). If the caller does not have any child threads,
it will return immediately with
While this is similar to the
wait system call, note that it only operates on
children that share the same address space.
wait, in turn, will need to be
updated so that it only synchronizes on processes created by the caller that
do not share the same address space.
The main thread (i.e., the "original" thread) of a given process can call
thread_join as many times as it invoked
thread_create, so to ensure it
To allow your newly minted threads to coordinate critical sections and safely share data, you will implement the following system calls that expose a mutex lock. The lock will be implemented internally using a spinlock.
int mtx_create(int locked);
typedefa separate type for the lock ID, though it isn't strictly necessary). The lock starts out in the
lockedstate (binary: true or false).
int mtx_lock(int lock_id);
int mtx_unlock(int lock_id);
Note that you can build arbitrarily more sophisticated synchronization mechanisms (e.g., semaphores) in userspace by leveraging this mutex lock.
To test your code, you should write a program that implements the producer/consumer problem by sharing a bounded buffer between a parent and child (or sibling) threads, using the mutex as a primitive for implementing synchronization.
Add this program to your codebase and the Makefile (see how
getcount was added
for reference), and be sure to commit and push it as part of your submission.
As before, submit your work with the command
git push origin master, after
committing and testing all your changes.