Making Rare Events Visible Without Breaking the Kernel
A scheduling policy can choose only among events that become visible to it. SECT therefore adds scheduling points around operations likely to mediate communication between kernel tasks, then asks whether each candidate point is safe to use before yielding. This chapter examines that diagnosis in two parts: why ordinary scheduler boundaries miss important interleavings, and why the extra control introduces its own safety and completeness limits. The goal is not to make every instruction preemptible. It is to increase useful resolution without confusing a plausible intervention with a proof of safety.
Why native scheduling points miss the ordering that matters
The Linux scheduler already regains control at meaningful operational moments. A task can block, yield, exhaust a time slice, or otherwise stop running. Those boundaries serve fairness and responsiveness: they let the system share CPUs and keep runnable work moving. They are not selected primarily because a shared-memory access is about to communicate with another task. A concurrency bug can therefore lie between two ordinary scheduling opportunities, even when the operations on either side are exactly where the relevant ordering is decided.
Imagine two kernel tasks whose critical operations are close together but neither operation blocks. The native scheduler may let the first task continue through both operations, or may happen to interrupt at a nearby point for reasons unrelated to the shared state. A campaign can repeat the input and obtain different timing without gaining a reliable way to request the ordering in which the second task intervenes between those operations. Temporal isolation supplies the policy for choosing a task, but it cannot choose a task at a point the kernel never exposes.
This is a boundary problem rather than simply a lack-of-randomness problem. If an event is visible only after a critical section has completed, selecting another task there cannot recreate an intervention inside the section. If the only boundary is a long time slice, many distinct shared-memory orderings collapse into one coarse scheduling decision. The resulting execution may look concurrent from the outside while still omitting the narrow transition that changes the state. Control over a broad interval is not equivalent to control over the event that carries the bug.
SECT addresses this visibility gap with compile-time instrumentation. Its LLVM pass identifies memory operations that access variables visible across threads and adds scheduling opportunities around them. It also targets selected high-level synchronization primitives, including widely used locks and other kernel coordination constructs. The point is semantic, not merely numeric: an access or synchronization operation is interesting because another task may communicate through it, not because every instruction deserves an equal chance to cause a context switch.
This choice protects the experiment from a different kind of waste. If the scheduler were invoked at every load, store, or instruction, most interventions would occur where tasks cannot affect one another. Context-switch overhead would rise, the execution would be distorted by an enormous number of irrelevant choices, and the exploration budget would be spent on events with little concurrency meaning. By concentrating on shared-memory and synchronization locations, SECT tries to align scheduling control with the places where reordering can change observable behavior.
The instrumentation is also policy-aware.