P2L4. Thread Design Considerations Flashcards

1
Q

What’s required to support kernel vs user level threads?

A

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 well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

How does the process control block (PCB) change when we need to support both user and kernel level threads?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What relationships are required between thread-related data structures?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is “hard” process state? What is “light” process state? Give examples of each.

A

“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)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Explain the rationale for splitting the PCB into multiple data structures.

A

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
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What interactions are necessary to efficiently manage threads?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What happens when a thread exits?

A

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!

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Explain the differences between interrupts and signals.

A
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Explain what interrupts and signals share.

A
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

How do (hardware) interrupts work?

A

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 well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

How do signals work?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Why disable interrupts or signals?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

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?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

In what context are interrupt masks maintained?

In what context are signal masks maintained?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What should we know about interrupts on multicore systems (TODO: better question)?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What types of signals are there?

A

One-Shot Signals: n signals pending == 1 signal pending. The handler will be called at least once. These types of signals must be explicity re-enabled (after the signal is handled, if the handler is not reinstalled the OS will go back to using its default for the signal)

Real Time Signals: if n signals raised, then handler is called n times.

17
Q

How does the Solaris OS use threads to avoid deadlocks with interrupt/signal handling?

A

Rather than expecting the thread that has a mutex to block interrupts/signals, the Solaris OS uses a seperate thead to execute interrupt/signal handler code. This means that if a thread has a lock, and a handler also needs the lock, the thread that’s executing the handler will be rescheduled until after the lock-holding thread unlocks the mutex, thus avoiding the deadlock.

However, creating threads is expensive, so Solaris checks if the handler contains a mutex. If it doesn’t contain a mutex, then it executes the handler in the original thread. If it does create a mutex, only then does it create a thread to handle the interrupt/signal.

18
Q

How did Solaris OS use of threads for handlers that need to obtain a lock impact performance?

How is it an example of optimizing for the common case?

A
  • Checking if a handler has a lock, creating a thread to execute the handler, etc. has an overhead of 40 SPARC instructions per interrupt.
  • However we see a savings of 12 instructions per mutex (no changes in interrupt mask, level, etc.)
  • There are far fewer interrupts than mutex lock/unlock operations so overall it’s a performance win.

The common case here is the mutex lock/unlock operation, so we want to make those as efficent as possible.