From 7da84639809bc523e1c4432be94386d66580b1b5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 21 Apr 2019 21:35:36 +0200 Subject: [PATCH 1/2] backport: fix ceiling analysis bug This commit fixes a ceiling bug where the ceiling of a ready queue will be incorrectly computed. The analysis was not including the priority of the system timer interrupt (`SysTick`) in the analysis resulting in a priority ceiling lower than what's required for memory safety which led to data races. The bug can be observed in the following program: ``` rust #[rtfm::app(device = /* .. */)] const APP: () = { #[init] fn init() { // .. } #[task(priority = 2)] fn foo(x: i32) { // .. } #[task(priority = 1, spawn = [foo], schedule = [foo])] fn bar() { // .. } extern "C" { fn EXTI0(); fn EXTI1(); } }; ``` Here the framework chooses a priority of `2` for the `SysTick` interrupt (because it matches the priority of the `schedule`-able task `foo`). Both `SysTick` and `bar::Spawn.foo` need to access the ready queue (which, in this case, stores the messages sent to task `foo`) but the framework doesn't account for the priority of `SysTick` (`2`) and chooses a priority ceiling of `1` for the ready queue (because it matches the priority of task `bar` which can spawn `foo`). The result is that `bar::Spawn.foo` modifies the ready queue *without* a critical section (because `bar`'s priority matches the priority ceiling of the ready queue) which is wrong because `SysTick` (priority = `3`) can also modify the ready queue. --- macros/src/analyze.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/macros/src/analyze.rs b/macros/src/analyze.rs index cfd8ebc94a..c80ce5d16c 100644 --- a/macros/src/analyze.rs +++ b/macros/src/analyze.rs @@ -190,7 +190,7 @@ pub fn app(app: &App) -> Analysis { } // Ceiling analysis of free queues (consumer end point) -- first pass - // Ceiling analysis of ready queues (producer end point) + // Ceiling analysis of ready queues (producer end point) -- first pass // Also compute more Send-ness requirements let mut free_queues: HashMap<_, _> = app.tasks.keys().map(|task| (task.clone(), 0)).collect(); let mut ready_queues: HashMap<_, _> = dispatchers.keys().map(|level| (*level, 0)).collect(); @@ -215,10 +215,17 @@ pub fn app(app: &App) -> Analysis { } } + // Ceiling analysis of ready queues (producer end point) -- second pass // Ceiling analysis of free queues (consumer end point) -- second pass // Ceiling analysis of the timer queue let mut tq_ceiling = tq_priority; for (priority, task) in app.schedule_calls() { + // the system timer handler contends for the spawnee's dispatcher READY_QUEUE + let c = ready_queues + .entry(app.tasks[task].args.priority) + .or_default(); + *c = cmp::max(*c, tq_priority); + if let Some(priority) = priority { // Users of `schedule` contend for the to-be-spawned task FREE_QUEUE (consumer end point) let c = free_queues.get_mut(task).expect("BUG: free_queue.get_mut"); From 7b18df53ddde535cd1a60c8ba3eec6c8d6cb9349 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 1 May 2019 20:26:46 +0200 Subject: [PATCH 2/2] update .travis.yml --- .travis.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 31d10e84ee..563806977a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,18 +2,17 @@ language: rust matrix: include: + # - env: TARGET=x86_64-unknown-linux-gnu + + # - env: TARGET=thumbv6m-none-eabi + # if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) + + # - env: TARGET=thumbv7m-none-eabi + # if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) + # NOTE used to build docs on successful merges to master - - env: TARGET=x86_64-unknown-linux-gnu - - - env: TARGET=thumbv6m-none-eabi - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv7m-none-eabi - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - env: TARGET=x86_64-unknown-linux-gnu rust: nightly - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - env: TARGET=thumbv6m-none-eabi rust: nightly