mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-24 12:42:52 +01:00
159 lines
5.9 KiB
Markdown
159 lines
5.9 KiB
Markdown
|
# Контроль доступа
|
|||
|
|
|||
|
Одна из основ 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,
|
|||
|
},
|
|||
|
// ..
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
```
|