4. Thread Design Considerations Flashcards
What’s required to support kernel vs user level threads?
Supporting threads at the kernel level means the OS itself is multi-threaded.
OS kernel maintains:
- thread abstraction data structure
- scheduling, synchronization
Supporting threads at the user level means there is a user-level library that is linked with the application and it provides all the management and runtime support for threads.
User-level library provides:
- thread abstraction data structure
- scheduling, synchronization
How does the process control block (PCB) change when we need to support both user and kernel level threads?
The user-level threads library will need to have a user-level thread data structure to keep track of the user level thread ids, registers, and stacks.
If we want to have multiple kernel-level threads associated with a process, we’d want to remove the execution state from the PCB and put that info into a kernel-level thread data structure to keep track of the stacks and registers.
The PCB keeps the virtual address mapping information.
What relationships are required between thread-related data structures?
The user-level thread library needs to keep track of all the threads that belong to a process, so there’s a relationship between the user-level thread (ULT) data structures and the process control block (PCB) that represents their address space.
For each process we need to keep track of which kernel-level threads execute on its behalf, and what is the address space within which each kernel-level thread operates, so there’s a relationship between the kernel-level thread (KLT) data structures and the process control block (PCB).
If the system has multiple CPUs we need a data structure to represent it, then we need a relationship between the kernel-level threads and the CPU.
What is “hard” process state? What is “light” process state? Give examples of each.
“Hard” process state is relevant for all user-level threads that execute within a process. (e.g., virtual address mapping)
“Light” process state is only relevant for a subset of user-level threads that are currently associated with a particular kernel-level thread. (e.g., signal mask, sys call arguments)
Explain the rationale for splitting the PCB into multiple data structures.
Cons of Single PCB:
- Scalability: large continuous data structure
- Overhead: private copy for each entity
- Performance: saved and restored on each context switch
- Flexibility: update for any changes
Pros of multiple data structures:
- Scalability: smaller data structures
- Overhead: easier to share
- Performance: on context switch only save and restore what needs to change
- Flexibility: user-level library need only update portion of the state
What interactions are necessary to efficiently manage threads?
System calls and special signals to allow the kernel and the user-level threads library to interact and coordinate. (e.g., The user-level library can request additional kernel-level threads using the set_concurrency system call, and the kernel can signal the user-level library that a kernel-level thread is about to block, giving the user-level library a chance to request more light weight processes / kernel-level threads.
What happens when a thread exits?
The thread is put on a “death row”
A reaper thread periodically destroys threads on death row.
If a reaper thread doesn’t destroy the thread by the time we need to create another one, then it’s reused, which gives us a performance gain!
Explain the differences between interrupts and signals.
Explain what interrupts and signals share.
How do (hardware) interrupts work?
When a device wants to send a notification to the CPU it sends a signal interrupt (MSI). Based on the info it sends we can tell exactly which device it was.
If the interrupt is enabled, it’s looked up in the interrupt handler table to find the starting address of the interrupt handling routine. Based on the interrupt number, we look up the starting address of the handler code, and set the program counter to the starting address and the execution routine of the handler starts.
Which interrupt can can occur on a plantform depends on the hardware and how it’s handled is specified by the operating system.
How do signals work?
Signals are different than interrupts because they’re generated internally as opposed to externally.
Once a signal is generated it’s similar to an interrup. The OS maintains a signal handler for every process in the system. For each signal in the system the table will specify the starting address of a handler routine.
The signals that can occur are defined by the operating system. How they are handled can be specified by the process, but the OS sets some defaults.
Why disable interrupts or signals?
Both interrupts and signals are executed in the context of the thread that was interrupted. This means they’re handled on the thread’s stack.
If a thread locks a mutex, is signaled/interrupted, and the handler needs the same mutex, then we have a deadlock. We can avoid this by ignoring some signals/interrupts using a signal mask. When the signal/interrupt is issued but not enabled, it will remain pending until the mask changes.
So then prior to aquiring the mutex, the thread disables the interrupt to prevent it from being interrupted while it has the mutex. Once the lock is freed, the thread will reset the mask, enable the interrupt, and execute the handler code.
Say a signal is being ignored by a thread and during this time it’s sent 3 times. When the signal is re-enabled by the thread, how many times will the handler run?
Typically only once.
If we want to make sure a handler routine runs more than once, it’s not sufficient to simply generate the signal more than once.
In what context are interrupt masks maintained?
In what context are signal masks maintained?
Interrupt masks are maintined per CPU. If mask disables an interrupt, then hardware interrupt routing mechanism will not deliver interrupt to the CPU.
Signal masks are maintained per execution context (ULT on top of KLT). If mask disables signal, then kernel sees mask and will not disrupt corresponding thread.
What should we know about interrupts on multicore systems (TODO: better question)?
Interrupts can be directed to any CPU that has them enabled.
We may set an interrupt on just a single core. This avoids overheads and pertubations on all other cores.