Skip to content

Commit bb66e6a

Browse files
authored
task_switch: explicitly drop current task's TLS reference (#989)
* This change ensures that the `CURRENT_TASK` TLS variable that is used in task switching is dropped *before* switching to the next task, in order to ensure that `RefCell`'s runtime borrowing mechanic always works across task switches.
1 parent 18dc5f5 commit bb66e6a

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

kernel/task/src/lib.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use alloc::{
3737
};
3838
use core::{
3939
any::Any,
40+
cell::RefMut,
4041
fmt,
4142
hash::{Hash, Hasher},
4243
ops::Deref,
@@ -810,12 +811,12 @@ type TaskSwitchInnerRet = (*mut usize, usize, SimdExt, SimdExt);
810811
/// Hence, the the main [`task_switch()`] routine proceeds with the context switch
811812
/// after we return to it from this function.
812813
fn task_switch_inner(
813-
curr_task_tls_slot: &mut Option<TaskRef>,
814+
mut curr_task_tls_slot: RefMut<'_, Option<TaskRef>>,
814815
next: TaskRef,
815816
cpu_id: CpuId,
816817
preemption_guard: PreemptionGuard,
817818
) -> Result<TaskSwitchInnerRet, (bool, PreemptionGuard)> {
818-
let Some(ref curr) = curr_task_tls_slot else {
819+
let Some(curr) = curr_task_tls_slot.as_ref() else {
819820
error!("BUG: task_switch_inner(): couldn't get current task");
820821
return Err((false, preemption_guard));
821822
};
@@ -825,7 +826,7 @@ fn task_switch_inner(
825826
return Err((false, preemption_guard));
826827
}
827828

828-
// trace!("task_switch [0]: (CPU {}) prev {:?}, next {:?}, interrupts?: {}", cpu_id, curr, next, irq_safety::interrupts_enabled());
829+
// log::trace!("task_switch [0]: (CPU {}) prev {:?}, next {:?}, interrupts?: {}", cpu_id, curr, next, irq_safety::interrupts_enabled());
829830

830831
// These conditions are checked elsewhere, but can be re-enabled if we want to be extra strict.
831832
// if !next.is_runnable() {
@@ -908,11 +909,15 @@ fn task_switch_inner(
908909
// We store the removed `TaskRef` in CPU-local storage so that it remains accessible
909910
// until *after* the context switch.
910911
if curr_task_has_exited {
911-
// trace!("task_switch(): deiniting current task TLS for: {:?}, next: {}", curr_task_tls_slot.as_deref(), next.deref());
912+
// log::trace!("[CPU {}] task_switch(): deiniting current task TLS for: {:?}, next: {}", cpu_id, curr_task_tls_slot.as_deref(), next.deref());
912913
let prev_taskref = curr_task_tls_slot.take();
913914
DROP_AFTER_TASK_SWITCH.with_mut(|d| d.0 = prev_taskref);
914915
}
915916

917+
// Now we are done touching the current task's TLS slot, so proactively drop it now
918+
// to ensure that it isn't accidentally dropped later after we've switched the active TLS area.
919+
drop(curr_task_tls_slot);
920+
916921
// Now, set the next task as the current task running on this CPU.
917922
//
918923
// Note that we cannot do this until we've done the above part that cleans up
@@ -1129,7 +1134,9 @@ mod tls_current_task {
11291134
Ok(ExitableTaskRef { task: taskref })
11301135
}
11311136
Err(_e) => {
1132-
log::error!("BUG: init_current_task() failed to mutably borrow CURRENT_TASK");
1137+
log::error!("[CPU {}] BUG: init_current_task(): failed to mutably borrow CURRENT_TASK. \
1138+
Task ID: {}, {:?}", cpu::current_cpu(), current_task_id, taskref,
1139+
);
11331140
Err(InitCurrentTaskError::AlreadyBorrowed(current_task_id))
11341141
}
11351142
}
@@ -1145,9 +1152,9 @@ mod tls_current_task {
11451152
/// Returns an `Err` containing the `value` if the current task cannot be obtained.
11461153
pub(crate) fn with_current_task_tls_slot_mut<F, R, T>(function: F, value: T) -> Result<R, T>
11471154
where
1148-
F: FnOnce(&mut Option<TaskRef>, T) -> R
1155+
F: FnOnce(core::cell::RefMut<'_, Option<TaskRef>>, T) -> R
11491156
{
1150-
if let Ok(tls_slot) = CURRENT_TASK.try_borrow_mut().as_deref_mut() {
1157+
if let Ok(tls_slot) = CURRENT_TASK.try_borrow_mut() {
11511158
Ok(function(tls_slot, value))
11521159
} else {
11531160
Err(value)

0 commit comments

Comments
 (0)