blob: 304137e64ea1e2f409b780ec7a67f43f0c67c7a2 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <zircon/types.h>
#include <fbl/intrusive_wavl_tree.h>
#include <ffl/fixed.h>
#include <utility>
// Forward declaration.
typedef struct thread thread_t;
// Fixed-point task weight.
//
// The 16bit fractional component accommodates the exponential curve defining
// the priority-to-weight relation:
//
// Weight = 1.225^(Priority - 31)
//
// This yields roughly 10% bandwidth difference between adjacent priorities.
//
// Weights should not be negative, however, the value is signed for consistency
// with zx_time_t (SchedTime) and zx_duration_t (SchedDuration), which are the
// primary types used in conjunction with SchedWeight. This is to make it less
// likely that expressions involving weights are accidentally promoted to
// unsigned.
using SchedWeight = ffl::Fixed<int64_t, 16>;
// Fixed-point types wrapping time and duration types to make time expressions
// cleaner in the scheduler code.
using SchedDuration = ffl::Fixed<zx_duration_t, 0>;
using SchedTime = ffl::Fixed<zx_time_t, 0>;
// Utilities that return fixed-point Expression representing the given integer
// time units in terms of system time units (nanoseconds).
template <typename T>
constexpr auto SchedNs(T nanoseconds) {
return ffl::FromInteger(ZX_NSEC(nanoseconds));
}
template <typename T>
constexpr auto SchedUs(T microseconds) {
return ffl::FromInteger(ZX_USEC(microseconds));
}
template <typename T>
constexpr auto SchedMs(T milliseconds) {
return ffl::FromInteger(ZX_MSEC(milliseconds));
}
// Per-thread state used by FairScheduler.
class FairTaskState {
public:
// The key type of this node operated on by WAVLTree.
using KeyType = std::pair<SchedTime, uint64_t>;
FairTaskState() = default;
explicit FairTaskState(SchedWeight weight)
: weight_{weight} {}
FairTaskState(const FairTaskState&) = delete;
FairTaskState& operator=(const FairTaskState&) = delete;
SchedWeight weight() const { return weight_; }
// Returns the key used to order the run queue.
KeyType key() const { return {virtual_finish_time_, generation_}; }
// Returns true of the task state is currently enqueued in the runnable tree.
bool InQueue() const {
return run_queue_node_.InContainer();
}
// Returns true if the task is active (queued or running) on a run queue.
bool active() const { return active_; }
// Sets the task state to active (on a run queue). Returns true if the task
// was not previously active.
bool OnInsert() {
const bool was_active = active_;
active_ = true;
return !was_active;
}
// Sets the task state to inactive (not on a run queue). Returns true if the
// task was previously active.
bool OnRemove() {
const bool was_active = active_;
active_ = false;
return was_active;
}
// Returns the generation count from the last time the thread was enqueued
// in the runnable tree.
uint64_t generation() const { return generation_; }
private:
friend class FairScheduler;
// WAVLTree node state.
fbl::WAVLTreeNodeState<thread_t*> run_queue_node_;
// The current weight of the thread.
SchedWeight weight_{0};
// Flag indicating whether this thread is associated with a runqueue.
bool active_{false};
// TODO(eieio): Some of the values below are only relevant when running,
// while others only while ready. Consider using a union to save space.
// The virtual time of the thread's current bandwidth request.
SchedTime virtual_start_time_{0};
// The virtual finish time of the thread's current bandwidth request.
SchedTime virtual_finish_time_{0};
// The current timeslice allocated to the thread.
SchedDuration time_slice_ns_{0};
// The remainder of timeslice allocated to the thread when it blocked.
SchedDuration lag_time_ns_{0};
// Takes the value of FairScheduler::generation_count_ + 1 at the time this
// node is added to the run queue.
uint64_t generation_{0};
};