r/compsci • u/Mossack-Fonseca • 2d ago
what is context switching?
I know this has been discussed before, but it's extremely confusing for me because of how many variations there are in definitions. Here are some observations:
Most people would agree that process-switches and system calls both involve context switching, however I think the underlying "state saving" is different between these two events. In a system call, there is an entry phase where the kernel saves register state to the kernel stack (and not every system call leads to a process or thread switch). In a process-switch, the PCB gets updated so that the process can later be resumed. Is this accurate?
On Linux, both processes and threads are schedule-able (they're both "tasks"). As best as I can understand, there's a function called context_switch() in the Linux kernel that gets called during scheduling. However, it seems context switching is used in a broader sense. In other words "context switching" doesn't mean exactly that we're calling the function "context_switch()".
There is at least one textbook that considers functions as having their own context (Doeppner's Operating Systems in Depth). This is a little confusing because I can't find anyone else who considers a function call a change in context.
The question is: does anyone have a technical definition of context switching that captures what most people mean when they say "context switch"?
I've also been reading about the xv6 since it's a smaller educational operating system. If somebody has experience/knowledge of the xv6 internals, I would appreciate any input. Thank you
1
u/Benabik 2d ago
A process switch requires a kernel call, caused by a timer interrupt instead of a syscall. The kernel basically just switches its pointers for what state it will restore afterwards. So there is little difference between the two. (Although a syscall can also result in a process switch if it blocks.) I do not recall the exact mechanisms in the Linux kernel.
Kernel threads (pthreads on posix) are the same thing, with the slight exception that the kernel does not need to change the memory map, but most of the differences are just that the thread shares many data structures in the kernel with the rest of the process. There are library-only thread solutions (green threads or async tasks) that the kernel is unaware of. In those cases the library does basically the same thing, but it can be faster without the protection mode change. The tradeoff is that all green threads block if a system call blocks.
1
u/kazprog 2d ago edited 2d ago
A function call's context is more often called its "frame" in the callstack. There are registers in x86 specifically for pointing to the bottom of the frame and the current top of the frame, which would also align with the top of the callstack as a whole. I think they are called rbp (register base pointer) and rsp (register stack pointer). Calling that a "context" formally is a bit strange, but it might make sense informally if you're trying to discuss lexical scope and what syntactic bindings are available and how it relates to a calling convention.
A timer-based pre-emptive process switch runs like this:
- an interrupt fires from the interrupt controller's timer, the PIC or APIC or something even more new
- the interrupt mechanism runs a context switch from the user process to the kernel scheduler:
- the cpu core that is running the process has its state saved to a register-file or to the top of the stack, saving all of the normal registers and importantly the instruction pointer, spelled "rip", humorously enough.
- the kernel's interrupt handling routine runs as a result of the same interrupt mechanism, but only after the core's state was saved
- the kernel's interrupt handler runs the scheduler in this case, and the scheduler somehow knows what the prior task was, how long it was given to run a task, who else is waiting to run (the "run-queue") and the relative priorities of all of these tasks, and it runs the task it thinks is best suited to running next. in order to not thrash too much, usually processes are given a certain amount of time to run without being switched away from, this is called the scheduler's "quantum", or just "a quantum".
- the scheduler context switches back to the process that has been selected.
so there are two context switches, one invoked by the PIC (programmable interrupt controller), the other invoked by the scheduler itself, once it has decided who next should go.
A context switch has two parts, highlighted above:
- save the state from the prior process, either in a registerfile or on top of the stack
- pick up the instruction pointer and the rest of the state from the next process, and begin executing.
- in the ones i've seen, the context switch often pushes the instruction pointer onto the stack and then does something a bit tricky, with the return instruction or a call instruction or something, to invoke into the next process.
A kernel system call, on the other hand, runs like so:
- the process cooperatively (rather than pre-emptively) calls the system call, running a context switch, storing the user process' state and loading the kernel's state.
- the core escalated execution permissions from the user ring to the kernel ring
- the kernel figures out what system call to run
- the kernel runs it, either copying the necessary results to a memory address the user has provided, by modifying the process table itself (opening a file), or just through its return value
- the kernel cooperatively context switches back, de-escalating permissions and return control to the user.
1
u/DawnOnTheEdge 2d ago
It seems to primarily mean a switch between user and kernel mode (on a hardware level, between highest privilege with access to all memory on the system and lowest privilege with access only to the process’ address space).
1
13
u/SomewhereRude2144 2d ago
The thing that helped me was stopping to think of it as one specific mechanism and more as "whatever state you need to save and restore when you hand the CPU to something else." That's why a syscall and a full process switch both count, but they save different amounts. The function call thing is where it gets fuzzy, because most of the time the compiler handles that saving via the calling convention and nobody calls it a context switch. But conceptually, yeah, you're switching the active context, it's just not the OS doing it.