Читаем Real-Time Interrupt-driven Concurrency полностью

#![allow(unused)]

fn main() {

#[rtic::app(device = ..)]

mod app {

#[init]

fn init(c: init::Context) { .. }

#[interrupt(binds = UART0)]

fn foo(c: foo::Context) {

static mut X: u64 = 0;

let x: &mut u64 = X;

// ..

//~ `bar` может вытеснить `foo` в этом месте

// ..

}

#[interrupt(binds = UART1, priority = 2)]

fn bar(c: foo::Context) {

extern "C" {

fn UART0();

}

// этот обработчик прерывания вызовет задачу-обработчик `foo`, что сломает

// ссылку на статическую переменную `X`

unsafe { UART0() }

}

}

}

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

Пример выше раскрывается в:

#![allow(unused)]

fn main() {

fn foo(c: foo::Context) {

// .. пользовательский код ..

}

fn bar(c: bar::Context) {

// .. пользовательский код ..

}

mod app {

// все в этом блоке невидимо для пользовательского кода

#[no_mangle]

unsafe fn USART0() {

foo(..);

}

#[no_mangle]

unsafe fn USART1() {

bar(..);

}

}

}

<p id="Аппаратно"><strong><a l:href="#Аппаратно">Аппаратно</a></strong></p>

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

<p id="Контроль_доступа"><strong><a l:href="#Контроль_доступа">Контроль доступа</a></strong></p>

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

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

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

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

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

#![allow(unused)]

fn main() {

#[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) {

// .. пользовательский код ..

}

// ..

}

}

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

fn init(c: init::Context) {

// .. пользовательский код ..

}

fn foo(c: foo::Context) {

// .. пользовательский код ..

}

fn bar(c: bar::Context) {

// .. пользовательский код ..

}

// Публичное API

pub mod init {

pub struct Context<'a> {

Перейти на страницу:

Похожие книги

Компьютерные сети. 6-е изд.
Компьютерные сети. 6-е изд.

Перед вами шестое издание самой авторитетной книги по современным сетевым технологиям, написанное признанным экспертом Эндрю Таненбаумом в соавторстве со специалистом компании Google Дэвидом Уэзероллом и профессором Чикагского университета Ником Фимстером. Первая версия этого классического труда появилась на свет в далеком 1980 году, и с тех пор каждое издание книги неизменно становилось бестселлером. В книге последовательно изложены основные концепции, определяющие современное состояние компьютерных сетей и тенденции их развития. Авторы подробно объясняют устройство и принципы работы аппаратного и программного обеспечения, рассматривают все аспекты и уровни организации сетей — от физического до прикладного. Изложение теоретических принципов дополняется яркими, показательными примерами функционирования интернета и компьютерных сетей различного типа. Большое внимание уделяется сетевой безопасности. Шестое издание полностью переработано с учетом изменений, произошедших в сфере сетевых технологий за последние годы, и, в частности, освещает такие технологии, как DOCSIS, 4G и 5G, беспроводные сети стандарта 802.11ax, 100-гигабитные сети Ethernet, интернет вещей, современные транспортные протоколы CUBIC TCP, QUIC и BBR, программно-конфигурируемые сети и многое другое.

Дэвид Уэзеролл , Ник Фимстер , Эндрю Таненбаум

Учебные пособия, самоучители