Expand description
The eligible deadline queue, from the source the BPF program is built from: the loader reads the queues in the arena through the same code. Eligible Deadline Queue: an intrusive red-black tree, a port of scx_eevdf’s lib/edq.bpf.c.
The tree is ordered by deadline, ties broken by insertion order, and every node caches the minimum eligibility and the shortest slice of its subtree. The first eligible task in deadline order, which is what pick_eevdf() searches for, is then one descent from the root, and the shortest queued request is read off the root.
Nodes and queues are addressed by plain u64 addresses, 0 for none, and
every access goes through Memory. In BPF that is the arena, cast at
each access, with loops bounded by may_goto, which the verifier does not
unroll.
The host tests run the same code on ordinary memory.
A queued task is its node followed by a hold count and its membership,
the address of its queue, 0, or DEAD. The queue has a lock of its
own. Its owner CID takes it in its callbacks, which already hold the rq
lock, so the only other holders are remote CIDs peeking or stealing, and
those only try it. Lockless snapshots of the first deadline and the
shortest slice serve decisions that tolerate a stale value.
The snapshots need only View, the loads of Memory. An observer
outside the scheduler, such as the loader reading the arena it mapped,
implements that alone: it can read a queue’s words and can neither
change them nor take the lock.
Structs§
- Cursor
- A resumable position in deadline order, which survives the nodes it passed leaving the tree.
Constants§
- BLACK 🔒
- COLOR 🔒
- CURSOR_
AFTER - A cursor that resumes after its key.
- CURSOR_
AT - A cursor that resumes at its key, the task it names included.
- CURSOR_
START - A cursor that starts at the first task.
- DEAD
- Membership of a task that may never be queued again.
- DEADLINE 🔒
- E2BIG
- EALREADY
- EBUSY
- ECANCELED
- EINVAL
- ELIGIBILITY 🔒
- ENOENT
- ETIMEDOUT
- FIRST 🔒
- FIRST_
DEADLINE 🔒 - HOLD 🔒
- LEFT 🔒
- LOCK 🔒
- LOCK_
SPINS 🔒 - MAX_
DEPTH 🔒 - Bound on a walk from the root to a leaf. A red-black tree of 2^31 nodes is no deeper than this.
- MAX_
SPINS 🔒 - Spinning for a queue lock, or for holders to drop a task, is bounded by can_loop alone, as lib/edq’s is. On JITs with timed may_goto, x86 and arm64 among them, that is a quarter of a second per program run, not BPF_MAX_LOOPS iterations. A holder can be held up for milliseconds, by an interrupt or, on a virtual machine, by the host descheduling its vCPU.
- MEMBER 🔒
- MIN_
ELIGIBILITY 🔒 - MIN_
SLICE 🔒 - NR 🔒
- PARENT 🔒
- QUEUE_
BYTES - Bytes a queue takes in a table of them, a cache line each.
- QUEUE_
MIN_ 🔒SLICE - QUEUE_
SEQ 🔒 - QUEUE_
WORDS - Words in a queue.
- RED 🔒
- RIGHT 🔒
- ROOT 🔒
- SEQ 🔒
- SLICE 🔒
- TASK_
WORDS - Words in a queued task.
Traits§
Functions§
- clear_
links 🔒 - drop_
task - eligible 🔒
- erase_
fixup 🔒 - Restore the red-black properties after a black node left the child slot
of
parentthat is now empty: that side is one black node short. - erase_
step 🔒 - One step of
erase_fixupwith the short side,SIDE, known at compile time, as the verifier explores far fewer states through two fixed-side copies than through one that picks the side at run time. Returns the result once the properties hold, orNoneto go on one level up. - first_
deadline - Lockless snapshot of the first deadline, or
Nonewhen empty. - first_
eligible 🔒 - The first node in deadline order whose eligibility is at or before
cutoff, or 0: one descent guided by the subtree minima. - get 🔒
- held
- Is
taskheld by a pop or a peek that has not dropped it yet? - hold_
count - How many pops and peeks hold
task, for debugging dumps. - hold_
task - insert
- Queue
taskonqueue. Fails withEALREADYif it is queued anywhere, andECANCELEDonce it is dead. - insert_
fixup 🔒 - Restore the red-black properties after linking the red leaf
node. - key
- The deadline, eligibility and insertion order a queued task was keyed with.
- leftmost 🔒
- The leftmost node under
node, or 0 if the walk ran out. - less 🔒
- lock
- Take
queue’s lock, spinning a bounded time. - lock_
slow 🔒 - The spin of
lock, in a function of its own: see LOCK_SPINS. - locked
- Lockless snapshot of whether
queue’s lock is held. - membership
- The queue
taskis a member of: its address, 0, orDEAD. - min_
slice - Lockless snapshot of the shortest queued slice, 0 when empty.
- nr_
inserted - Lockless snapshot of how many tasks were ever queued on
queue. - nr_
queued - opposite 🔒
- pop_
first - Remove and return the first task by deadline, or 0 if the queue is empty.
With
hold, the task is held for the caller. - pop_
first_ eligible_ or_ first - Remove and return the first task whose eligibility is at or before
cutoff, or else the first task, or 0 if the queue is empty. Withhold, the task is held for the caller. - pop_
locked 🔒 - propagate 🔒
- Recompute the cached minima from
nodeup to the root. The walk stops at the first node whose minima did not change, since nothing above it can change either, unlessresumeis further up the path: then it goes on fromresume, whose cached minima are not ones the nodes above saw. - put 🔒
- queue_
init - Initialize an empty queue.
- red 🔒
- refresh_
min_ 🔒slice - remove
- Take
taskout ofqueue.EINVALif it is not queued there. - remove_
locked 🔒 - replace_
child 🔒 - rotate 🔒
- Rotate
nodedown to the sidedown, raising its child on the other side, and return that child. The child takes over the node’s subtree, and with it its minima. - task_
detach - Take
taskout of whatever queue it is in for good, then wait for the holders to drop it, so that its memory can be reused. - task_
fini - Take
taskout of the queue it is in, if any. Returns 1 if it was queued, 0 if not, or an error. - task_
init - Bring a fresh task to the state of one queued nowhere and held by nobody, word by word.
- time_
before 🔒 - try_
first_ eligible_ deadline - The deadline of the first eligible task and the shortest queued slice,
without removing anything.
ENOENTwhen nothing queued is eligible,EBUSYwhen the queue is contended. - try_
peek_ next_ hold - Hold the next task in deadline order after
cursorand advance it, so that a bounded scan can resume even after the tasks it passed have left. Returns 0 with no task at the end,EBUSYwhen contended. - try_
remove - As
remove, butEBUSYif the queue is contended. - trylock
- Take
queue’s lock if it is free. - unlock
- update 🔒
- Refresh the cached subtree minima of
node.