rtic/book/ru/src/internals/ceilings.md
2021-04-08 12:22:43 +03:00

4.5 KiB
Raw Blame History

Анализ приоритетов

Поиск максимального приоритета ресурса (ceiling) - поиск динамического приоритета, который любая задача должна иметь, чтобы безопасно работать с памятью ресурсов. Анализ приоритетов - относительно прост, но критичен для безопасности памяти RTIC программ.

Для расчета максимального приоритета ресурса мы должны сначала составить список задач, имеющих доступ к ресурсу -- так как фреймворк RTIC форсирует контроль доступа к ресурсам на этапе компиляции, он также имеет доступ к этой информации на этапе компиляции. Максимальный приоритет ресурса - просто наивысший логический приоритет среди этих задач.

init и idle не настоящие задачи, но у них есть доступ к ресурсам, поэтому они должны учитываться при анализе приоритетов. idle учитывается как задача, имеющая логический приоритет 0, в то время как init полностью исключается из анализа -- причина этому в том, что init никогда не использует (не нуждается) критические секции для доступа к статическим переменным.

В предыдущем разделе мы показывали, что разделяемые ресусы могут быть представлены уникальными ссылками (&mut-) или скрываться за прокси в зависимости от того, имеет ли задача к ним доступ. Какой из вариантов представляется задаче зависит от приоритета задачи и максимального приоритета ресурса. Если приоритет задачи такой же, как максимальный приоритет ресурса, тогда задача получает уникальную ссылку (&mut-) на память ресурса, в противном случае задача получает прокси -- это также касается idle. init особеннвй: он всегда получает уникальные ссылки (&mut-) на ресурсы.

Пример для иллюстрации анализа приоритетов:

#[rtic::app(device = ..)]
mod app {
    struct Resources {
        // доступен из `foo` (prio = 1) и `bar` (prio = 2)
        // -> CEILING = 2
        #[init(0)]
        x: u64,

        // доступен из `idle` (prio = 0)
        // -> CEILING = 0
        #[init(0)]
        y: u64,
    }

    #[init(resources = [x])]
    fn init(c: init::Context) {
        // уникальная ссылка, потому что это `init`
        let x: &mut u64 = c.resources.x;

        // уникальная ссылка, потому что это `init`
        let y: &mut u64 = c.resources.y;

        // ..
    }

    // PRIORITY = 0
    #[idle(resources = [y])]
    fn idle(c: idle::Context) -> ! {
        // уникальная ссылка, потому что
        // приоритет (0) == максимальному приоритету ресурса (0)
        let y: &'static mut u64 = c.resources.y;

        loop {
            // ..
        }
    }

    #[interrupt(binds = UART0, priority = 1, resources = [x])]
    fn foo(c: foo::Context) {
        // прокси-ресурс, потому что
        // приоритет задач (1) < максимальному приоритету ресурса (2)
        let x: resources::x = c.resources.x;

        // ..
    }

    #[interrupt(binds = UART1, priority = 2, resources = [x])]
    fn bar(c: foo::Context) {
        // уникальная ссылка, потому что
        // приоритет задачи (2) == максимальному приоритету ресурса (2)
        let x: &mut u64 = c.resources.x;

        // ..
    }

    // ..
}