Skip to content

Commit 69871f6

Browse files
committed
refactor(kernel): wrap running_task with CpuLockCell instead of AtomicRef
`::atomic_ref` doesn't build for an Armv6-M target (because of atomics limitations), so making this change is necessary to support Armv6-M.
1 parent f4a30bf commit 69871f6

File tree

7 files changed

+67
-51
lines changed

7 files changed

+67
-51
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/constance/Cargo.toml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,6 @@ tokenlock = { version = "0.3.0", default-features = false }
2020
bitflags = { version = "1.2.1" }
2121
chrono = { version = "0.4.13", optional = true, default-features = false }
2222

23-
[dependencies.atomic_ref]
24-
# - “Make the crate `no_std`”
25-
# <https://github.com/mystor/atomic_ref/pull/1>
26-
# - “Make `AtomicRef::new` `const fn` (nightly-only)”
27-
# <https://github.com/mystor/atomic_ref/pull/2>
28-
git = "https://github.com/yvt/atomic_ref.git"
29-
rev = "37523c17a2a535f4d04c204d65d2742647abed25"
30-
features = ["nightly"]
31-
3223
[dev-dependencies]
3324
quickcheck_macros = "0.9.1"
3425
env_logger = "0.7.1"

src/constance/src/kernel.rs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//! The RTOS kernel
2-
use atomic_ref::AtomicRef;
32
use core::{
43
borrow::BorrowMut,
54
fmt,
@@ -634,7 +633,7 @@ pub trait PortToKernel {
634633
// TODO: Explain phases
635634
unsafe fn boot() -> !;
636635

637-
/// Determine the next task to run and store it in [`State::running_task_ref`].
636+
/// Determine the next task to run and store it in [`State::running_task_ptr`].
638637
///
639638
/// Precondition: CPU Lock active / Postcondition: CPU Lock active
640639
unsafe fn choose_running_task();
@@ -800,7 +799,8 @@ pub struct State<
800799
> {
801800
/// The currently or recently running task. Can be in a Running or Waiting
802801
/// state.
803-
running_task: AtomicRef<'static, TaskCb<System, PortTaskState, TaskPriority>>,
802+
running_task:
803+
utils::CpuLockCell<System, Option<&'static TaskCb<System, PortTaskState, TaskPriority>>>,
804804

805805
/// The task ready bitmap, in which each bit indicates whether the
806806
/// task ready queue corresponding to that bit contains a task or not.
@@ -831,7 +831,7 @@ impl<
831831
for State<System, PortTaskState, TaskReadyBitmap, TaskReadyQueue, TaskPriority, TimeoutHeap>
832832
{
833833
const INIT: Self = Self {
834-
running_task: AtomicRef::new(None),
834+
running_task: utils::CpuLockCell::new(None),
835835
task_ready_bitmap: Init::INIT,
836836
task_ready_queue: Init::INIT,
837837
priority_boost: AtomicBool::new(false),
@@ -862,16 +862,28 @@ impl<
862862

863863
impl<System: KernelCfg2> State<System> {
864864
/// Get the currently running task.
865-
pub fn running_task(&self) -> Option<&'static TaskCb<System>> {
866-
self.running_task.load(Ordering::Relaxed)
865+
#[inline]
866+
fn running_task(
867+
&self,
868+
lock: utils::CpuLockGuardBorrowMut<System>,
869+
) -> Option<&'static TaskCb<System>> {
870+
*self.running_task.read(&*lock)
867871
}
868872

869-
/// Get a reference to the variable storing the currently running task.
870-
///
871-
/// # Safety
872-
///
873-
/// Modifying the stored value is not allowed.
874-
pub unsafe fn running_task_ref(&self) -> &AtomicRef<'static, TaskCb<System>> {
875-
&self.running_task
873+
/// Get a pointer to the variable storing the currently running task.
874+
///
875+
/// Reading the variable is safe as long as the read is free of data race.
876+
/// Note that only the dispatcher (that calls
877+
/// [`PortToKernel::choose_running_task`]) can modify the variable
878+
/// asynchonously. For example, it's safe to read it in a task context. It's
879+
/// also safe to read it in the dispatcher. On the other hand, reading it in
880+
/// a non-task context (except for the dispatcher, of course) may lead to
881+
/// an undefined behavior unless CPU Lock is activated while reading the
882+
/// variable.
883+
///
884+
/// Writing the variable is not allowed.
885+
#[inline]
886+
pub fn running_task_ptr(&self) -> *mut Option<&'static TaskCb<System>> {
887+
self.running_task.as_ptr()
876888
}
877889
}

src/constance/src/kernel/task.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ impl<System: Kernel> Task<System> {
135135
/// handler could be interrupted by another interrrupt, which might do
136136
/// scheduling on return (whether this happens or not is unspecified).
137137
pub fn current() -> Result<Option<Self>, GetCurrentTaskError> {
138-
let _lock = utils::lock_cpu::<System>()?;
139-
let task_cb = if let Some(cb) = System::state().running_task() {
138+
let mut lock = utils::lock_cpu::<System>()?;
139+
let task_cb = if let Some(cb) = System::state().running_task(lock.borrow_mut()) {
140140
cb
141141
} else {
142142
return Ok(None);
@@ -425,12 +425,12 @@ pub(super) unsafe fn exit_current_task<System: Kernel>() -> Result<!, ExitTaskEr
425425
.store(false, Ordering::Release);
426426

427427
// Transition the current task to Dormant
428-
let running_task = System::state().running_task().unwrap();
428+
let running_task = System::state().running_task(lock.borrow_mut()).unwrap();
429429
assert_eq!(*running_task.st.read(&*lock), TaskSt::Running);
430430
running_task.st.replace(&mut *lock, TaskSt::Dormant);
431431

432432
// Erase `running_task`
433-
System::state().running_task.store(None, Ordering::Relaxed);
433+
System::state().running_task.replace(&mut *lock, None);
434434

435435
core::mem::forget(lock);
436436

@@ -551,22 +551,29 @@ pub(super) unsafe fn make_ready<System: Kernel>(
551551
///
552552
/// System services that transition a task into the Ready state should call
553553
/// this before returning to the caller.
554-
pub(super) fn unlock_cpu_and_check_preemption<System: Kernel>(lock: utils::CpuLockGuard<System>) {
554+
pub(super) fn unlock_cpu_and_check_preemption<System: Kernel>(
555+
mut lock: utils::CpuLockGuard<System>,
556+
) {
555557
// If Priority Boost is active, treat the currently running task as the
556558
// highest-priority task.
557559
if System::is_priority_boost_active() {
558560
debug_assert_eq!(
559-
*System::state().running_task().unwrap().st.read(&*lock),
561+
*System::state()
562+
.running_task(lock.borrow_mut())
563+
.unwrap()
564+
.st
565+
.read(&*lock),
560566
TaskSt::Running
561567
);
562568
return;
563569
}
564570

565-
let prev_task_priority = if let Some(running_task) = System::state().running_task() {
566-
running_task.priority.read(&*lock).to_usize().unwrap()
567-
} else {
568-
usize::MAX
569-
};
571+
let prev_task_priority =
572+
if let Some(running_task) = System::state().running_task(lock.borrow_mut()) {
573+
running_task.priority.read(&*lock).to_usize().unwrap()
574+
} else {
575+
usize::MAX
576+
};
570577

571578
// The priority of the next task to run
572579
let next_task_priority = System::state()
@@ -593,14 +600,18 @@ pub(super) fn choose_next_running_task<System: Kernel>(
593600
if System::is_priority_boost_active() {
594601
// Blocking system calls aren't allowed when Priority Boost is active
595602
debug_assert_eq!(
596-
*System::state().running_task().unwrap().st.read(&*lock),
603+
*System::state()
604+
.running_task(lock.borrow_mut())
605+
.unwrap()
606+
.st
607+
.read(&*lock),
597608
TaskSt::Running
598609
);
599610
return;
600611
}
601612

602613
// The priority of `running_task`
603-
let prev_running_task = System::state().running_task();
614+
let prev_running_task = System::state().running_task(lock.borrow_mut());
604615
let prev_task_priority = if let Some(running_task) = prev_running_task {
605616
if *running_task.st.read(&*lock) == TaskSt::Running {
606617
running_task.priority.read(&*lock).to_usize().unwrap()
@@ -675,7 +686,7 @@ pub(super) fn choose_next_running_task<System: Kernel>(
675686

676687
System::state()
677688
.running_task
678-
.store(next_running_task, Ordering::Relaxed);
689+
.replace(&mut *lock, next_running_task);
679690
}
680691

681692
/// Transition the currently running task into the Waiting state. Returns when
@@ -691,7 +702,7 @@ pub(super) fn wait_until_woken_up<System: Kernel>(
691702
debug_assert_eq!(state::expect_waitable_context::<System>(), Ok(()));
692703

693704
// Transition the current task to Waiting
694-
let running_task = System::state().running_task().unwrap();
705+
let running_task = System::state().running_task(lock.borrow_mut()).unwrap();
695706
assert_eq!(*running_task.st.read(&*lock), TaskSt::Running);
696707
running_task.st.replace(&mut *lock, TaskSt::Waiting);
697708

@@ -720,7 +731,7 @@ pub(super) fn park_current_task<System: Kernel>() -> Result<(), ParkError> {
720731
let mut lock = utils::lock_cpu::<System>()?;
721732
state::expect_waitable_context::<System>()?;
722733

723-
let running_task = System::state().running_task().unwrap();
734+
let running_task = System::state().running_task(lock.borrow_mut()).unwrap();
724735

725736
// If the task already has a park token, return immediately
726737
if running_task.park_token.replace(&mut *lock, false) {
@@ -741,7 +752,7 @@ pub(super) fn park_current_task_timeout<System: Kernel>(
741752
let mut lock = utils::lock_cpu::<System>()?;
742753
state::expect_waitable_context::<System>()?;
743754

744-
let running_task = System::state().running_task().unwrap();
755+
let running_task = System::state().running_task(lock.borrow_mut()).unwrap();
745756

746757
// If the task already has a park token, return immediately
747758
if running_task.park_token.replace(&mut *lock, false) {

src/constance/src/kernel/wait.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,10 @@ impl<System: Kernel> WaitQueue<System> {
220220
#[inline]
221221
pub(super) fn wait(
222222
&'static self,
223-
lock: CpuLockGuardBorrowMut<'_, System>,
223+
mut lock: CpuLockGuardBorrowMut<'_, System>,
224224
payload: WaitPayload<System>,
225225
) -> Result<WaitPayload<System>, WaitError> {
226-
let task = System::state().running_task().unwrap();
226+
let task = System::state().running_task(lock.borrow_mut()).unwrap();
227227
let wait = Wait {
228228
task,
229229
link: CpuLockCell::new(None),
@@ -252,7 +252,7 @@ impl<System: Kernel> WaitQueue<System> {
252252
payload: WaitPayload<System>,
253253
duration_time32: timeout::Time32,
254254
) -> Result<WaitPayload<System>, WaitTimeoutError> {
255-
let task = System::state().running_task().unwrap();
255+
let task = System::state().running_task(lock.borrow_mut()).unwrap();
256256
let wait = Wait {
257257
task,
258258
link: CpuLockCell::new(None),
@@ -283,7 +283,7 @@ impl<System: Kernel> WaitQueue<System> {
283283

284284
debug_assert!(core::ptr::eq(
285285
wait.task,
286-
System::state().running_task().unwrap()
286+
System::state().running_task(lock.borrow_mut()).unwrap()
287287
));
288288
debug_assert!(core::ptr::eq(wait.wait_queue.unwrap(), self));
289289

@@ -517,10 +517,10 @@ pub(super) fn reorder_wait_of_task<System: Kernel>(
517517
/// [waitable]: crate#contexts
518518
#[inline]
519519
pub(super) fn wait_no_queue<System: Kernel>(
520-
lock: CpuLockGuardBorrowMut<'_, System>,
520+
mut lock: CpuLockGuardBorrowMut<'_, System>,
521521
payload: WaitPayload<System>,
522522
) -> Result<WaitPayload<System>, WaitError> {
523-
let task = System::state().running_task().unwrap();
523+
let task = System::state().running_task(lock.borrow_mut()).unwrap();
524524
let wait = Wait {
525525
task,
526526
link: CpuLockCell::new(None),
@@ -550,7 +550,7 @@ pub(super) fn wait_no_queue_timeout<System: Kernel>(
550550
payload: WaitPayload<System>,
551551
duration_time32: timeout::Time32,
552552
) -> Result<WaitPayload<System>, WaitTimeoutError> {
553-
let task = System::state().running_task().unwrap();
553+
let task = System::state().running_task(lock.borrow_mut()).unwrap();
554554
let wait = Wait {
555555
task,
556556
link: CpuLockCell::new(None),
@@ -580,7 +580,7 @@ fn wait_no_queue_inner<System: Kernel>(
580580

581581
debug_assert!(core::ptr::eq(
582582
wait.task,
583-
System::state().running_task().unwrap()
583+
System::state().running_task(lock.borrow_mut()).unwrap()
584584
));
585585
debug_assert!(wait.wait_queue.is_none());
586586
debug_assert!(wait.link.read(&*lock).is_none());

src/constance_port_arm_m/src/threading.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ impl State {
204204
// - This is the top-level function in the PendSV handler. That is,
205205
// the compiler must really inline `handle_pend_sv`.
206206

207-
let running_task_ref = unsafe { System::state().running_task_ref() };
207+
let running_task_ptr = System::state().running_task_ptr();
208208

209209
extern "C" fn choose_next_task<System: PortInstance>() {
210210
// Choose the next task to run
@@ -289,7 +289,7 @@ impl State {
289289
msr control, r0
290290
"
291291
:
292-
: "{r0}"(running_task_ref)
292+
: "{r0}"(running_task_ptr)
293293
, "X"(choose_next_task::<System> as extern fn())
294294
:
295295
: "volatile");

src/constance_port_std/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,10 @@ impl State {
342342
let mut lock = self.thread_group.get().unwrap().lock();
343343

344344
// Tell the scheduler which task to run next
345-
lock.scheduler().task_thread = if let Some(task) = System::state().running_task() {
345+
// Safety: `running_task` is only modified by `choose_running_task`, so
346+
// there's no data race
347+
let running_task = unsafe { *System::state().running_task_ptr() };
348+
lock.scheduler().task_thread = if let Some(task) = running_task {
346349
log::trace!("dispatching task {:p}", task);
347350

348351
let mut tsm = task.port_task_state.tsm.lock();

0 commit comments

Comments
 (0)