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

Processes (proc_t)

  • 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 as proc_idleproc_init(). Also, don't forget to add the process to proc_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 set p_pid, p_name, p_pproc, p_status, p_state, and initialize p_threads, p_children, p_list_link,p_child_link, and p_wait using the appropriate init functions
    • If the process has a parent, don't forget to update that parent's p_children field
  • You will cleanup the process in proc_cleanup() (performed by the process on itself) and proc_destroy() (performed by another process)

Process State

  • Processes can be in two states: PROC_RUNNING and PROC_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.

Threads (kthread_t)

  • 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 in proc.h. However, in Weenix, processes will only have one thread associated with them at any given time
  • Contains a thread's return value, state, owned mutexes, etc. Like proc.h, we highly recommend familiarizing yourself with kthread.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_ts: 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 state KT_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 state KT_SLEEP if they're, say, waiting for a mutex. Any event that is in KT_SLEEP will be asleep until the event that it's waiting on is finished. Similar to UT_WAIT from uthreads
  • KT_SLEEP_CANCELLABLE - the thread is blocked indefinitely but can be interrupted. For example, a thread might be in the state KT_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

Mutexes (kmutex_t)

  • 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.

Lists (list_t/link_list_t)

  • 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 name
  • PROC_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 cpu
  • kt_runq - the run queue of threads waiting to be run
  • curproc - the current process
  • proc_list - list of all processes
  • proc_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() in proc.c)
  • Context Switching (core_switch() in sched.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 about kthread_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() in proc.c as a means to print process metadata to the terminal.
  • We've also provided proc_list_info() in proc.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 use DBG_PROC, i.e. dbg(DBG_PROC, "Process %d exited", curpoc->p_pid)

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, and kmutex.h
    • Then work through proc.c, kthread.c, and sched.c in that order.
  • 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.
  • 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 and list.h
  • 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 :)