let input = baz_INPUTS[ready.index as usize].read();
baz_FQ.split().0.enqueue_unchecked(ready.index);
let priority = Cell::new(PRIORITY);
baz(baz::Context::new(&priority), input)
}
Task::bar => {
}
}
}
basepri::write(snapshot);
}
}
}
INPUTS плюс FQ, список свободной памяти равняется эффективному пулу памяти. Однако, вместо того
Фреймворк RTIC использует несколько очередей, такие как очереди готовности и списки свободной памяти. Когда список свободной памяти пуст, попытка выызова (spawn) задачи приводит к ошибке; это условие проверяется во время выполнения. Не все операции, произвожимые фреймворком с этими очередями проверяют их пустоту / наличие места. Например, возвращение ячейки списка свободной памяти (см. диспетчер задач) не проверяется, поскольку есть фиксированное количество таких ячеек циркулирующих в системе, равное вместительности списка свободной памяти. Аналогично, добавление записи в очередь готовности (см. Spawn) не проверяется, потому что вместительность очереди выбрана фреймворком.
Пользователи могут задавать вместительность программных задач; эта вместительность - максимальное количество сообщений, которые можно послать указанной задаче от задачи более высоким приоритетом до того, как spawn вернет ошибку. Эта определяемая пользователем иместительность - размер списка свободной памяти задачи (например foo_FQ), а также размер массива, содержащего входные данные для задачи (например foo_INPUTS).
Вместительность очереди готовности (например RQ1) вычисляется как
В нашем запущенном примере задача bar не принимает входных данных, поэтому мы можем пропустить проверку как bar_INPUTS, так и bar_FQ и позволить пользователю посылать неограниченное число сообщений задаче, но если бы мы сделали это, было бы невозможно превысить вместительность для RQ1, что позволяет нам пропустить проверку "полна ли очередь?" при вызове задачи baz. В разделе о очереди таймера мы увидим как список свободной памяти используется для задач без входных данных.
Очереди, использемые внутри интерфейса spawn, рассматриваются как обычные ресурсы и для них тоже работает анализ приоритетов. Важно заметить, что это SPSC очереди, и только один из конечных элементов становится ресурсом; другим конечным элементом владеет диспетчер задач.
Рассмотрим следующий пример:
#![allow(unused)]
fn main() {
#[rtic::app(device = ..)]
mod app {
#[idle(spawn = [foo, bar])]
fn idle(c: idle::Context) -> ! {
}
#[task]
fn foo(c: foo::Context) {
}
#[task]
fn bar(c: bar::Context) {
}
#[task(priority = 2, spawn = [foo])]
fn baz(c: baz::Context) {
}
#[task(priority = 3, spawn = [bar])]
fn quux(c: quux::Context) {
}
}
}
Вот как будет проходить анализ приоритетов:
• idle (prio = 0) и baz (prio = 2) соревнуются за конечный потребитель foo_FQ; это приводит к максимальному приоритету 2.
• idle (prio = 0) и quux (prio = 3) соревнуются за конечный потребитель bar_FQ; это приводит к максимальному приоритету 3.
• idle (prio = 0), baz (prio = 2) и quux (prio = 3) соревнуются за конечный производитель RQ1; это приводит к максимальному приоритету 3