Skip to content

Commit

Permalink
Temp
Browse files Browse the repository at this point in the history
Signed-off-by: Klim Tsoutsman <klim@tsoutsman.com>
  • Loading branch information
tsoutsman committed Jan 4, 2024
1 parent 67b064b commit 6ed96c3
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions kernel/scheduler_epoch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"

[dependencies]
bit_set = { path = "../../libs/bit_set" }
kernel_config = { path = "../kernel_config" }
log = "0.4.8"
spin = "0.9.4"
task = { path = "../task" }
Expand Down
56 changes: 53 additions & 3 deletions kernel/scheduler_epoch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
//! The implementation is based on the [`O(1)` Linux
//! scheduler][linux-scheduler].
//!
//! The scheduler is comprised of two run queues: an .
//!
//! [linux-scheduler]: https://litux.nl/mirror/kerneldevelopment/0672327201/ch04lev1sec2.html

#![no_std]
Expand All @@ -16,6 +18,7 @@ use alloc::{boxed::Box, vec::Vec};
use core::{
mem,
ops::{Deref, DerefMut},
time::Duration,
};

use task::TaskRef;
Expand All @@ -24,13 +27,20 @@ use crate::queue::RunQueue;

const MAX_PRIORITY: u8 = 63;
const DEFAULT_PRIORITY: u8 = 20;
const INITIAL_TOKENS: usize = 0;

/// An instance of an epoch scheduler, typically one per CPU.
/// The minimum amount of time for every runnable task to run.
///
/// This is not strictly adhered to when the tasks are run
const TARGET_LATENCY: Duration = Duration::from_millis(15);

/// An epoch scheduler.
///
/// See crate-level docs for more information.
pub struct Scheduler {
idle_task: TaskRef,
active: RunQueue,
expired: RunQueue,
total_weight: usize,
}

impl Scheduler {
Expand All @@ -40,6 +50,8 @@ impl Scheduler {
idle_task,
active: RunQueue::new(),
expired: RunQueue::new(),
// TODO: 0 or 1
total_weight: 0,
}
}

Expand Down Expand Up @@ -81,6 +93,7 @@ impl<T> Returnable for Option<T> {
}

impl task::scheduler::Scheduler for Scheduler {
#[inline]
fn next(&mut self) -> TaskRef {
if self.active.is_empty() {
if !self.expired.is_empty() {
Expand All @@ -94,23 +107,29 @@ impl task::scheduler::Scheduler for Scheduler {
.unwrap_or(self.idle_task.clone())
}

#[inline]
fn add(&mut self, task: TaskRef) {
let task = EpochTaskRef::new(task);
let (task, weight) = EpochTaskRef::new(task, self.total_weight);
self.total_weight += weight;
self.expired.push(task, DEFAULT_PRIORITY);
}

#[inline]
fn busyness(&self) -> usize {
self.active.len() + self.expired.len()
}

#[inline]
fn remove(&mut self, task: &TaskRef) -> bool {
self.apply(|run_queue| run_queue.remove(task))
}

#[inline]
fn as_priority_scheduler(&mut self) -> Option<&mut dyn task::scheduler::PriorityScheduler> {
Some(self)
}

#[inline]
fn drain(&mut self) -> Box<dyn Iterator<Item = TaskRef> + '_> {
let mut active = RunQueue::new();
let mut expired = RunQueue::new();
Expand All @@ -121,6 +140,7 @@ impl task::scheduler::Scheduler for Scheduler {
Box::new(active.drain().chain(expired.drain()))
}

#[inline]
fn tasks(&self) -> Vec<TaskRef> {
self.active
.clone()
Expand All @@ -131,11 +151,13 @@ impl task::scheduler::Scheduler for Scheduler {
}

impl task::scheduler::PriorityScheduler for Scheduler {
#[inline]
fn set_priority(&mut self, task: &TaskRef, priority: u8) -> bool {
let priority = core::cmp::min(priority, MAX_PRIORITY);
self.apply(|run_queue| run_queue.set_priority(task, priority))
}

#[inline]
fn priority(&mut self, task: &TaskRef) -> Option<u8> {
self.apply(|run_queue| run_queue.priority(task))
}
Expand All @@ -147,21 +169,48 @@ struct EpochTaskRef {
tokens: usize,
}

impl EpochTaskRef {
#[must_use]
pub(crate) fn new(task: TaskRef, config: TaskConfiguration) -> (Self, usize) {
const NUM_TOKENS: usize =
TARGET_LATENCY / kernel_config::time::CONFIG_TIMESLICE_PERIOD_MICROSECONDS;

// TODO
let weight = config.priority + 1;

(
Self {
task,
tokens: core::cmp::max(NUM_TOKENS * weight / config.total_weight, 1),
},
weight,
)
}
}

pub(crate) struct TaskConfiguration {
pub(crate) priority: usize,
pub(crate) total_weight: usize,
}

impl Deref for EpochTaskRef {
type Target = TaskRef;

#[inline]
fn deref(&self) -> &TaskRef {
&self.task
}
}

impl DerefMut for EpochTaskRef {
#[inline]
fn deref_mut(&mut self) -> &mut TaskRef {
&mut self.task
}
}

impl EpochTaskRef {
#[inline]
fn new(task: TaskRef) -> EpochTaskRef {
EpochTaskRef {
task,
Expand All @@ -171,6 +220,7 @@ impl EpochTaskRef {
}

impl From<EpochTaskRef> for TaskRef {
#[inline]
fn from(value: EpochTaskRef) -> Self {
value.task
}
Expand Down
14 changes: 14 additions & 0 deletions kernel/scheduler_epoch/src/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use task::TaskRef;

use crate::{EpochTaskRef, MAX_PRIORITY};

/// A singular run queue.
///
/// The scheduler contains two of these: an active one, and an expired one.
#[derive(Debug, Clone)]
pub(crate) struct RunQueue {
// TODO: Encode using MAX_PRIORITY
Expand All @@ -14,6 +17,7 @@ pub(crate) struct RunQueue {
}

impl RunQueue {
#[inline]
pub(crate) const fn new() -> Self {
const INIT: VecDeque<EpochTaskRef> = VecDeque::new();

Expand All @@ -24,20 +28,25 @@ impl RunQueue {
}
}

#[inline]
pub(crate) const fn len(&self) -> usize {
debug_assert_eq!(self.inner.iter().map(|queue| queue.len()).sum(), self.len);
self.len
}

#[inline]
pub(crate) const fn is_empty(&self) -> bool {
self.len() == 0
}

#[inline]
pub(crate) fn push(&mut self, task: EpochTaskRef, priority: u8) {
self.priorities.insert(priority);
self.inner[priority as usize].push_back(task);
self.len += 1;
}

#[inline]
pub(crate) fn next(&mut self, expired: &mut Self) -> Option<TaskRef> {
loop {
let top_index = self.top_index()?;
Expand Down Expand Up @@ -71,10 +80,12 @@ impl RunQueue {
}
}

#[inline]
fn top_index(&self) -> Option<usize> {
self.priorities.max().map(|priority| priority as usize)
}

#[inline]
pub(crate) fn remove(&mut self, task: &TaskRef) -> bool {
for i in self.priorities.iter() {
let queue = &mut self.inner[i];
Expand All @@ -98,6 +109,7 @@ impl RunQueue {
}

/// Returns the priority of the given task.
#[inline]
pub(crate) fn priority(&self, task: &TaskRef) -> Option<u8> {
for i in self.priorities.iter() {
let queue = &self.inner[i];
Expand All @@ -114,6 +126,7 @@ impl RunQueue {
///
/// Returns `true` if an action was performed i.e. if the task was in the
/// run queue.
#[inline]
pub(crate) fn set_priority(&mut self, task: &TaskRef, priority: u8) -> bool {
for i in self.priorities.iter() {
let queue = &mut self.inner[i];
Expand All @@ -137,6 +150,7 @@ impl RunQueue {
false
}

#[inline]
pub(crate) fn drain(self) -> Drain {
Drain { inner: self }
}
Expand Down

0 comments on commit 6ed96c3

Please sign in to comment.