diff options
| author | Andrey Zgarbul <zgarbul.andrey@gmail.com> | 2021-04-04 08:15:13 +0300 |
|---|---|---|
| committer | Andrey Zgarbul <zgarbul.andrey@gmail.com> | 2021-04-08 12:22:43 +0300 |
| commit | 05bda2b1bd2e15f5a20cda1444992eb9b6c8887e (patch) | |
| tree | 25330724d4e6d9ea3a62b592c07bfc5799c7da57 /book/ru/src/internals/late-resources.md | |
| parent | 83cdf00eecb0f14857b5e0f28e884b2120eabb18 (diff) | |
update russian translation of the book
Diffstat (limited to 'book/ru/src/internals/late-resources.md')
| -rw-r--r-- | book/ru/src/internals/late-resources.md | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/book/ru/src/internals/late-resources.md b/book/ru/src/internals/late-resources.md new file mode 100644 index 0000000..0fad0ae --- /dev/null +++ b/book/ru/src/internals/late-resources.md @@ -0,0 +1,114 @@ +# Поздние ресурсы + +Некоторые ресурсы инициализируются во время выполнения после завершения функции `init`. +Важно то, что ресурсы (статические переменные) полностью инициализируются +до того, как задачи смогут запуститься, вот почему они должны быть инициализированы +пока прерывания отключены. + +Ниже показан пример кода, генерируемого фреймворком для инициализации позних ресурсов. + +``` rust +#[rtic::app(device = ..)] +mod app { + struct Resources { + x: Thing, + } + + #[init] + fn init() -> init::LateResources { + // .. + + init::LateResources { + x: Thing::new(..), + } + } + + #[task(binds = UART0, resources = [x])] + fn foo(c: foo::Context) { + let x: &mut Thing = c.resources.x; + + x.frob(); + + // .. + } + + // .. +} +``` + +Код, генерируемы фреймворком выглядит примерно так: + +``` rust +fn init(c: init::Context) -> init::LateResources { + // .. пользовательский код .. +} + +fn foo(c: foo::Context) { + // .. пользовательский код .. +} + +// Public API +pub mod init { + pub struct LateResources { + pub x: Thing, + } + + // .. +} + +pub mod foo { + pub struct Resources<'a> { + pub x: &'a mut Thing, + } + + pub struct Context<'a> { + pub resources: Resources<'a>, + // .. + } +} + +/// Детали реализации +mod app { + // неинициализированная статическая переменная + static mut x: MaybeUninit<Thing> = MaybeUninit::uninit(); + + #[no_mangle] + unsafe fn main() -> ! { + cortex_m::interrupt::disable(); + + // .. + + let late = init(..); + + // инициализация поздних ресурсов + x.as_mut_ptr().write(late.x); + + cortex_m::interrupt::enable(); //~ compiler fence + + // исключения, прерывания и задачи могут вытеснить `main` в этой точке + + idle(..) + } + + #[no_mangle] + unsafe fn UART0() { + foo(foo::Context { + resources: foo::Resources { + // `x` уже инициализирована к этому моменту + x: &mut *x.as_mut_ptr(), + }, + // .. + }) + } +} +``` + +Важная деталь здесь то, что `interrupt::enable` ведет себя как like a *compiler +fence*, которое не дает компилятору пореставить запись в `X` *после* +`interrupt::enable`. Если бы компилятор мог делать такие перестановки появились +бы гонки данных между этой записью и любой операцией `foo`, взаимодействующей с `X`. + +Архитектурам с более сложным конвейером инструкций нужен барьер памяти +(`atomic::fence`) вместо compiler fence для полной очистки операции записи +перед включением прерываний. Архитектура ARM Cortex-M не нуждается в барьере памяти +в одноядерном контексте. |
