1
1
//! Tasks
2
- use core:: { cell:: UnsafeCell , fmt, hash, marker:: PhantomData , mem, sync:: atomic:: Ordering } ;
2
+ use core:: {
3
+ cell:: UnsafeCell , convert:: TryFrom , fmt, hash, marker:: PhantomData , mem, sync:: atomic:: Ordering ,
4
+ } ;
3
5
use num_traits:: ToPrimitive ;
4
6
5
7
use super :: {
6
8
hunk:: Hunk , state, timeout, utils, wait, ActivateTaskError , BadIdError , ExitTaskError ,
7
9
GetCurrentTaskError , Id , InterruptTaskError , Kernel , KernelCfg1 , ParkError , ParkTimeoutError ,
8
- Port , PortThreading , SleepError , UnparkError , UnparkExactError , WaitTimeoutError ,
10
+ Port , PortThreading , SetTaskPriorityError , SleepError , UnparkError , UnparkExactError ,
11
+ WaitTimeoutError ,
9
12
} ;
10
13
use crate :: {
11
14
time:: Duration ,
@@ -218,6 +221,27 @@ impl<System: Kernel> Task<System> {
218
221
let task_cb = self . task_cb ( ) ?;
219
222
unpark_exact ( lock, task_cb)
220
223
}
224
+
225
+ /// Set the task's priority.
226
+ ///
227
+ /// Tasks with lower priority values execute first. The priority is reset to
228
+ /// the initial value specified by [`CfgTaskBuilder::priority`] upon
229
+ /// activation.
230
+ ///
231
+ /// [`CfgTaskBuilder::priority`]: crate::kernel::cfg::CfgTaskBuilder::priority
232
+ ///
233
+ /// The value must be in range `0..`[`num_task_priority_levels`]. Otherwise,
234
+ /// this method will return [`SetTaskPriorityError::BadParam`].
235
+ ///
236
+ /// The task shouldn't be in the Dormant state. Otherwise, this method will
237
+ /// return [`SetTaskPriorityError::BadObjectState`].
238
+ ///
239
+ /// [`num_task_priority_levels`]: crate::kernel::cfg::CfgBuilder::num_task_priority_levels
240
+ pub fn set_priority ( self , priority : usize ) -> Result < ( ) , SetTaskPriorityError > {
241
+ let lock = utils:: lock_cpu :: < System > ( ) ?;
242
+ let task_cb = self . task_cb ( ) ?;
243
+ set_task_priority ( lock, task_cb, priority)
244
+ }
221
245
}
222
246
223
247
/// [`Hunk`] for a task stack.
@@ -288,9 +312,9 @@ pub struct TaskCb<
288
312
pub port_task_state : PortTaskState ,
289
313
290
314
/// The static properties of the task.
291
- pub attr : & ' static TaskAttr < System > ,
315
+ pub attr : & ' static TaskAttr < System , TaskPriority > ,
292
316
293
- pub priority : TaskPriority ,
317
+ pub ( super ) priority : utils :: CpuLockCell < System , TaskPriority > ,
294
318
295
319
pub ( super ) st : utils:: CpuLockCell < System , TaskSt > ,
296
320
@@ -309,20 +333,6 @@ pub struct TaskCb<
309
333
pub ( super ) park_token : utils:: CpuLockCell < System , bool > ,
310
334
}
311
335
312
- impl < System : Port , PortTaskState : Init + ' static , TaskPriority : Init + ' static > Init
313
- for TaskCb < System , PortTaskState , TaskPriority >
314
- {
315
- const INIT : Self = Self {
316
- port_task_state : Init :: INIT ,
317
- attr : & TaskAttr :: INIT ,
318
- priority : Init :: INIT ,
319
- st : Init :: INIT ,
320
- link : Init :: INIT ,
321
- wait : Init :: INIT ,
322
- park_token : Init :: INIT ,
323
- } ;
324
- }
325
-
326
336
impl < System : Kernel , PortTaskState : fmt:: Debug + ' static , TaskPriority : fmt:: Debug + ' static >
327
337
fmt:: Debug for TaskCb < System , PortTaskState , TaskPriority >
328
338
{
@@ -336,7 +346,7 @@ impl<System: Kernel, PortTaskState: fmt::Debug + 'static, TaskPriority: fmt::Deb
336
346
}
337
347
338
348
/// The static properties of a task.
339
- pub struct TaskAttr < System > {
349
+ pub struct TaskAttr < System , TaskPriority : ' static = < System as KernelCfg1 > :: TaskPriority > {
340
350
/// The entry point of the task.
341
351
///
342
352
/// # Safety
@@ -353,22 +363,17 @@ pub struct TaskAttr<System> {
353
363
// this is blocked by <https://github.com/rust-lang/const-eval/issues/11>
354
364
/// The hunk representing the stack region for the task.
355
365
pub stack : StackHunk < System > ,
356
- }
357
366
358
- impl < System > Init for TaskAttr < System > {
359
- const INIT : Self = Self {
360
- entry_point : |_| { } ,
361
- entry_param : 0 ,
362
- stack : StackHunk :: INIT ,
363
- } ;
367
+ pub priority : TaskPriority ,
364
368
}
365
369
366
- impl < System : Kernel > fmt:: Debug for TaskAttr < System > {
370
+ impl < System : Kernel , TaskPriority : fmt :: Debug > fmt:: Debug for TaskAttr < System , TaskPriority > {
367
371
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
368
372
f. debug_struct ( "TaskAttr" )
369
373
. field ( "entry_point" , & self . entry_point )
370
374
. field ( "entry_param" , & self . entry_param )
371
375
. field ( "stack" , & self . stack )
376
+ . field ( "priority" , & self . priority )
372
377
. finish ( )
373
378
}
374
379
}
@@ -505,6 +510,9 @@ fn activate<System: Kernel>(
505
510
// Safety: CPU Lock active, the task is in the Dormant state
506
511
unsafe { System :: initialize_task_state ( task_cb) } ;
507
512
513
+ // Reset the task priority
514
+ task_cb. priority . replace ( & mut * lock, task_cb. attr . priority ) ;
515
+
508
516
// Safety: The previous state is Dormant, and we just initialized the task
509
517
// state, so this is safe
510
518
unsafe { make_ready ( lock. borrow_mut ( ) , task_cb) } ;
@@ -527,7 +535,7 @@ pub(super) unsafe fn make_ready<System: Kernel>(
527
535
task_cb. st . replace ( & mut * lock, TaskSt :: Ready ) ;
528
536
529
537
// Insert the task to a ready queue
530
- let pri = task_cb. priority . to_usize ( ) . unwrap ( ) ;
538
+ let pri = task_cb. priority . read ( & * lock ) . to_usize ( ) . unwrap ( ) ;
531
539
list_accessor ! ( <System >:: state( ) . task_ready_queue[ pri] , lock. borrow_mut( ) )
532
540
. push_back ( Ident ( task_cb) ) ;
533
541
@@ -555,7 +563,7 @@ pub(super) fn unlock_cpu_and_check_preemption<System: Kernel>(lock: utils::CpuLo
555
563
}
556
564
557
565
let prev_task_priority = if let Some ( running_task) = System :: state ( ) . running_task ( ) {
558
- running_task. priority . to_usize ( ) . unwrap ( )
566
+ running_task. priority . read ( & * lock ) . to_usize ( ) . unwrap ( )
559
567
} else {
560
568
usize:: MAX
561
569
} ;
@@ -595,7 +603,7 @@ pub(super) fn choose_next_running_task<System: Kernel>(
595
603
let prev_running_task = System :: state ( ) . running_task ( ) ;
596
604
let prev_task_priority = if let Some ( running_task) = prev_running_task {
597
605
if * running_task. st . read ( & * lock) == TaskSt :: Running {
598
- running_task. priority . to_usize ( ) . unwrap ( )
606
+ running_task. priority . read ( & * lock ) . to_usize ( ) . unwrap ( )
599
607
} else {
600
608
usize:: MAX
601
609
}
@@ -795,3 +803,79 @@ pub(super) fn put_current_task_on_sleep_timeout<System: Kernel>(
795
803
Err ( WaitTimeoutError :: Timeout ) => Ok ( ( ) ) ,
796
804
}
797
805
}
806
+
807
+ /// Implements [`Task::set_priority`].
808
+ fn set_task_priority < System : Kernel > (
809
+ mut lock : utils:: CpuLockGuard < System > ,
810
+ task_cb : & ' static TaskCb < System > ,
811
+ priority : usize ,
812
+ ) -> Result < ( ) , SetTaskPriorityError > {
813
+ // Validate the given priority
814
+ if priority >= System :: NUM_TASK_PRIORITY_LEVELS {
815
+ return Err ( SetTaskPriorityError :: BadParam ) ;
816
+ }
817
+ let priority_internal =
818
+ System :: TaskPriority :: try_from ( priority) . unwrap_or_else ( |_| unreachable ! ( ) ) ;
819
+
820
+ let st = * task_cb. st . read ( & * lock) ;
821
+
822
+ if st == TaskSt :: Dormant {
823
+ return Err ( SetTaskPriorityError :: BadObjectState ) ;
824
+ }
825
+
826
+ // Assign the new priority
827
+ let old_priority = task_cb
828
+ . priority
829
+ . replace ( & mut * lock, priority_internal)
830
+ . to_usize ( )
831
+ . unwrap ( ) ;
832
+
833
+ if old_priority == priority {
834
+ return Ok ( ( ) ) ;
835
+ }
836
+
837
+ match st {
838
+ TaskSt :: Ready => {
839
+ // Move the task between ready queues
840
+ let old_pri_empty = {
841
+ let mut accessor = list_accessor ! (
842
+ <System >:: state( ) . task_ready_queue[ old_priority] ,
843
+ lock. borrow_mut( )
844
+ ) ;
845
+ accessor. remove ( Ident ( task_cb) ) ;
846
+ accessor. is_empty ( )
847
+ } ;
848
+
849
+ list_accessor ! (
850
+ <System >:: state( ) . task_ready_queue[ priority] ,
851
+ lock. borrow_mut( )
852
+ )
853
+ . push_back ( Ident ( task_cb) ) ;
854
+
855
+ // Update `task_ready_bitmap` accordingly
856
+ // (This code assumes `priority != old_priority`.)
857
+ let task_ready_bitmap = System :: state ( ) . task_ready_bitmap . write ( & mut * lock) ;
858
+ task_ready_bitmap. set ( priority) ;
859
+ if old_pri_empty {
860
+ task_ready_bitmap. clear ( old_priority) ;
861
+ }
862
+ }
863
+ TaskSt :: Running => { }
864
+ TaskSt :: Waiting => {
865
+ // Reposition the task in a wait queue if the task is currently waiting
866
+ wait:: reorder_wait_of_task ( lock. borrow_mut ( ) , task_cb) ;
867
+ }
868
+ TaskSt :: Dormant | TaskSt :: PendingActivation => unreachable ! ( ) ,
869
+ }
870
+
871
+ if let TaskSt :: Running | TaskSt :: Ready = st {
872
+ // - If `st == TaskSt::Running`, `task_cb` is the currently running
873
+ // task. If the priority was lowered, it could be preempted by
874
+ // a task in the Ready state.
875
+ // - If `st == TaskSt::Ready` and the priority was raised, it could
876
+ // preempt the currently running task.
877
+ unlock_cpu_and_check_preemption ( lock) ;
878
+ }
879
+
880
+ Ok ( ( ) )
881
+ }
0 commit comments