Типы, Send и Sync
Атрибут app
вводит контекст, коллекцию переменных в каждую из функций.
Все эти переменные имеют предсказуемые, неанонимные типы, поэтому Вы можете
писать простые функции, получающие их как аргументы.
Описание API определяет как эти типы эти типы генерируются из входных данных.
Вы можете также сгенерировать документацию для Вашей бинарной библиотеки
(cargo doc --bin <name>
); в документации Вы найдете структуры Context
(например init::Context
и idle::Context
), чьи поля представляют переменные
включенные в каждую функцию.
В примере ниже сгенерированы разные типы с помощью атрибута app
.
# #![allow(unused_variables)] #fn main() { //! examples/types.rs #![deny(unsafe_code)] #![deny(warnings)] #![no_main] #![no_std] extern crate panic_semihosting; use cortex_m_semihosting::debug; use rtfm::{Exclusive, Instant}; #[rtfm::app(device = lm3s6965)] const APP: () = { static mut SHARED: u32 = 0; #[init(schedule = [foo], spawn = [foo])] fn init(c: init::Context) { let _: Instant = c.start; let _: rtfm::Peripherals = c.core; let _: lm3s6965::Peripherals = c.device; let _: init::Schedule = c.schedule; let _: init::Spawn = c.spawn; debug::exit(debug::EXIT_SUCCESS); } #[exception(schedule = [foo], spawn = [foo])] fn SVCall(c: SVCall::Context) { let _: Instant = c.start; let _: SVCall::Schedule = c.schedule; let _: SVCall::Spawn = c.spawn; } #[interrupt(resources = [SHARED], schedule = [foo], spawn = [foo])] fn UART0(c: UART0::Context) { let _: Instant = c.start; let _: resources::SHARED = c.resources.SHARED; let _: UART0::Schedule = c.schedule; let _: UART0::Spawn = c.spawn; } #[task(priority = 2, resources = [SHARED], schedule = [foo], spawn = [foo])] fn foo(c: foo::Context) { let _: Instant = c.scheduled; let _: Exclusive<u32> = c.resources.SHARED; let _: foo::Resources = c.resources; let _: foo::Schedule = c.schedule; let _: foo::Spawn = c.spawn; } extern "C" { fn UART1(); } }; #}
Send
Send
- маркерный типаж (trait) для "типов, которые можно передавать через границы
потоков", как это определено в core
. В контексте RTFM типаж Send
необходим
только там, где возможна передача значения между задачами, запускаемыми на
разных приоритетах. Это возникает в нескольких случаях: при передаче сообщений,
в совместно используемых static mut
ресурсах и инициализации поздних ресурсов.
Атрибут app
проверит, что Send
реализован, где необходимо, поэтому Вам не
стоит волноваться об этом. Более важно знать, где Вам не нужен типаж Send
:
в типах, передаваемых между задачами с одинаковым приоритетом. Это возникает
в двух случаях: при передаче сообщений и в совместно используемых static mut
ресурсах.
В примере ниже показано, где можно использовать типы, не реализующие Send
.
# #![allow(unused_variables)] #fn main() { //! `examples/not-send.rs` #![deny(unsafe_code)] #![deny(warnings)] #![no_main] #![no_std] extern crate panic_halt; use core::marker::PhantomData; use cortex_m_semihosting::debug; use rtfm::app; pub struct NotSend { _0: PhantomData<*const ()>, } #[app(device = lm3s6965)] const APP: () = { static mut SHARED: Option<NotSend> = None; #[init(spawn = [baz, quux])] fn init(c: init::Context) { c.spawn.baz().unwrap(); c.spawn.quux().unwrap(); } #[task(spawn = [bar])] fn foo(c: foo::Context) { // scenario 1: message passed to task that runs at the same priority c.spawn.bar(NotSend { _0: PhantomData }).ok(); } #[task] fn bar(_: bar::Context, _x: NotSend) { // scenario 1 } #[task(priority = 2, resources = [SHARED])] fn baz(mut c: baz::Context) { // scenario 2: resource shared between tasks that run at the same priority *c.resources.SHARED = Some(NotSend { _0: PhantomData }); } #[task(priority = 2, resources = [SHARED])] fn quux(mut c: quux::Context) { // scenario 2 let _not_send = c.resources.SHARED.take().unwrap(); debug::exit(debug::EXIT_SUCCESS); } extern "C" { fn UART0(); fn UART1(); } }; #}
Sync
Похожая ситуация, Sync
- маркерный типаж для "типов, на которых можно
ссылаться в разных потоках", как это определено в core
. В контексте RTFM
типаж Sync
необходим только там, где возможны две или более задачи,
запускаемые на разных приоритетах, чтобы захватить разделяемую ссылку на
ресурс. Это возникает только совместно используемых static
-ресурсах.
Атрибут app
проверит, что Sync
реализован, где необходимо, но важно знать,
где ограничение Sync
не требуется: в static
-ресурсах, разделяемых между
задачами с одинаковым приоритетом.
В примере ниже показано, где можно использовать типы, не реализующие Sync
.
# #![allow(unused_variables)] #fn main() { //! `examples/not-sync.rs` #![deny(unsafe_code)] #![deny(warnings)] #![no_main] #![no_std] extern crate panic_halt; use core::marker::PhantomData; use cortex_m_semihosting::debug; pub struct NotSync { _0: PhantomData<*const ()>, } #[rtfm::app(device = lm3s6965)] const APP: () = { static SHARED: NotSync = NotSync { _0: PhantomData }; #[init] fn init(_: init::Context) { debug::exit(debug::EXIT_SUCCESS); } #[task(resources = [SHARED])] fn foo(c: foo::Context) { let _: &NotSync = c.resources.SHARED; } #[task(resources = [SHARED])] fn bar(c: bar::Context) { let _: &NotSync = c.resources.SHARED; } extern "C" { fn UART0(); } }; #}