aboutsummaryrefslogtreecommitdiff
path: root/book/ru/src/internals/access.md
blob: ea073a4d3e3b0e34400e6b03f6678dbf9af58a30 (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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# Контроль доступа

Одна из основ RTIC - контроль доступа. Контроль того, какая часть программы
может получить доступ к какой статической переменной - инструмент обеспечения
безопасности памяти.

Статические переменные используются для разделения состояний между обработчиками
прерываний, или между обработчиком прерывания и нижним контекстом выполнения, `main`.
В обычном Rust коде трудно обеспечить гранулированный контроль за тем, какие функции
могут получать доступ к статическим переменным, поскольку к статическим переменным
можно получить доступ из любой функции, находящейся в той же области видимости,
в которой они определены. Модули дают частичный контроль над доступом
к статическим переменным, но они недостаточно гибкие.

Чтобы добиться полного контроля за тем, что задачи могут получить доступ
только к статическим переменным (ресурсам), которые им были указаны в RTIC атрибуте,
фреймворк RTIC производит трансформацию структуры кода.
Эта трансформация состоит из размещения ресурсов (статических переменных), определенных
пользователем *внутри* модуля, а пользовательского кода *вне* модуля.
Это делает невозможным обращение пользовательского кода к статическим переменным.

Затем доступ к ресурсам предоставляется каждой задаче с помощью структуры `Resources`,
чьи поля соответствуют ресурсам, к которым получает доступ задача.
Есть лишь одна такая структура на задачу и структура `Resources` инициализируется
либо уникальной ссылкой (`&mut-`) на статическую переменную, либо с помощью прокси-ресурса (см.
раздел [критические секции](critical-sections.html)).

Код ниже - пример разных трансформаций структуры кода, происходящих за сценой:

``` rust
#[rtic::app(device = ..)]
mod app {
    static mut X: u64: 0;
    static mut Y: bool: 0;

    #[init(resources = [Y])]
    fn init(c: init::Context) {
        // .. пользовательский код ..
    }

    #[interrupt(binds = UART0, resources = [X])]
    fn foo(c: foo::Context) {
        // .. пользовательский код ..
    }

    #[interrupt(binds = UART1, resources = [X, Y])]
    fn bar(c: bar::Context) {
        // .. пользовательский код ..
    }

    // ..
}
```

Фреймворк создает код, подобный этому:

``` rust
fn init(c: init::Context) {
    // .. пользовательский код ..
}

fn foo(c: foo::Context) {
    // .. пользовательский код ..
}

fn bar(c: bar::Context) {
    // .. пользовательский код ..
}

// Публичное API
pub mod init {
    pub struct Context<'a> {
        pub resources: Resources<'a>,
        // ..
    }

    pub struct Resources<'a> {
        pub Y: &'a mut bool,
    }
}

pub mod foo {
    pub struct Context<'a> {
        pub resources: Resources<'a>,
        // ..
    }

    pub struct Resources<'a> {
        pub X: &'a mut u64,
    }
}

pub mod bar {
    pub struct Context<'a> {
        pub resources: Resources<'a>,
        // ..
    }

    pub struct Resources<'a> {
        pub X: &'a mut u64,
        pub Y: &'a mut bool,
    }
}

/// Детали реализации
mod app {
    // все, что внутри этого модуля спрятано от пользовательского кода

    static mut X: u64 = 0;
    static mut Y: bool = 0;

    // настоящая точка входа в программу
    unsafe fn main() -> ! {
        interrupt::disable();

        // ..

        // вызов пользовательского кода; передача ссылок на статические переменные
        init(init::Context {
            resources: init::Resources {
                X: &mut X,
            },
            // ..
        });

        // ..

        interrupt::enable();

        // ..
    }

    // обработчик прерывания,с которым связан `foo`
    #[no_mangle]
    unsafe fn UART0() {
        // вызов пользовательского кода; передача ссылок на статические переменные
        foo(foo::Context {
            resources: foo::Resources {
                X: &mut X,
            },
            // ..
        });
    }

    // обработчик прерывания,с которым связан `bar`
    #[no_mangle]
    unsafe fn UART1() {
        // вызов пользовательского кода; передача ссылок на статические переменные
        bar(bar::Context {
            resources: bar::Resources {
                X: &mut X,
                Y: &mut Y,
            },
            // ..
        });
    }
}
```