rtic/book/ru/src/internals/access.md

159 lines
5.9 KiB
Markdown
Raw Normal View History

2021-04-04 07:15:13 +02:00
# Контроль доступа
Одна из основ 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,
},
// ..
});
}
}
```