Skip to content

Commit

Permalink
Merge branch 'runqueue/multiple-cores' of github.com:elenaf9/RIOT-rs …
Browse files Browse the repository at this point in the history
…into threads/rp2040-multicore
  • Loading branch information
elenaf9 committed Apr 30, 2024
2 parents 6b140a1 + 441611e commit 3b326e9
Show file tree
Hide file tree
Showing 4 changed files with 270 additions and 201 deletions.
171 changes: 86 additions & 85 deletions src/riot-rs-runqueue/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#![cfg_attr(not(test), no_std)]
#![feature(min_specialization)]

mod runqueue;
pub use runqueue::{CoreId, RunQueue, RunqueueId, ThreadId};
pub use runqueue::{CoreId, GlobalRunqueue, RunQueue, RunqueueId, ThreadId};

#[cfg(test)]
mod tests {
Expand All @@ -15,24 +16,24 @@ mod tests {
runqueue.add(1, 0);
runqueue.add(2, 0);

assert_eq!(runqueue.get_next(), Some(0));
assert_eq!(runqueue.get_next(0), Some(0));

runqueue.advance(0);
runqueue.advance(0, 0);

assert_eq!(runqueue.get_next(), Some(1));
runqueue.advance(0);
assert_eq!(runqueue.get_next(0), Some(1));
runqueue.advance(0, 0);

assert_eq!(runqueue.get_next(), Some(2));
assert_eq!(runqueue.get_next(), Some(2));
assert_eq!(runqueue.get_next(0), Some(2));
assert_eq!(runqueue.get_next(0), Some(2));

runqueue.advance(0);
assert_eq!(runqueue.get_next(), Some(0));
runqueue.advance(0, 0);
assert_eq!(runqueue.get_next(0), Some(0));

runqueue.advance(0);
assert_eq!(runqueue.get_next(), Some(1));
runqueue.advance(0, 0);
assert_eq!(runqueue.get_next(0), Some(1));

runqueue.advance(0);
assert_eq!(runqueue.get_next(), Some(2));
runqueue.advance(0, 0);
assert_eq!(runqueue.get_next(0), Some(2));
}

#[test]
Expand All @@ -44,13 +45,13 @@ mod tests {
}

for i in 0..=31 {
assert_eq!(runqueue.get_next(), Some(i));
runqueue.advance(0);
assert_eq!(runqueue.get_next(0), Some(i));
runqueue.advance(0, 0);
}

for i in 0..=31 {
assert_eq!(runqueue.get_next(), Some(i));
runqueue.advance(0);
assert_eq!(runqueue.get_next(0), Some(i));
runqueue.advance(0, 0);
}
}

Expand All @@ -65,17 +66,17 @@ mod tests {
runqueue.add(2, 1);
runqueue.add(4, 1);

assert_eq!(runqueue.get_next(), Some(2));
assert_eq!(runqueue.get_next(0), Some(2));
runqueue.del(2, 1);
assert_eq!(runqueue.get_next(), Some(4));
assert_eq!(runqueue.get_next(0), Some(4));
runqueue.del(4, 1);
assert_eq!(runqueue.get_next(), Some(0));
assert_eq!(runqueue.get_next(0), Some(0));
runqueue.del(0, 0);
assert_eq!(runqueue.get_next(), Some(1));
assert_eq!(runqueue.get_next(0), Some(1));
runqueue.del(1, 0);
assert_eq!(runqueue.get_next(), Some(3));
assert_eq!(runqueue.get_next(0), Some(3));
runqueue.del(3, 0);
assert_eq!(runqueue.get_next(), None);
assert_eq!(runqueue.get_next(0), None);
}
#[test]
fn test_push_twice() {
Expand All @@ -84,16 +85,16 @@ mod tests {
runqueue.add(0, 0);
runqueue.add(1, 0);

assert_eq!(runqueue.get_next(), Some(0));
assert_eq!(runqueue.get_next(0), Some(0));
runqueue.del(0, 0);
assert_eq!(runqueue.get_next(), Some(1));
assert_eq!(runqueue.get_next(0), Some(1));

runqueue.add(0, 0);

assert_eq!(runqueue.get_next(), Some(1));
assert_eq!(runqueue.get_next(0), Some(1));

runqueue.advance(0);
assert_eq!(runqueue.get_next(), Some(0));
runqueue.advance(0, 0);
assert_eq!(runqueue.get_next(0), Some(0));
}

#[test]
Expand All @@ -105,38 +106,38 @@ mod tests {
// Second thread should get allocated to core 1.
assert_eq!(runqueue.add(1, 0), Some(1));

assert_eq!(runqueue.get_next_for_core(0), Some(0));
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert!(runqueue.get_next_for_core(2).is_none());
assert_eq!(runqueue.get_next(0), Some(0));
assert_eq!(runqueue.get_next(1), Some(1));
assert!(runqueue.get_next(2).is_none());

// Advancing a runqueue shouldn't change any allocations
// if all threads in the queue are already running.
assert_eq!(runqueue.advance_from(0, 0), None);
assert_eq!(runqueue.get_next_for_core(0), Some(0));
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert!(runqueue.get_next_for_core(2).is_none());
assert_eq!(runqueue.advance(0, 0), None);
assert_eq!(runqueue.get_next(0), Some(0));
assert_eq!(runqueue.get_next(1), Some(1));
assert!(runqueue.get_next(2).is_none());

// Restores original order.
assert_eq!(runqueue.advance_from(1, 0), None);
assert_eq!(runqueue.advance(1, 0), None);

// Add more threads, which should be allocated to free
// cores.
assert_eq!(runqueue.add(2, 0), Some(2));
assert_eq!(runqueue.add(3, 0), Some(3));
assert_eq!(runqueue.add(4, 0), None);
assert_eq!(runqueue.get_next_for_core(0), Some(0));
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(2), Some(2));
assert_eq!(runqueue.get_next_for_core(3), Some(3));
assert_eq!(runqueue.get_next(0), Some(0));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(2), Some(2));
assert_eq!(runqueue.get_next(3), Some(3));

// Advancing the runqueue now should change the mapping
// on core 0, since the previous head was running there.
assert_eq!(runqueue.advance_from(0, 0), Some(0));
assert_eq!(runqueue.get_next_for_core(0), Some(4));
assert_eq!(runqueue.advance(0, 0), Some(0));
assert_eq!(runqueue.get_next(0), Some(4));
// Other allocations shouldn't change.
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(2), Some(2));
assert_eq!(runqueue.get_next_for_core(3), Some(3));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(2), Some(2));
assert_eq!(runqueue.get_next(3), Some(3));

// Adding or deleting waiting threads shouldn't change
// any allocations.
Expand All @@ -146,11 +147,11 @@ mod tests {
// Deleting a running thread should allocate the waiting
// thread to the now free core.
assert_eq!(runqueue.del(2, 0), Some(2));
assert_eq!(runqueue.get_next_for_core(2), Some(5));
assert_eq!(runqueue.get_next(2), Some(5));
// Other allocations shouldn't change.
assert_eq!(runqueue.get_next_for_core(0), Some(4));
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(3), Some(3));
assert_eq!(runqueue.get_next(0), Some(4));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(3), Some(3));
}

#[test]
Expand All @@ -163,68 +164,68 @@ mod tests {
assert_eq!(runqueue.add(3, 0), Some(3));
assert_eq!(runqueue.add(4, 0), None);

assert_eq!(runqueue.get_next_for_core(0), Some(0));
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(2), Some(2));
assert_eq!(runqueue.get_next_for_core(3), Some(3));
assert_eq!(runqueue.get_next(0), Some(0));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(2), Some(2));
assert_eq!(runqueue.get_next(3), Some(3));

// Advancing highest priority queue shouldn't change anything
// because there are more cores than threads in this priority's queue.
assert_eq!(runqueue.advance_from(0, 2), None);
assert_eq!(runqueue.get_next_for_core(0), Some(0));
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(2), Some(2));
assert_eq!(runqueue.get_next_for_core(3), Some(3));
assert_eq!(runqueue.advance(0, 2), None);
assert_eq!(runqueue.get_next(0), Some(0));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(2), Some(2));
assert_eq!(runqueue.get_next(3), Some(3));

// Advancing lowest priority queue should change allocations
// since there are two threads in this priority's queue,
// but only one available core for them.

// Core 3 was newly allocated.
assert_eq!(runqueue.advance_from(3, 0), Some(3));
assert_eq!(runqueue.get_next_for_core(3), Some(4));
assert_eq!(runqueue.advance(3, 0), Some(3));
assert_eq!(runqueue.get_next(3), Some(4));
// Other allocations didn't change.
assert_eq!(runqueue.get_next_for_core(0), Some(0));
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(2), Some(2));
assert_eq!(runqueue.get_next(0), Some(0));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(2), Some(2));

// Restores original order.
runqueue.advance_from(4, 0);
runqueue.advance(4, 0);

// Delete one high-priority thread.
// The waiting low-priority thread should be allocated
// to the newly freed core.

// Core 0 was newly allocated.
assert_eq!(runqueue.del(0, 2), Some(0));
assert_eq!(runqueue.get_next_for_core(0), Some(4));
assert_eq!(runqueue.get_next(0), Some(4));
// Other allocations didn't change.
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(2), Some(2));
assert_eq!(runqueue.get_next_for_core(3), Some(3));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(2), Some(2));
assert_eq!(runqueue.get_next(3), Some(3));

// Add one medium-priority thread.
// The low-priority thread furthest back in its priority queue
// should be preempted.

// Core 0 was newly allocated.
assert_eq!(runqueue.add(5, 1), Some(0));
assert_eq!(runqueue.get_next_for_core(0), Some(5));
assert_eq!(runqueue.get_next(0), Some(5));
// Other allocations didn't change.
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(2), Some(2));
assert_eq!(runqueue.get_next_for_core(3), Some(3));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(2), Some(2));
assert_eq!(runqueue.get_next(3), Some(3));
}

#[test]
fn multicore_invalid_core() {
let mut runqueue: RunQueue<8, 32, 1> = RunQueue::new();
assert_eq!(runqueue.add(0, 2), Some(0));
assert_eq!(runqueue.add(1, 2), None);
assert_eq!(runqueue.get_next(), Some(0));
assert_eq!(runqueue.get_next_for_core(0), Some(0));
assert_eq!(runqueue.get_next(0), Some(0));
assert_eq!(runqueue.get_next(0), Some(0));
// Querying for n > `N_CORES` shouldn't cause a panic.
assert_eq!(runqueue.get_next_for_core(1), None)
assert_eq!(runqueue.get_next(1), None)
}

#[test]
Expand All @@ -238,19 +239,19 @@ mod tests {
assert_eq!(runqueue.add(5, 0), None);

// Advance head.
assert_eq!(runqueue.advance_from(0, 0), Some(0));
assert_eq!(runqueue.get_next_for_core(0), Some(4));
assert_eq!(runqueue.advance(0, 0), Some(0));
assert_eq!(runqueue.get_next(0), Some(4));
// Other allocations didn't change.
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(2), Some(2));
assert_eq!(runqueue.get_next_for_core(3), Some(3));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(2), Some(2));
assert_eq!(runqueue.get_next(3), Some(3));

// Advance from a thread that is not head.
assert_eq!(runqueue.advance_from(2, 0), Some(2));
assert_eq!(runqueue.get_next_for_core(2), Some(5));
assert_eq!(runqueue.advance(2, 0), Some(2));
assert_eq!(runqueue.get_next(2), Some(5));
// Other allocations didn't change.
assert_eq!(runqueue.get_next_for_core(0), Some(4));
assert_eq!(runqueue.get_next_for_core(1), Some(1));
assert_eq!(runqueue.get_next_for_core(3), Some(3));
assert_eq!(runqueue.get_next(0), Some(4));
assert_eq!(runqueue.get_next(1), Some(1));
assert_eq!(runqueue.get_next(3), Some(3));
}
}
Loading

0 comments on commit 3b326e9

Please sign in to comment.