Выбрать главу

Давайте сначала глянем на код, генерируемый фреймворком для диспетчеризации задач. Рассмотрим пример:

#![allow(unused)]

fn main() {

#[rtic::app(device = ..)]

mod app {

// ..

#[interrupt(binds = UART0, priority = 2, spawn = [bar, baz])]

fn foo(c: foo::Context) {

foo.spawn.bar().ok();

foo.spawn.baz(42).ok();

}

#[task(capacity = 2, priority = 1)]

fn bar(c: bar::Context) {

// ..

}

#[task(capacity = 2, priority = 1, resources = [X])]

fn baz(c: baz::Context, input: i32) {

// ..

}

extern "C" {

fn UART1();

}

}

}

Фреймворк создает следующий диспетчер задач, состоящий из обработчика прерывания и очереди готовности:

#![allow(unused)]

fn main() {

fn bar(c: bar::Context) {

// .. пользовательский код ..

}

mod app {

use heapless::spsc::Queue;

use cortex_m::register::basepri;

struct Ready<T> {

task: T,

// ..

}

/// вызываемые (`spawn`) задачи, выполняющиеся с уровнем приоритета `1`

enum T1 {

bar,

baz,

}

// очередь готовности диспетчера задач

// `U4` - целое число, представляющее собой емкость этой очереди

static mut RQ1: Queue<Ready<T1>, U4> = Queue::new();

// обработчик прерывания, выбранный для диспетчеризации задач с приоритетом `1`

#[no_mangle]

unsafe UART1() {

// приоритет данного обработчика прерывания

const PRIORITY: u8 = 1;

let snapshot = basepri::read();

while let Some(ready) = RQ1.split().1.dequeue() {

match ready.task {

T1::bar => {

// **ПРИМЕЧАНИЕ** упрощенная реализация

// используется для отслеживания динамического приоритета

let priority = Celclass="underline" :new(PRIORITY);

// вызов пользовательского кода

bar(bar::Context::new(&priority));

}

T1::baz => {

// рассмотрим `baz` позднее

}

}

}

// инвариант BASEPRI

basepri::write(snapshot);

}

}

}

Интерфейс spawn предоставлен пользователю как методы структурв Spawn. Для каждой задачи существует своя структура Spawn.

Код Spawn, генерируемый фреймворком для предыдущего примера выглядит так:

#![allow(unused)]

fn main() {

mod foo {

// ..

pub struct Context<'a> {

pub spawn: Spawn<'a>,

// ..

}

pub struct Spawn<'a> {

// отслеживает динамический приоритет задачи

priority: &'a Cell<u8>,

}

impl<'a> Spawn<'a> {

// `unsafe` и спрятано, поскольку сы не хотит, чтобы пользователь вмешивался сюда

#[doc(hidden)]

pub unsafe fn priority(&self) -> &Cell<u8> {

self.priority

}

}

}

mod app {

// ..

// Поиск максимального приоритета для конечного производителя `RQ1`

const RQ1_CEILING: u8 = 2;

// используется, чтобы отследить сколько еще сообщений для `bar` можно поставить в очередь

// `U2` - емкость задачи `bar`; максимум 2 экземпляра можно добавить в очередь

// эта очередь заполняется фреймворком до того, как запустится `init`

static mut bar_FQ: Queue<(), U2> = Queue::new();

// Поиск максимального приоритета для конечного потребителя `bar_FQ`

const bar_FQ_CEILING: u8 = 2;

// приоритет-ориентированная критическая секция

//

// это запускае переданное замыкание `f` с динамическим приоритетом не ниже