From 3f45497a6501132847769296a1f63107ccd9efff Mon Sep 17 00:00:00 2001 From: michael Date: Tue, 11 Apr 2023 20:43:11 -0500 Subject: [PATCH 1/3] Implements PriorityTaskQueue with std's LinkedList rather than a custom linked list implementation. --- src/scheduler/task.rs | 127 +++++++----------------------------------- 1 file changed, 21 insertions(+), 106 deletions(-) diff --git a/src/scheduler/task.rs b/src/scheduler/task.rs index b126854965..93d7c73565 100644 --- a/src/scheduler/task.rs +++ b/src/scheduler/task.rs @@ -237,33 +237,18 @@ impl TaskHandlePriorityQueue { } } -#[derive(Default)] -struct QueueHead { - head: Option>>, - tail: Option>>, -} - -impl QueueHead { - pub const fn new() -> Self { - Self { - head: None, - tail: None, - } - } -} - /// Realize a priority queue for tasks pub struct PriorityTaskQueue { - queues: [QueueHead; NO_PRIORITIES], + queues: [LinkedList>>; NO_PRIORITIES], prio_bitmap: u64, } impl PriorityTaskQueue { /// Creates an empty priority queue for tasks pub const fn new() -> PriorityTaskQueue { - const QUEUE_HEAD: QueueHead = QueueHead::new(); + const EMPTY_LIST: LinkedList>> = LinkedList::new(); PriorityTaskQueue { - queues: [QUEUE_HEAD; NO_PRIORITIES], + queues: [EMPTY_LIST; NO_PRIORITIES], prio_bitmap: 0, } } @@ -274,53 +259,17 @@ impl PriorityTaskQueue { //assert!(i < NO_PRIORITIES, "Priority {} is too high", i); self.prio_bitmap |= (1 << i) as u64; - match self.queues[i].tail { - None => { - // first element in the queue - self.queues[i].head = Some(task.clone()); - - let mut borrow = task.borrow_mut(); - borrow.next = None; - borrow.prev = None; - } - Some(ref mut tail) => { - // add task at the end of the node - tail.borrow_mut().next = Some(task.clone()); - - let mut borrow = task.borrow_mut(); - borrow.next = None; - borrow.prev = Some(tail.clone()); - } - } - - self.queues[i].tail = Some(task); + let queue = &mut self.queues[i]; + queue.push_back(task); } fn pop_from_queue(&mut self, queue_index: usize) -> Option>> { - let (new_head, task) = { - let head = self.queues[queue_index].head.as_mut()?; - let mut borrow = head.borrow_mut(); - - if let Some(ref mut nhead) = borrow.next { - nhead.borrow_mut().prev = None; - } - - let new_head = borrow.next.clone(); - borrow.next = None; - borrow.prev = None; - - let task = head.clone(); - - (new_head, task) - }; - - self.queues[queue_index].head = new_head; - if self.queues[queue_index].head.is_none() { - self.queues[queue_index].tail = None; + let task = self.queues[queue_index].pop_back(); + if self.queues[queue_index].is_empty() { self.prio_bitmap &= !(1 << queue_index as u64); } - Some(task) + task } /// Pop the task with the highest priority from the queue @@ -356,49 +305,23 @@ impl PriorityTaskQueue { /// Change priority of specific task pub fn set_priority(&mut self, handle: TaskHandle, prio: Priority) -> Result<(), ()> { let i = handle.get_priority().into() as usize; - let mut pos = self.queues[i].head.as_mut().ok_or(())?; - - loop { - if handle.id == pos.borrow().id { - let task = pos.clone(); - - // Extract found task from queue and set new priority - { - let mut borrow = task.borrow_mut(); - - let new = borrow.next.as_ref().cloned(); - if let Some(prev) = borrow.prev.as_mut() { - prev.borrow_mut().next = new; - } - - let new = borrow.prev.as_ref().cloned(); - if let Some(next) = borrow.next.as_mut() { - next.borrow_mut().prev = new; - } - - if borrow.prev.as_mut().is_none() { - // Ok, the task is head of the list - self.queues[i].head = borrow.next.as_ref().cloned(); - } - - if borrow.next.as_mut().is_none() { - // Ok, the task is tail of the list - self.queues[i].tail = borrow.prev.as_ref().cloned(); - } - - borrow.prio = prio; - borrow.next = None; - borrow.prev = None; - } - + let mut index = 0; + for current_task in &self.queues[i] { + // Move the task from its old list to the new list. + if handle.id == current_task.borrow().id { + // Calling remove is unstable: https://github.com/rust-lang/rust/issues/69210 + let mut split_list = self.queues[i].split_off(index); + let task = split_list.pop_front().ok_or(())?; + self.queues[i].append(&mut split_list); + + task.borrow_mut().prio = prio; self.push(task); - return Ok(()); } - - let ptr = pos.as_ptr(); - pos = unsafe { (*ptr).next.as_mut().ok_or(())? }; + index += 1; } + + Err(()) } } @@ -425,10 +348,6 @@ pub struct Task { pub core_id: CoreId, /// Stack of the task pub stacks: TaskStacks, - /// next task in queue - pub next: Option>>, - /// previous task in queue - pub prev: Option>>, /// Task Thread-Local-Storage (TLS) pub tls: Option, /// lwIP error code for this task @@ -460,8 +379,6 @@ impl Task { last_fpu_state: arch::processor::FPUState::new(), core_id, stacks, - next: None, - prev: None, tls: None, #[cfg(feature = "newlib")] lwip_errno: 0, @@ -480,8 +397,6 @@ impl Task { last_fpu_state: arch::processor::FPUState::new(), core_id, stacks: TaskStacks::from_boot_stacks(), - next: None, - prev: None, tls: None, #[cfg(feature = "newlib")] lwip_errno: 0, From 02ccc14077ccc4c88507297b05e25fdc814d4771 Mon Sep 17 00:00:00 2001 From: michael Date: Tue, 11 Apr 2023 21:06:18 -0500 Subject: [PATCH 2/3] Fixed clippy error. --- src/scheduler/task.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/scheduler/task.rs b/src/scheduler/task.rs index 93d7c73565..4589991d44 100644 --- a/src/scheduler/task.rs +++ b/src/scheduler/task.rs @@ -305,8 +305,8 @@ impl PriorityTaskQueue { /// Change priority of specific task pub fn set_priority(&mut self, handle: TaskHandle, prio: Priority) -> Result<(), ()> { let i = handle.get_priority().into() as usize; - let mut index = 0; - for current_task in &self.queues[i] { + + for (index, current_task) in self.queues[i].iter().enumerate() { // Move the task from its old list to the new list. if handle.id == current_task.borrow().id { // Calling remove is unstable: https://github.com/rust-lang/rust/issues/69210 @@ -318,7 +318,6 @@ impl PriorityTaskQueue { self.push(task); return Ok(()); } - index += 1; } Err(()) From 7445ef1f76f75d18b607779f15fd3e652790fe74 Mon Sep 17 00:00:00 2001 From: michael Date: Mon, 17 Apr 2023 22:06:22 -0500 Subject: [PATCH 3/3] Use Iterator::position, extract task removal to a separate method, and correctly set priority bitmask to reflect empty lists. --- src/scheduler/task.rs | 47 ++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/scheduler/task.rs b/src/scheduler/task.rs index 4589991d44..efafe5863d 100644 --- a/src/scheduler/task.rs +++ b/src/scheduler/task.rs @@ -272,6 +272,30 @@ impl PriorityTaskQueue { task } + /// Remove the task at index from the queue and return that task, + /// or None if the index is out of range or the list is empty. + fn remove_from_queue( + &mut self, + task_index: usize, + queue_index: usize, + ) -> Option>> { + //assert!(prio < NO_PRIORITIES, "Priority {} is too high", prio); + + let queue = &mut self.queues[queue_index]; + if task_index <= queue.len() { + // Calling remove is unstable: https://github.com/rust-lang/rust/issues/69210 + let mut split_list = queue.split_off(task_index); + let element = split_list.pop_front(); + queue.append(&mut split_list); + if queue.is_empty() { + self.prio_bitmap &= !(1 << queue_index as u64); + } + element + } else { + None + } + } + /// Pop the task with the highest priority from the queue pub fn pop(&mut self) -> Option>> { if let Some(i) = msb(self.prio_bitmap) { @@ -304,20 +328,15 @@ impl PriorityTaskQueue { /// Change priority of specific task pub fn set_priority(&mut self, handle: TaskHandle, prio: Priority) -> Result<(), ()> { - let i = handle.get_priority().into() as usize; - - for (index, current_task) in self.queues[i].iter().enumerate() { - // Move the task from its old list to the new list. - if handle.id == current_task.borrow().id { - // Calling remove is unstable: https://github.com/rust-lang/rust/issues/69210 - let mut split_list = self.queues[i].split_off(index); - let task = split_list.pop_front().ok_or(())?; - self.queues[i].append(&mut split_list); - - task.borrow_mut().prio = prio; - self.push(task); - return Ok(()); - } + let old_priority = handle.get_priority().into() as usize; + if let Some(index) = self.queues[old_priority] + .iter() + .position(|current_task| current_task.borrow().id == handle.id) + { + let Some(task) = self.remove_from_queue(index, old_priority) else { return Err(()) }; + task.borrow_mut().prio = prio; + self.push(task); + return Ok(()); } Err(())