Processes and Threads Help Guide - brown-cs1690/handout GitHub Wiki
Theme Song: ...Ready For It? - Taylor Swift
Resources
What is Procs (Processes)?
- A Process is an instance of a computer program. Processes contain various threads (one thread in the case of Weenix) as well as metadata: executable code (the program itself), the Process ID, the process state, virtual memory (stack, heap, text, data), register state, and references to children processes
- During this project, you will be concerned about how processes and threads work together to form the base of your operating system. Other details such as virtual memory, registers, files, etc. will be handled in later projects
- This project is important because processes and threads allow us to do things like create terminals, manage files, and essentially any other work that the operating system would need to do
Data Structures
proc_t
)
Processes (- Contains metadata like the process ID, the process name, the associated thread, exit status, process state, etc. We highly recommend familiarizing yourself with
proc.h
before the assignment. Don't worry if some of the fields don't make sense; you'll be constantly updating your procs code as your Weenix becomes more sophisticated - You will set up the struct for processes in
proc_create()
. You can follow a similar (but not same) structure asproc_idleproc_init()
. Also, don't forget to add the process toproc_list
!- If you're not sure what a field is for, such as
p_vmmap
, you shouldn't need to worry about it. For now, you should at least be able to setp_pid
,p_name
,p_pproc
,p_status
,p_state
, and initializep_threads
,p_children
,p_list_link
,p_child_link
, andp_wait
using the appropriate init functions - If the process has a parent, don't forget to update that parent's
p_children
field
- If you're not sure what a field is for, such as
- You will cleanup the process in
proc_cleanup()
(performed by the process on itself) andproc_destroy()
(performed by another process)
Process State
- Processes can be in two states:
PROC_RUNNING
andPROC_DEAD
. A running process is a process whose thread is running, whereas a dead process is a process whose thread has exited
Process ID
- A Process ID (PID) is how processes are identified within Weenix. A PID of 0 is the idle process and a PID of 1 is the init process. We'll cover more about these two processes later. After 0 and 1, all processes are labeled sequentially, like 2, 3, and 4.
kthread_t
)
Threads (- A thread is the smallest unit of execution. They execute the code you write. In operating systems, processes typically have multiple threads associated with each process
- You will notice throughout Procs that threads are referenced inside of lists such as
p_threads
inproc.h
. However, in Weenix, processes will only have one thread associated with them at any given time
- You will notice throughout Procs that threads are referenced inside of lists such as
- Contains a thread's return value, state, owned mutexes, etc. Like
proc.h
, we highly recommend familiarizing yourself withkthread.h
before the assignment. Again, don't worry if some of the fields don't make sense; you'll be updating your kthreads code in VM soon enough.
Thread State
In kthread.h
, you'll notice that there are six kthread_state_t
s: KT_NO_STATE
, KT_ON_CPU
, KT_RUNNABLE
, KT_SLEEP
, KT_SLEEP_CANCELLABLE
, and KT_EXITED
.
KT_NO_STATE
- an illegal state; if your thread is in stateKT_NO_STATE
, then something's gone wrong.KT_ON_CPU
- If your thread is in this state, then the thread is currently running.KT_RUNNABLE
- the thread is not currently running but is in line to get a turn on the CPU.KT_SLEEP
- the thread is blocked indefinitely (it can't be interrupted by cancellation). Threads could be in the stateKT_SLEEP
if they're, say, waiting for a mutex. Any event that is inKT_SLEEP
will be asleep until the event that it's waiting on is finished. Similar toUT_WAIT
from uthreadsKT_SLEEP_CANCELLABLE
- the thread is blocked indefinitely but can be interrupted. For example, a thread might be in the stateKT_SLEEP_CANCELLABLE
if there are no new characters to be read from the line discipline's buffer (don't worry if this doesn't make sense, we'll cover this in Drivers).KT_EXITED
- when a thread finishes execution. Note that in Weenix, if a thread finishes execution, its parent process will also have finished execution since Weenix processes only have one thread. So, when a kthread exits, it will notify its parent process, who will then clean up the process.
Scheduling
- The scheduling is similar to how it occurs in uthreads. The run queue is used for threads waiting to run (no priority in Weenix)
- A thread may be waiting on a sleep queue, such as waiting for a mutex or waiting for a child process to exit
- A thread that is not currently running must be on some queue
- Threads are scheduled, not processes
- It will be helpful to view the life cycle of threads/processes diagram on the Procs handout
kmutex_t
)
Mutexes (- Contains the queue of threads that are waiting to obtain the mutex and a reference to the current holder of the mutex. Although you will not have to implement mutexes as part of Procs, it is crucial that you understand how mutexes work in conjunction with processes and threads.
list_t/link_list_t
)
Lists (- This is a circular doubly linked list implementation. For an explanation of how to use lists (which you will be using throughout Weenix), refer to
list.h
. You can also look at examples of how lists are used in other parts of Weenix
Macros and Global Variables
Helpful Macros
PROC_RUNNING
,PROC_DEAD
- see "Process State"KT_NO_STATE
,KT_ON_CPU
,KT_RUNNABLE
,KT_SLEEP
,KT_SLEEP_CANCELLABLE
,KT_EXITED
- see "Thread State"PROC_NAME_LEN
- maximum length for a process's namePROC_MAX_COUNT
- maximum number of processes
Global Variables
It's helpful to keep the following global variables in mind:
curthr
- the current thread on the cpukt_runq
- the run queue of threads waiting to be runcurproc
- the current processproc_list
- list of all processesproc_initproc
- pointer to init process
To-Dos and To-Donts
What is completed for you?
- Mutexes
- Initialization of the Idle Process (PID 0)
- Destruction of Processes (
proc_destroy()
inproc.c
) - Context Switching (
core_switch()
insched.c
)
What do you have to complete?
- The bulk of
proc.c
(process creation, cleanup, killing, and waitpid) - The bulk of
kthread.c
(thread creation, destruction, and cancelling. Don't worry aboutkthread_clone()
). - Scheduling in
sched.c
(thread switching, making threads runnable, cancelling threads, putting threads to a (cancellable) sleep)
do_waitpid()
This function may not seem too hard conceptually but you'll want to make sure that this function works. A broken do_waitpid()
will result in a lot of other broken functions.
- At a high level,
do_waitpid()
is a function that waits for a child process of the current process to exit. - In order to make sure that the current process is notified when a child process exits, we can use
sched_sleep_on()
. Think of the current process as sleeping on the child process. - What should we do with an exited process? Destroy it, right?
- Make sure to break up
do_waitpid()
into two cases. If we wait for any process to exit (PID == -1), then we should just keep looking for a process until we find one that's exited. Otherwise, we should look for a process with the specified PID. - Again, make sure to test this function thoroughly!
Testing
A crucial but often overlooked part of software development is testing. Make sure to develop a particularly thorough test suite for Procs. Here are some things you might want to test:
- Running several processes and threads concurrently.
- Processes and threads exit cleanly.
- Exiting your kernel using proc_kill_all versus letting threads terminate manually.
- Processes' interactions with mutexes
- Cleaning up of child processes.
- Cancellation of processes.
- Waiting on child processes.
- Refer to the list of cases on the Procs handout We want to highly emphasize the importance of testing these cases and other cases you can think of. Future projects continue building on each other (especially building on Procs). You may find bugs with Procs in the next project, or you may not even encounter the bugs until VM.
Running Tests
In order to run your tests, you will have to call proctest_main()
(proctest.c
) in initproc_run()
(kmain.c)
. You should be able to follow test_termination()
to create tests of your own.
Debugging
- We've provided
proc_info()
inproc.c
as a means to print process metadata to the terminal. - We've also provided
proc_list_info()
inproc.c
as a means to print metadata regarding a processes' children. - Use the
dbg
macro to print any information to the terminal. For this assignment, you will want to useDBG_PROC
, i.e.dbg(DBG_PROC, "Process %d exited", curpoc->p_pid)
- For more guidance on this, please refer to the Debugging handout
FAQs
- What should I see in the QEMU window after finishing Procs?
- For now, a blank screen. Things will appear on the QEMU window after Drivers
- Make sure your editor terminal doesn't have any errors though!
- That's a lot of code. Where should I start?
- Start by reading through
proc.h
,kthread.h
,sched.h
, andkmutex.h
- Then work through
proc.c
,kthread.c
, andsched.c
in that order.
- Start by reading through
- Why is Weenix shutting down early?
- Make sure you have a while loop in
initproc_run()
that waits(do_waitpid())
until there are no more child processes before returning.
- Make sure you have a while loop in
- What's the difference between threads and processes?
- Threads are roughly "units of execution" while processes are "units of resources"
Getting Started
- Read. Read through all of the documentation we give you. It will save you a lot of time if you spend some time reading through things and understanding how Procs works. You won't get a 100% understanding on your first read, but it's good to have some baseline understanding of what you're implementing
- Start with reading through the header files,
proc.h
,kthread.h
,sched.h
,kmutex.h
,slab.h
andlist.h
- Start with reading through the header files,
- You may find this to be overwhelming. Weenix may be a codebase that's bigger than what you're used to working with. However, you'll spend enough time going through it that it'll become easier to navigate. Projects are organized in their own folders to make it even easier. As long as you spend some time reading through everything first, understanding how it works conceptually, and process the information, you'll be okay! Don't be afraid to ask your mentor TA any questions you have or to ask on Edstem. We know you can get through this :)