aboutsummaryrefslogtreecommitdiff
path: root/book/ru/src/internals/ceilings.md
blob: df9901a2b434ecf12608d15d0b73fd318a72b212 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# Анализ приоритетов

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

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

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

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

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

``` rust
#[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;

        // ..
    }

    // ..
}
```