class WaitQueueCollection

Defined at line 188 of file ../../zircon/kernel/include/kernel/thread.h

A WaitQueueCollection is the data structure which holds a collection of

threads which are currently blocked in a wait queue. The data structure

imposes a total ordering on the threads meant to represent the order in which

the threads should be woken, from "most important" to "least important".

One unusual property of the ordering implemented by a WaitQueueCollection is

that, unlike an ordering determined completely by properties such as thread

priority or weight, it is dynamic with respect to time. This is to say that

while at any instant in time there is always a specific order to the threads,

as time advances, this order can change. The ordering itself is determined

by the nature of the various dynamic scheduling disciplines implemented by

the Zircon scheduler.

At any specific time |now|, the order of the collection is considered to

be:

1) The deadline threads in the collection whose absolute deadlines are in the

future, sorted by ascending absolute deadline. These are the threads who

still have a chance of meeting their absolute deadline, with the nearest

absolute deadline considered to be the most important.

2) The deadline threads in the collection whose absolute deadlines are in the

past, sorted by ascending relative deadline. These are the threads who

have been blocked until after their last cycle's absolute deadline. If

all threads were to be woken |now|, the thread with the minimum relative

deadline would be the thread which has the new absolute deadline across

the set.

3) The fair threads in the collection, sorted by their "virtual finish time".

This is equal to the start time of the thread plus the scheduler's maximum

target latency divided by the thread's weight (normalized to the range

(0.0, 1.0]. This is the same ordering imposed by the Scheduler's RunQueue

for fair threads, and is intended to prioritize higher weight threads,

while still ensuring some level of fairness over time. The start time

represents the last time that a thread entered a run queue, and while high

weight threads will be chosen before low weight threads who arrived at

similar times, threads who arrived earlier (and have been waiting for

longer) will eventually end up being chosen, no matter how much weight

other threads in the collection have compared to it.

TODO(johngro): Instead of using the start time for the last time a

thread entered a RunQueue, should we use the time at which the thread

joined the wait queue instead?

In an attempt to make the selection of the "best" thread in a wait queue as

efficient as we can, in light of the dynamic nature of the total ordering, we

use an "augmented" WAVL tree as our data structure, much like the scheduler's

RunQueue. The tree keeps all of its threads sorted according to a primary

key representing the minimum absolute deadline or a modified version its

virtual finish time, depending on the thread's scheduling discipline).

The virtual finish time of threads is modified so that the MSB of the time is

always set. This guarantees that fair threads _always_ come after in the

sorting of threads. Note that we could have also achieved this partitioning

by tracking fair threads separately from deadline thread in a separate tree

instance. We keep things in a single tree (for now) in order to help to

minimize the size of WaitQueueCollections to help control the size of objects

in the kernel (such as the Mutex object).

There should be no serious issue with using the MSB of the sort key in this

fashion. Absolute timestamps in zircon use signed 64 bit integers, and the

monotonic clock is set at startup to start from zero, meaning that there is

no real world case where we would be searching for a deadline thread to

wake using a timestamp with the MSB set.

Finally, we also maintain an addition augmented invariant such that: For

every node (X) in the tree, the pointer to the thread with the minimum

relative deadline in the subtree headed by X is maintained as nodes are

inserted and removed.

With these invariants in place, finding the best thread to run can be

computed as follows.

1) If the left-most member of the tree has the MSB of its sorting key set,

then the thread is a fair thread, and there are _no_ deadline threads in

the tree. Additionally, this thread has the minimum virtual finish time

across all of the fair threads in the tree, and therefore is the "best"

thread to unblock. When the tree is in this state, selection is O(1).

2) Otherwise, there are deadline threads in the tree. The tree is searched

to find the first thread whose absolute deadline is in the future,

relative to |now|. If such a thread exists, then it is the "best" thread

to run right now and it is selected. When the tree is in this state,

selection is O(log).

3) If there are no threads whose deadlines are in the future, the pointer to

the thread with the minimum relative deadline in the tree is chosen,

simply by fetching the best-in-subtree pointer maintained in |root()|.

While this operation is O(1), when the tree is this state, the over all

achieved order was O(log) because of the search which needed to happen

during step 2.

Insert and remove order for the tree should be:

1) Insertions into the tree are always O(log).

2) Unlike a typical WAVL tree, removals of a specific thread from the tree

are O(log) instead of being amortized constant. This is because of the

cost of restoring the augmented invariant after removal, which involves

walking from the point of removal up to the root of the tree.

Public Members

static Fixed kPrimaryKeyZero

Public Methods

SchedDuration MinInheritableRelativeDeadline ()

The current minimum inheritable relative deadline of the set of blocked threads.

Defined at line 160 of file ../../zircon/kernel/kernel/wait.cc

void WaitQueueCollection ()

Defined at line 271 of file ../../zircon/kernel/include/kernel/thread.h

void ~WaitQueueCollection ()

Defined at line 272 of file ../../zircon/kernel/include/kernel/thread.h

void Validate ()

Defined at line 277 of file ../../zircon/kernel/include/kernel/thread.h

uint32_t Count ()

Passthrus for the underlying container's size and is_empty methods.

Defined at line 284 of file ../../zircon/kernel/include/kernel/thread.h

bool IsEmpty ()

Defined at line 285 of file ../../zircon/kernel/include/kernel/thread.h

Thread & PeekOnlyThread ()

Defined at line 290 of file ../../zircon/kernel/include/kernel/thread.h

Thread * PeekFront ()

Peek at the first Thread in the collection.

Defined at line 296 of file ../../zircon/kernel/include/kernel/thread.h

const Thread * PeekFront ()

Defined at line 297 of file ../../zircon/kernel/include/kernel/thread.h

SchedulerState::WaitQueueInheritedSchedulerState * FindInheritedSchedulerStateStorage ()

Defined at line 2092 of file ../../zircon/kernel/include/kernel/thread.h

void Insert (Thread * thread)

Add the Thread into its sorted location in the collection.

Defined at line 171 of file ../../zircon/kernel/kernel/wait.cc

void Remove (Thread * thread)

Remove the Thread from the collection.

Defined at line 183 of file ../../zircon/kernel/kernel/wait.cc

ChainLock::Result LockAll ()

Either lock every thread in the collection, or failed with

ChainLock::Result::Backoff, releasing any locks which were obtained in the

process. ASSERTs if any cycles are detected by the ChainLock. Used by

WaitQueue WakeAll. Note that it is not possible to statically annotated

this, and needs to be used with extreme care. If LockAll returns success,

it is critical that the caller (eventually) drops all of the locks.

Defined at line 197 of file ../../zircon/kernel/kernel/wait.cc

const BlockedThreadTree & threads ()

Accessor for the underlying thread collection.

Defined at line 316 of file ../../zircon/kernel/include/kernel/thread.h

BlockedThreadTree & threads ()

Defined at line 317 of file ../../zircon/kernel/include/kernel/thread.h

void WaitQueueCollection (const WaitQueueCollection & )

Disallow copying and moving.

Defined at line 320 of file ../../zircon/kernel/include/kernel/thread.h

WaitQueueCollection & operator= (const WaitQueueCollection & )

Defined at line 321 of file ../../zircon/kernel/include/kernel/thread.h

void WaitQueueCollection (WaitQueueCollection && )

Defined at line 323 of file ../../zircon/kernel/include/kernel/thread.h

WaitQueueCollection & operator= (WaitQueueCollection && )

Defined at line 324 of file ../../zircon/kernel/include/kernel/thread.h

Records