aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml2
-rw-r--r--README_ru.md6
-rw-r--r--book/ru/src/by-example/app.md8
-rw-r--r--book/ru/src/by-example/resources.md87
-rw-r--r--book/ru/src/by-example/tips.md4
-rw-r--r--book/ru/src/internals/late-resources.md3
-rw-r--r--book/ru/src/internals/tasks.md10
-rw-r--r--book/ru/src/migration/migration_v5.md289
-rw-r--r--macros/src/codegen.rs1
-rw-r--r--macros/src/codegen/dispatchers.rs6
-rw-r--r--macros/src/codegen/local_resources.rs9
-rw-r--r--macros/src/codegen/local_resources_struct.rs8
-rw-r--r--macros/src/codegen/module.rs23
-rw-r--r--macros/src/codegen/post_init.rs5
-rw-r--r--macros/src/codegen/pre_init.rs11
-rw-r--r--macros/src/codegen/shared_resources.rs3
-rw-r--r--macros/src/codegen/shared_resources_struct.rs4
-rw-r--r--macros/src/codegen/software_tasks.rs9
-rw-r--r--macros/src/codegen/timer_queue.rs24
-rw-r--r--macros/src/codegen/util.rs81
-rw-r--r--src/export.rs1
-rw-r--r--src/lib.rs2
-rw-r--r--src/linked_list.rs597
-rw-r--r--src/tq.rs10
24 files changed, 367 insertions, 836 deletions
diff --git a/Cargo.toml b/Cargo.toml
index e3cb010b..ed0312df 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,7 +44,7 @@ cortex-m = "0.7.0"
cortex-m-rtic-macros = { path = "macros", version = "0.6.0-alpha.5" }
rtic-monotonic = "0.1.0-alpha.2"
rtic-core = "0.3.1"
-heapless = "0.7.1"
+heapless = "0.7.5"
bare-metal = "1.0.0"
[dependencies.dwt-systick-monotonic]
diff --git a/README_ru.md b/README_ru.md
index 918d03e3..49e66d1d 100644
--- a/README_ru.md
+++ b/README_ru.md
@@ -50,10 +50,16 @@
- Приложения должны быть написаны в редакции 2018.
+## [Руководство пользователя](https://rtic.rs) - [(Версия в разработке)](https://rtic.rs/dev)
+
## [Документация пользователя](https://rtic.rs)
## [Справочник по API](https://rtic.rs/stable/api/)
+## [Сборник примеров, предоставляемы сообществом][examples]
+
+[examples]: https://github.com/rtic-rs/rtic-examples
+
## Чат
Присоединяйтесь к нам, чтобы говорить о RTIC [в Matrix-комнате][matrix-room].
diff --git a/book/ru/src/by-example/app.md b/book/ru/src/by-example/app.md
index 628819ad..5beca239 100644
--- a/book/ru/src/by-example/app.md
+++ b/book/ru/src/by-example/app.md
@@ -23,7 +23,7 @@
Внутри модуля `app` атрибут ожидает найти функцию инициализации, помеченную
атрибутом `init`. Эта функция должна иметь сигнатуру
-`fn(init::Context) [-> init::LateResources]` (возвращаемый тип нужен не всегда).
+`fn(init::Context) (-> init::LateResources, init::Monotonics)`.
Эта функция инициализации будет первой частью программы, выполняемой при запуске.
Функция `init` будет запущена *с отключенными прерываниями* и будет иметь эксклюзивный доступ
@@ -54,6 +54,12 @@ $ cargo run --example init
{{#include ../../../../ci/expected/init.run}}
```
+> **ПРИМЕЧАНИЕ**: Не забывайте указывать выбранное вами целевое устройство, передавая параметр target
+> в cargo (например `cargo run --example init --target thumbv7m-none-eabi`) или
+> настроив устройство, используемое по умолчанию для сборки примеров в `.cargo/config.toml`.
+> В нашем случае используется Cortex M3, эмулируемый с помощью QEMU, поэтому пишем `thumbv7m-none-eabi`.
+> Смотрите [`Создание нового проекта`](./new.md) для большей информации.
+
## `idle`
Функцию, помеченную атрибутом `idle` может опционально добавить в модуль.
diff --git a/book/ru/src/by-example/resources.md b/book/ru/src/by-example/resources.md
index 70f798d2..ed8904ba 100644
--- a/book/ru/src/by-example/resources.md
+++ b/book/ru/src/by-example/resources.md
@@ -7,21 +7,26 @@
Фреймворк дает пользователю полный контроль за тем, какой контекст может
получить доступ к какому ресурсу.
-Все ресурсы определены в одной структуре внутри модуля `#[app]`.
-Каждое поле структуры соответствует отдельному ресурсу.
-`struct`-ура должна быть аннотирована следующим атрибутом: `#[resources]`.
-
-Ресурсам могут быть опционально даны начальные значения с помощью атрибута `#[init]`.
-Ресурсы, которым не передано начально значение, называются
-*поздними* ресурсами, более детально они описаны в одном из разделов на этой странице.
+Все ресурсы определены в *двух* структурах внутри модуля `#[app]`.
+Каждое поле этих структур соответствует отдельному ресурсу.
+Одна `struct`-ура должна быть аннотирована атрибутом `#[local]`.
+Другая `struct`-ура должна быть аннотирована атрибутом `#[shared]`.
+Разница между этими двумя множествами ресурсов будет описана познее.
Каждый контекс (задача-обработчик, `init` или `idle`) должен указать ресурсы, к которым
он намерен обращаться, в соответсятвующем ему атрибуте с метаданными, используя
-аргумент `resources`. Этот аргумент принимает список имен ресурсов в качестве значения.
-Перечисленные ресурсы становятся доступны в контексте через поле `resources` структуры `Context`.
+либо аргумент `local`, либо `shared`. Этот аргумент принимает список имен ресурсов в качестве значения.
+Перечисленные ресурсы становятся доступны в контексте через поля `local` и `shared` структуры `Context`.
+
+Во время выполнения при выходе из функции `#[init]` все ресурсы инициализированы.
+Функция `#[init]` должна возвращать начальные значения для всех ресурсов;
+отсюда следует, что тип возвращаемого ею значения включает типы
+структур `#[shared]` и `#[local]`.
+Поскольку ресурсы инициализированы в ходе функции `#[init]`, к ним нельзя
+получить доступ внетри функции `#[init]`.
-Пример программы, показанной ниже содержит два обработчика прерывания, которые разделяют
-доступ к ресурсу под названием `shared`.
+Пример программы, показанной ниже содержит два обработчика прерывания.
+Каждый обработчик имеет доступ к его собственному `#[local]` ресурсу.
``` rust
{{#include ../../../../examples/resource.rs}}
@@ -32,15 +37,17 @@ $ cargo run --example resource
{{#include ../../../../ci/expected/resource.run}}
```
-Заметьте, что к ресурсу `shared` нельзя получить доступ из `idle`. Попытка сделать это
-приведет к ошибке компиляции.
+К ресурсу `#[local]` нельзя получить доступ извне задачи к которой он
+привязан атрибутом `#[task]`.
+Попытка обращения к одному и тому же ресурсу `#[local]` из более чем одной
+задачи - ошибка компиляции.
## `lock`
-Критические секции необходимы для разделения изменяемых данных таким образом,
+Критические секции необходимы для доступа к ресурсам `#[shared]` таким образом,
чтобы избежать гонок данных.
-Поле `resources`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого
+Поле `shared`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого
ресурса, доступного задаче.
Единственный метод этого трейта, [`lock`], запускает свой аргумент-замыкание в критической секции.
@@ -81,33 +88,7 @@ $ cargo run --example lock
{{#include ../../../../examples/multilock.rs}}
```
-## Поздние ресурсы
-
-Поздние ресурсы - такие ресурсы, которым не передано начальное значение во время компиляции
-с помощью атрибута `#[init]`, но которые вместо этого инициализируются во время выполнения
-с помощью значений из структуры `init::LateResources`, возвращаемой функцией `init`.
-
-Поздние ресурсы полезны, например, для *move* (передача владения) периферии,
-инициализированной в `init`, в задачи.
-
-Пример ниже использует поздние ресурсы, чтобы установить неблокируемый односторонний канал
-между обработчиком прерывания `UART0` и задачей `idle`. Для канала использована очередь типа
-один производитель-один потребитель [`Queue`]. Структура очереди разделяется на потребителя
-и производителя в `init`, а затем каждая из частей располагается в отдельном ресурсу;
-`UART0` владеет ресурсом производителя, а `idle` владеет ресурсом потребителя.
-
-[`Queue`]: ../../../api/heapless/spsc/struct.Queue.html
-
-``` rust
-{{#include ../../../../examples/late.rs}}
-```
-
-``` console
-$ cargo run --example late
-{{#include ../../../../ci/expected/late.run}}
-```
-
-## Только разделяемый доступ
+## Только разделяемый (`&-`) доступ
По-умолчанию фреймворк предполагает, что все задачи требуют эксклюзивный доступ (`&mut-`) к ресурсам,
но возможно указать, что задаче достаточен разделяемый доступ (`&-`) к ресурсы с помощью синтакисиса
@@ -139,11 +120,21 @@ $ cargo run --example only-shared-access
## Неблокируемый доступ к изменяемым ресурсам
-Есть две других возможности доступа к ресурсам
+Критическая секция *не* требуется для доступа к ресурсу `#[shared]`,
+к которому обращаются только из задач с *одинаковым* приоритетом.
+В этом случае вы можете избежать `lock` API, добавив атрибут поля `#[lock_free]` при объявдении ресурса (смотреть пример ниже).
+Заметьте, что это лишь для удобства: даже если вы используете `lock` API,
+во время выполнения фреймворк *не* создаст критическую секцию.
+Еще одно ценное замечание: использование `#[lock_free]` на ресурсах,
+разделяемых задачами, запускаемыми с разными приоритетами
+приведет к ошибке *компиляции* -- не импользование `lock` API может
+привести к гонке данных в этом случае.
-* `#[lock_free]`: могут быть несколько задач с одинаковым приоритетом,
- получающие доступ к ресурсу без критических секций. Так как задачи с
- одинаковым приоритетом никогда не могут вытеснить друг друга, это безопасно.
-* `#[task_local]`: в этом случае должна быть только одна задача, использующая
- этот ресурс, так же как локальный `static mut` ресурс задачи, но (опционально) устанавливаемая с в init.
+``` rust
+{{#include ../../../../examples/lock-free.rs}}
+```
+``` console
+$ cargo run --example lock-free
+{{#include ../../../../ci/expected/lock-free.run}}
+``` \ No newline at end of file
diff --git a/book/ru/src/by-example/tips.md b/book/ru/src/by-example/tips.md
index cf66c4b7..f19cfee9 100644
--- a/book/ru/src/by-example/tips.md
+++ b/book/ru/src/by-example/tips.md
@@ -1,5 +1,9 @@
# Советы и хитрости
+Полные примеры для RTIC смотрите в репозитарии [rtic-examples][rtic-examples].
+
+[rtic-examples]: https://github.com/rtic-rs/rtic-examples
+
## Обобщенное программирование (Generics)
Все объекты, предоставляющие ресурысы реализуют трейт `rtic::Mutex`.
diff --git a/book/ru/src/internals/late-resources.md b/book/ru/src/internals/late-resources.md
index 0fad0aec..146c438d 100644
--- a/book/ru/src/internals/late-resources.md
+++ b/book/ru/src/internals/late-resources.md
@@ -103,8 +103,7 @@ mod app {
}
```
-Важная деталь здесь то, что `interrupt::enable` ведет себя как like a *compiler
-fence*, которое не дает компилятору пореставить запись в `X` *после*
+Важная деталь здесь то, что `interrupt::enable` ведет себя как *барьер компиляции*, который не дает компилятору переставить запись в `X` *после*
`interrupt::enable`. Если бы компилятор мог делать такие перестановки появились
бы гонки данных между этой записью и любой операцией `foo`, взаимодействующей с `X`.
diff --git a/book/ru/src/internals/tasks.md b/book/ru/src/internals/tasks.md
index 66503251..01380ba9 100644
--- a/book/ru/src/internals/tasks.md
+++ b/book/ru/src/internals/tasks.md
@@ -79,8 +79,8 @@ mod app {
}
// очередь готовности диспетчера задач
- // `U4` - целое число, представляющее собой емкость этой очереди
- static mut RQ1: Queue<Ready<T1>, U4> = Queue::new();
+ // `5-1=4` - представляет собой емкость этой очереди
+ static mut RQ1: Queue<Ready<T1>, 5> = Queue::new();
// обработчик прерывания, выбранный для диспетчеризации задач с приоритетом `1`
#[no_mangle]
@@ -151,9 +151,9 @@ mod app {
const RQ1_CEILING: u8 = 2;
// используется, чтобы отследить сколько еще сообщений для `bar` можно поставить в очередь
- // `U2` - емкость задачи `bar`; максимум 2 экземпляра можно добавить в очередь
+ // `3-1=2` - емкость задачи `bar`; максимум 2 экземпляра можно добавить в очередь
// эта очередь заполняется фреймворком до того, как запустится `init`
- static mut bar_FQ: Queue<(), U2> = Queue::new();
+ static mut bar_FQ: Queue<(), 3> = Queue::new();
// Поиск максимального приоритета для конечного потребителя `bar_FQ`
const bar_FQ_CEILING: u8 = 2;
@@ -227,7 +227,7 @@ mod app {
// список свободной памяти: используется для отслеживания свободных ячеек в массиве `baz_INPUTS`
// эта очередь инициализируется значениями `0` и `1` перед запуском `init`
- static mut baz_FQ: Queue<u8, U2> = Queue::new();
+ static mut baz_FQ: Queue<u8, 3> = Queue::new();
// Поиск максимального приоритета для конечного потребителя `baz_FQ`
const baz_FQ_CEILING: u8 = 2;
diff --git a/book/ru/src/migration/migration_v5.md b/book/ru/src/migration/migration_v5.md
index 04aedc5f..870c20fd 100644
--- a/book/ru/src/migration/migration_v5.md
+++ b/book/ru/src/migration/migration_v5.md
@@ -30,7 +30,46 @@ mod app {
Так как теперь используется обычный модуль Rust, это значит, что можно использовать
обычный пользовательский код в этом модуле.
-Также жто значит, что `use`-выражения для ресурсов (и т.п.) могут понадобиться.
+Также это значит, что `use`-выражения для ресурсов, используемые
+в пользовательском коде должны быть перемещены внутрь `mod app`,
+либо на них можно сослаться с помощью `super`. Например, измените:
+
+```rust
+use some_crate::some_func;
+
+#[rtic::app(/* .. */)]
+const APP: () = {
+ fn func() {
+ some_crate::some_func();
+ }
+};
+```
+
+на
+
+```rust
+#[rtic::app(/* .. */)]
+mod app {
+ use some_crate::some_func;
+
+ fn func() {
+ some_crate::some_func();
+ }
+}
+```
+
+или
+
+```rust
+use some_crate::some_func;
+
+#[rtic::app(/* .. */)]
+mod app {
+ fn func() {
+ super::some_crate::some_func();
+ }
+}
+```
## Перенос диспетчеров из `extern "C"` в аргументы app.
@@ -63,137 +102,255 @@ mod app {
Это работает и для ОЗУ-функций, см. examples/ramfunc.rs
-## Init всегда возвращает поздние ресурсы
+## Структуры ресурсов - `#[shared]`, `#[local]`
-С целью сделать API более симметричным задача #[init] всегда возвращает поздние ресурсы.
+Ранее ресурсы RTIC должны были размещаться в структуре с именем "Resources":
-С этого:
+``` rust
+struct Resources {
+ // Ресурсы определяются здесь
+}
+```
+
+Начиная с RTIC v0.6.0 структуры ресурсов аннотируются подобно
+`#[task]`, `#[init]`, `#[idle]`: аттрибутами `#[shared]` и `#[local]`
``` rust
-#[rtic::app(device = lm3s6965)]
-mod app {
- #[init]
- fn init(_: init::Context) {
- rtic::pend(Interrupt::UART0);
- }
+#[shared]
+struct MySharedResources {
+ // Разделяемые задачами ресурсы определены здесь
+}
- // [еще код]
+#[local]
+struct MyLocalResources {
+ // Ресурсы, определенные здесь нельзя передавать между задачами; каждый из них локальный для единственной задачи
}
```
-на это:
+Эти структуры разработчик может называть по своему желанию.
+
+## `shared` и `local` аргументы в `#[task]`'ах
+
+В v0.6.0 ресурсы разделены на `shared` ресурсы и `local` ресурсы.
+`#[task]`, `#[init]` и `#[idle]` больше не имеют аргумента `resources`;
+они должны использовать аргументы `shared` и `local`.
+
+В v0.5.x:
``` rust
-#[rtic::app(device = lm3s6965)]
-mod app {
- #[init]
- fn init(_: init::Context) -> init::LateResources {
- rtic::pend(Interrupt::UART0);
+struct Resources {
+ local_to_b: i64,
+ shared_by_a_and_b: i64,
+}
- init::LateResources {}
- }
+#[task(resources = [shared_by_a_and_b])]
+fn a(_: a::Context) {}
- // [еще код]
+#[task(resources = [shared_by_a_and_b, local_to_b])]
+fn b(_: b::Context) {}
+```
+
+В v0.6.0:
+
+``` rust
+#[shared]
+struct Shared {
+ shared_by_a_and_b: i64,
}
+
+#[local]
+struct Local {
+ local_to_b: i64,
+}
+
+#[task(shared = [shared_by_a_and_b])]
+fn a(_: a::Context) {}
+
+#[task(shared = [shared_by_a_and_b], local = [local_to_b])]
+fn b(_: b::Context) {}
```
-## Структура Resources - `#[resources]`
+## Симметричные блокировки
-Ранее ресурсы RTIC должны были располагаться в структуре с именем "Resources":
+Теперь RTIC использует симметричные блокировки, это значит, что метод `lock` нужно использовать для
+всех доступов к `shared` ресурсам. Поскольку высокоприоритетные задачи имеют эксклюзивный доступ к ресурсу,
+в старом коде можно было следующее:
``` rust
-struct Resources {
- // Ресурсы определены здесь
+#[task(priority = 2, resources = [r])]
+fn foo(cx: foo::Context) {
+ cx.resources.r = /* ... */;
+}
+
+#[task(resources = [r])]
+fn bar(cx: bar::Context) {
+ cx.resources.r.lock(|r| r = /* ... */);
}
```
-В RTIC v0.6.0 структура ресурсов аннотируется также, как и
-`#[task]`, `#[init]`, `#[idle]`: атрибутом `#[resources]`
+С симметричными блокировками нужно вызывать `lock` для обоих задач:
``` rust
-#[resources]
-struct Resources {
- // Ресурсы определены здесь
+#[task(priority = 2, shared = [r])]
+fn foo(cx: foo::Context) {
+ cx.shared.r.lock(|r| r = /* ... */);
+}
+
+#[task(shared = [r])]
+fn bar(cx: bar::Context) {
+ cx.shared.r.lock(|r| r = /* ... */);
}
```
-На самом деле, имя структуры предоставлено на усмотрение разработчика:
+Заметьте, что скорость работы не изменяется благодаря оптимизациям LLVM, которые убирают ненужные блокировки.
+
+## Неблокирующий доступ к ресурсам
+
+В RTIC 0.5 к ресурсам разделяемым задачами, запускаемыми с одинаковым
+приоритетом, можно получить доступ *без* `lock` API.
+Это все еще возможно в 0.6: ресурс `#[shared]` должен быть аннотирован
+аттрибутом поля `#[lock_free]`.
+
+v0.5 код:
``` rust
-#[resources]
-struct Whateveryouwant {
- // Ресурсы определены здесь
+struct Resources {
+ counter: u64,
+}
+
+#[task(resources = [counter])]
+fn a(cx: a::Context) {
+ *cx.resources.counter += 1;
+}
+
+#[task(resources = [counter])]
+fn b(cx: b::Context) {
+ *cx.resources.counter += 1;
}
```
-будет работать так же хороршо.
+v0.6 код:
-## Вызов/планирование откуда угодно
+``` rust
+#[shared]
+struct Shared {
+ #[lock_free]
+ counter: u64,
+}
-С этой новой возвожностью, старый код, такой как:
+#[task(shared = [counter])]
+fn a(cx: a::Context) {
+ *cx.shared.counter += 1;
+}
+
+#[task(shared = [counter])]
+fn b(cx: b::Context) {
+ *cx.shared.counter += 1;
+}
+```
+
+## нет преобразования `static mut`
+`static mut` переменные больше не преобразуются в безопасные `&'static mut` ссылки.
+Вместо этого синтаксиса используйте аргумент `local` в `#[init]`.
+
+v0.5.x code:
``` rust
-#[task(spawn = [bar])]
-fn foo(cx: foo::Context) {
- cx.spawn.bar().unwrap();
+#[init]
+fn init(_: init::Context) {
+ static mut BUFFER: [u8; 1024] = [0; 1024];
+ let buffer: &'static mut [u8; 1024] = BUFFER;
}
+```
-#[task(schedule = [bar])]
-fn bar(cx: bar::Context) {
- cx.schedule.foo(/* ... */).unwrap();
+v0.6.0 code:
+
+``` rust
+#[init(local = [
+ buffer: [u8; 1024] = [0; 1024]
+// type ^^^^^^^^^^^^ ^^^^^^^^^ initial value
+])]
+fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
+ let buffer: &'static mut [u8; 1024] = cx.local.buffer;
+
+ (Shared {}, Local {}, init::Monotonics())
}
```
-Теперь будет выглядеть так:
+## Init всегда возвращает поздние ресурсы
+
+С целью сделать API более симметричным задача #[init] всегда возвращает поздние ресурсы.
+
+С этого:
``` rust
-#[task]
-fn foo(_c: foo::Context) {
- bar::spawn().unwrap();
+#[rtic::app(device = lm3s6965)]
+mod app {
+ #[init]
+ fn init(_: init::Context) {
+ rtic::pend(Interrupt::UART0);
+ }
+
+ // [еще код]
}
+```
-#[task]
-fn bar(_c: bar::Context) {
- foo::schedule(/* ... */).unwrap();
+на это:
+
+
+``` rust
+#[rtic::app(device = lm3s6965)]
+mod app {
+ #[shared]
+ struct MySharedResources {}
+
+ #[local]
+ struct MyLocalResources {}
+
+ #[init]
+ fn init(_: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
+ rtic::pend(Interrupt::UART0);
+
+ (MySharedResources, MyLocalResources, init::Monotonics())
+ }
+
+ // [more code]
}
```
-Заметьте, что атрибуты `spawn` и `schedule` больше не нужны.
+## Вызов/планирование откуда угодно
-## Симметричные блокировки
+С этой новой возвожностью, старый код, такой как:
-Теперь RTIC использует симметричные блокировки, это значит, что метод `lock` нужно использовать для
-всех доступов к ресурсам. Поскольку высокоприоритетные задачи имеют эксклюзивный доступ к ресурсу,
-в старом коде можно было следующее:
``` rust
-#[task(priority = 2, resources = [r])]
+#[task(spawn = [bar])]
fn foo(cx: foo::Context) {
- cx.resources.r = /* ... */;
+ cx.spawn.bar().unwrap();
}
-#[task(resources = [r])]
+#[task(schedule = [bar])]
fn bar(cx: bar::Context) {
- cx.resources.r.lock(|r| r = /* ... */);
+ cx.schedule.foo(/* ... */).unwrap();
}
```
-С симметричными блокировками нужно вызывать `lock` для обоих задач:
+Теперь будет выглядеть так:
``` rust
-#[task(priority = 2, resources = [r])]
-fn foo(cx: foo::Context) {
- cx.resources.r.lock(|r| r = /* ... */);
+#[task]
+fn foo(_c: foo::Context) {
+ bar::spawn().unwrap();
}
-#[task(resources = [r])]
-fn bar(cx: bar::Context) {
- cx.resources.r.lock(|r| r = /* ... */);
+#[task]
+fn bar(_c: bar::Context) {
+ foo::schedule(/* ... */).unwrap();
}
```
-Заметьте, что скорость работы не изменяется благодаря оптимизациям LLVM, которые убирают ненужные блокировки.
+Заметьте, что атрибуты `spawn` и `schedule` больше не нужны.
---
diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs
index 6920031a..63a4e3ca 100644
--- a/macros/src/codegen.rs
+++ b/macros/src/codegen.rs
@@ -108,7 +108,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
let name = &monotonic.ident;
let name_str = &name.to_string();
let ident = util::monotonic_ident(&name_str);
- let ident = util::mark_internal_ident(&ident);
let panic_str = &format!(
"Use of monotonic '{}' before it was passed to the runtime",
name_str
diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs
index c239b0f8..57103acd 100644
--- a/macros/src/codegen/dispatchers.rs
+++ b/macros/src/codegen/dispatchers.rs
@@ -33,6 +33,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
// );
let t = util::spawn_t_ident(level);
items.push(quote!(
+ #[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
// #[doc = #doc]
@@ -44,7 +45,6 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let n = util::capacity_literal(channel.capacity as usize + 1);
let rq = util::rq_ident(level);
- let rq = util::mark_internal_ident(&rq);
let (rq_ty, rq_expr) = {
(
quote!(rtic::export::SCRQ<#t, #n>),
@@ -59,6 +59,8 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
// );
items.push(quote!(
#[doc(hidden)]
+ #[allow(non_camel_case_types)]
+ #[allow(non_upper_case_globals)]
static #rq: rtic::RacyCell<#rq_ty> = rtic::RacyCell::new(#rq_expr);
));
@@ -69,9 +71,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let task = &app.software_tasks[name];
let cfgs = &task.cfgs;
let fq = util::fq_ident(name);
- let fq = util::mark_internal_ident(&fq);
let inputs = util::inputs_ident(name);
- let inputs = util::mark_internal_ident(&inputs);
let (_, tupled, pats, _) = util::regroup_inputs(&task.inputs);
quote!(
diff --git a/macros/src/codegen/local_resources.rs b/macros/src/codegen/local_resources.rs
index a9ffa925..ff534862 100644
--- a/macros/src/codegen/local_resources.rs
+++ b/macros/src/codegen/local_resources.rs
@@ -24,7 +24,7 @@ pub fn codegen(
for (name, res) in &app.local_resources {
let cfgs = &res.cfgs;
let ty = &res.ty;
- let mangled_name = util::mark_internal_ident(&util::static_local_resource_ident(name));
+ let mangled_name = util::static_local_resource_ident(name);
let attrs = &res.attrs;
// late resources in `util::link_section_uninit`
@@ -33,6 +33,7 @@ pub fn codegen(
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
mod_app.push(quote!(
+ #[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
// #[doc = #doc]
#[doc(hidden)]
@@ -50,14 +51,12 @@ pub fn codegen(
let expr = &task_local.expr;
let attrs = &task_local.attrs;
- let mangled_name = util::mark_internal_ident(&util::declared_static_local_resource_ident(
- resource_name,
- &task_name,
- ));
+ let mangled_name = util::declared_static_local_resource_ident(resource_name, &task_name);
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
mod_app.push(quote!(
+ #[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
// #[doc = #doc]
#[doc(hidden)]
diff --git a/macros/src/codegen/local_resources_struct.rs b/macros/src/codegen/local_resources_struct.rs
index 4bd9e2a4..cdbfccca 100644
--- a/macros/src/codegen/local_resources_struct.rs
+++ b/macros/src/codegen/local_resources_struct.rs
@@ -44,11 +44,9 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
};
let mangled_name = if matches!(task_local, TaskLocal::External) {
- util::mark_internal_ident(&util::static_local_resource_ident(name))
+ util::static_local_resource_ident(name)
} else {
- util::mark_internal_ident(&util::declared_static_local_resource_ident(
- name, &task_name,
- ))
+ util::declared_static_local_resource_ident(name, &task_name)
};
fields.push(quote!(
@@ -86,9 +84,9 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
let doc = format!("Local resources `{}` has access to", ctxt.ident(app));
let ident = util::local_resources_ident(ctxt, app);
- let ident = util::mark_internal_ident(&ident);
let item = quote!(
#[allow(non_snake_case)]
+ #[allow(non_camel_case_types)]
#[doc = #doc]
pub struct #ident<#lt> {
#(#fields,)*
diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs
index c7092bd3..4db2c0c2 100644
--- a/macros/src/codegen/module.rs
+++ b/macros/src/codegen/module.rs
@@ -67,7 +67,6 @@ pub fn codegen(
if ctxt.has_local_resources(app) {
let ident = util::local_resources_ident(ctxt, app);
- let ident = util::mark_internal_ident(&ident);
let lt = if local_resources_tick {
lt = Some(quote!('a));
Some(quote!('a))
@@ -90,7 +89,6 @@ pub fn codegen(
if ctxt.has_shared_resources(app) {
let ident = util::shared_resources_ident(ctxt, app);
- let ident = util::mark_internal_ident(&ident);
let lt = if shared_resources_tick {
lt = Some(quote!('a));
Some(quote!('a))
@@ -131,6 +129,7 @@ pub fn codegen(
items.push(quote!(
/// Monotonics used by the system
#[allow(non_snake_case)]
+ #[allow(non_camel_case_types)]
pub struct #internal_monotonics_ident(
#(pub #monotonic_types),*
);
@@ -178,6 +177,8 @@ pub fn codegen(
items.push(quote!(
#(#cfgs)*
/// Execution context
+ #[allow(non_snake_case)]
+ #[allow(non_camel_case_types)]
pub struct #internal_context_name<#lt> {
#(#fields,)*
}
@@ -209,11 +210,8 @@ pub fn codegen(
let args = &args;
let tupled = &tupled;
let fq = util::fq_ident(name);
- let fq = util::mark_internal_ident(&fq);
let rq = util::rq_ident(priority);
- let rq = util::mark_internal_ident(&rq);
let inputs = util::inputs_ident(name);
- let inputs = util::mark_internal_ident(&inputs);
let device = &extra.device;
let enum_ = util::interrupt_ident();
@@ -263,16 +261,13 @@ pub fn codegen(
// Schedule caller
for (_, monotonic) in &app.monotonics {
let instants = util::monotonic_instants_ident(name, &monotonic.ident);
- let instants = util::mark_internal_ident(&instants);
let monotonic_name = monotonic.ident.to_string();
let tq = util::tq_ident(&monotonic.ident.to_string());
- let tq = util::mark_internal_ident(&tq);
let t = util::schedule_t_ident();
let m = &monotonic.ident;
let mono_type = &monotonic.ident;
let m_ident = util::monotonic_ident(&monotonic_name);
- let m_ident = util::mark_internal_ident(&m_ident);
let m_isr = &monotonic.args.binds;
let enum_ = util::interrupt_ident();
@@ -290,7 +285,7 @@ pub fn codegen(
)
};
- let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
+ let tq_marker = &util::timer_queue_marker_ident();
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
@@ -318,6 +313,8 @@ pub fn codegen(
items.push(quote!(
#(#cfgs)*
+ #[allow(non_snake_case)]
+ #[allow(non_camel_case_types)]
pub struct #internal_spawn_handle_ident {
#[doc(hidden)]
marker: u32,
@@ -327,7 +324,7 @@ pub fn codegen(
impl #internal_spawn_handle_ident {
pub fn cancel(self) -> Result<#ty, ()> {
rtic::export::interrupt::free(|_| unsafe {
- let tq = &mut *#tq.get_mut_unchecked().as_mut_ptr();
+ let tq = #tq.get_mut_unchecked();
if let Some((_task, index)) = tq.cancel_marker(self.marker) {
// Get the message
let msg = #inputs
@@ -359,7 +356,7 @@ pub fn codegen(
let marker = *#tq_marker.get_mut_unchecked();
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
- let tq = &mut *#tq.get_mut_unchecked().as_mut_ptr();
+ let tq = #tq.get_mut_unchecked();
tq.update_marker(self.marker, marker, instant, || #pend).map(|_| #name::#m::SpawnHandle { marker })
})
@@ -371,6 +368,7 @@ pub fn codegen(
///
/// This will use the time `Instant::new(0)` as baseline if called in `#[init]`,
/// so if you use a non-resetable timer use `spawn_at` when in `#[init]`
+ #[allow(non_snake_case)]
pub fn #internal_spawn_after_ident<D>(
duration: D
#(,#args)*
@@ -390,6 +388,7 @@ pub fn codegen(
#(#cfgs)*
/// Spawns the task at a fixed time instant
+ #[allow(non_snake_case)]
pub fn #internal_spawn_at_ident(
instant: rtic::time::Instant<#mono_type>
#(,#args)*
@@ -420,7 +419,7 @@ pub fn codegen(
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
- let tq = &mut *#tq.get_mut_unchecked().as_mut_ptr();
+ let tq = #tq.get_mut_unchecked();
tq.enqueue_unchecked(
nr,
diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs
index 161068d2..5624b20a 100644
--- a/macros/src/codegen/post_init.rs
+++ b/macros/src/codegen/post_init.rs
@@ -11,7 +11,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
// Initialize shared resources
for (name, res) in &app.shared_resources {
- let mangled_name = util::mark_internal_ident(&util::static_shared_resource_ident(name));
+ let mangled_name = util::static_shared_resource_ident(name);
// If it's live
let cfgs = res.cfgs.clone();
if analysis.shared_resource_locations.get(name).is_some() {
@@ -29,7 +29,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
// Initialize local resources
for (name, res) in &app.local_resources {
- let mangled_name = util::mark_internal_ident(&util::static_local_resource_ident(name));
+ let mangled_name = util::static_local_resource_ident(name);
// If it's live
let cfgs = res.cfgs.clone();
if analysis.local_resource_locations.get(name).is_some() {
@@ -58,7 +58,6 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
// Store the monotonic
let name = util::monotonic_ident(&monotonic.to_string());
- let name = util::mark_internal_ident(&name);
stmts.push(quote!(*#name.get_mut_unchecked() = Some(monotonics.#idx);));
}
diff --git a/macros/src/codegen/pre_init.rs b/macros/src/codegen/pre_init.rs
index ae628f6e..d3c4f54d 100644
--- a/macros/src/codegen/pre_init.rs
+++ b/macros/src/codegen/pre_init.rs
@@ -17,7 +17,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
for (name, task) in &app.software_tasks {
let cap = task.args.capacity;
let fq_ident = util::fq_ident(name);
- let fq_ident = util::mark_internal_ident(&fq_ident);
stmts.push(quote!(
(0..#cap).for_each(|i| #fq_ident.get_mut_unchecked().enqueue_unchecked(i));
@@ -77,18 +76,10 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
);));
}
- // Initialize monotonic's interrupts and timer queues
+ // Initialize monotonic's interrupts
for (_, monotonic) in &app.monotonics {
let priority = &monotonic.args.priority;
let binds = &monotonic.args.binds;
- let monotonic_name = monotonic.ident.to_string();
- let tq = util::tq_ident(&monotonic_name);
- let tq = util::mark_internal_ident(&tq);
-
- // Initialize timer queues
- stmts.push(
- quote!(#tq.get_mut_unchecked().as_mut_ptr().write(rtic::export::TimerQueue::new());),
- );
// Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
diff --git a/macros/src/codegen/shared_resources.rs b/macros/src/codegen/shared_resources.rs
index 181832fd..07f8c36a 100644
--- a/macros/src/codegen/shared_resources.rs
+++ b/macros/src/codegen/shared_resources.rs
@@ -21,7 +21,7 @@ pub fn codegen(
for (name, res) in &app.shared_resources {
let cfgs = &res.cfgs;
let ty = &res.ty;
- let mangled_name = util::mark_internal_ident(&util::static_shared_resource_ident(&name));
+ let mangled_name = &util::static_shared_resource_ident(&name);
// late resources in `util::link_section_uninit`
let section = util::link_section_uninit();
@@ -30,6 +30,7 @@ pub fn codegen(
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
mod_app.push(quote!(
+ #[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
// #[doc = #doc]
#[doc(hidden)]
diff --git a/macros/src/codegen/shared_resources_struct.rs b/macros/src/codegen/shared_resources_struct.rs
index 301bef73..5a805412 100644
--- a/macros/src/codegen/shared_resources_struct.rs
+++ b/macros/src/codegen/shared_resources_struct.rs
@@ -32,7 +32,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
None
};
let ty = &res.ty;
- let mangled_name = util::mark_internal_ident(&util::static_shared_resource_ident(&name));
+ let mangled_name = util::static_shared_resource_ident(&name);
if !res.properties.lock_free {
if access.is_shared() {
@@ -102,9 +102,9 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
let doc = format!("Shared resources `{}` has access to", ctxt.ident(app));
let ident = util::shared_resources_ident(ctxt, app);
- let ident = util::mark_internal_ident(&ident);
let item = quote!(
#[allow(non_snake_case)]
+ #[allow(non_camel_case_types)]
#[doc = #doc]
pub struct #ident<#lt> {
#(#fields,)*
diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs
index 0b073359..1669a3fb 100644
--- a/macros/src/codegen/software_tasks.rs
+++ b/macros/src/codegen/software_tasks.rs
@@ -37,7 +37,6 @@ pub fn codegen(
// Create free queues and inputs / instants buffers
let fq = util::fq_ident(name);
- let fq = util::mark_internal_ident(&fq);
let (fq_ty, fq_expr, mk_uninit): (_, _, Box<dyn Fn() -> Option<_>>) = {
(
@@ -49,6 +48,8 @@ pub fn codegen(
mod_app.push(quote!(
// /// Queue version of a free-list that keeps track of empty slots in
// /// the following buffers
+ #[allow(non_camel_case_types)]
+ #[allow(non_upper_case_globals)]
#[doc(hidden)]
static #fq: rtic::RacyCell<#fq_ty> = rtic::RacyCell::new(#fq_expr);
));
@@ -59,7 +60,6 @@ pub fn codegen(
for (_, monotonic) in &app.monotonics {
let instants = util::monotonic_instants_ident(name, &monotonic.ident);
- let instants = util::mark_internal_ident(&instants);
let mono_type = &monotonic.ty;
let uninit = mk_uninit();
@@ -69,6 +69,8 @@ pub fn codegen(
#uninit
// /// Buffer that holds the instants associated to the inputs of a task
// #[doc = #doc]
+ #[allow(non_camel_case_types)]
+ #[allow(non_upper_case_globals)]
#[doc(hidden)]
static #instants:
rtic::RacyCell<[core::mem::MaybeUninit<rtic::time::Instant<#mono_type>>; #cap_lit]> =
@@ -78,10 +80,11 @@ pub fn codegen(
let uninit = mk_uninit();
let inputs_ident = util::inputs_ident(name);
- let inputs_ident = util::mark_internal_ident(&inputs_ident);
mod_app.push(quote!(
#uninit
// /// Buffer that holds the inputs of a task
+ #[allow(non_camel_case_types)]
+ #[allow(non_upper_case_globals)]
#[doc(hidden)]
static #inputs_ident: rtic::RacyCell<[core::mem::MaybeUninit<#input_ty>; #cap_lit]> =
rtic::RacyCell::new([#(#elems,)*]);
diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs
index abddbadc..fdfa6381 100644
--- a/macros/src/codegen/timer_queue.rs
+++ b/macros/src/codegen/timer_queue.rs
@@ -10,11 +10,12 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
if !app.monotonics.is_empty() {
// Generate the marker counter used to track for `cancel` and `reschedule`
- let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
+ let tq_marker = util::timer_queue_marker_ident();
items.push(quote!(
// #[doc = #doc]
#[doc(hidden)]
#[allow(non_camel_case_types)]
+ #[allow(non_upper_case_globals)]
static #tq_marker: rtic::RacyCell<u32> = rtic::RacyCell::new(0);
));
@@ -52,40 +53,40 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
for (_, monotonic) in &app.monotonics {
let monotonic_name = monotonic.ident.to_string();
let tq = util::tq_ident(&monotonic_name);
- let tq = util::mark_internal_ident(&tq);
let t = util::schedule_t_ident();
let mono_type = &monotonic.ty;
let m_ident = util::monotonic_ident(&monotonic_name);
- let m_ident = util::mark_internal_ident(&m_ident);
// Static variables and resource proxy
{
// For future use
// let doc = &format!("Timer queue for {}", monotonic_name);
- let cap: u8 = app
+ let cap: usize = app
.software_tasks
.iter()
- .map(|(_name, task)| task.args.capacity)
+ .map(|(_name, task)| task.args.capacity as usize)
.sum();
- let n = util::capacity_literal(cap as usize);
- let tq_ty =
- quote!(core::mem::MaybeUninit<rtic::export::TimerQueue<#mono_type, #t, #n>>);
+ let n = util::capacity_literal(cap);
+ let tq_ty = quote!(rtic::export::TimerQueue<#mono_type, #t, #n>);
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
items.push(quote!(
#[doc(hidden)]
+ #[allow(non_camel_case_types)]
+ #[allow(non_upper_case_globals)]
static #tq: rtic::RacyCell<#tq_ty> =
- rtic::RacyCell::new(core::mem::MaybeUninit::uninit());
+ rtic::RacyCell::new(rtic::export::TimerQueue(rtic::export::SortedLinkedList::new_u16()));
));
let mono = util::monotonic_ident(&monotonic_name);
- let mono = util::mark_internal_ident(&mono);
// For future use
// let doc = &format!("Storage for {}", monotonic_name);
items.push(quote!(
#[doc(hidden)]
+ #[allow(non_camel_case_types)]
+ #[allow(non_upper_case_globals)]
static #mono: rtic::RacyCell<Option<#mono_type>> = rtic::RacyCell::new(None);
));
}
@@ -102,7 +103,6 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let cfgs = &task.cfgs;
let priority = task.args.priority;
let rq = util::rq_ident(priority);
- let rq = util::mark_internal_ident(&rq);
let rqt = util::spawn_t_ident(priority);
// The interrupt that runs the task dispatcher
@@ -138,7 +138,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
unsafe fn #bound_interrupt() {
while let Some((task, index)) = rtic::export::interrupt::free(|_|
if let Some(mono) = #m_ident.get_mut_unchecked().as_mut() {
- (&mut *#tq.get_mut_unchecked().as_mut_ptr()).dequeue(|| #disable_isr, mono)
+ #tq.get_mut_unchecked().dequeue(|| #disable_isr, mono)
} else {
// We can only use the timer queue if `init` has returned, and it
// writes the `Some(monotonic)` we are accessing here.
diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs
index c2330d46..8e40ad61 100644
--- a/macros/src/codegen/util.rs
+++ b/macros/src/codegen/util.rs
@@ -7,6 +7,8 @@ use syn::{Attribute, Ident, LitInt, PatType};
use crate::check::Extra;
+const RTIC_INTERNAL: &str = "__rtic_internal";
+
/// Turns `capacity` into an unsuffixed integer literal
pub fn capacity_literal(capacity: usize) -> LitInt {
LitInt::new(&capacity.to_string(), Span::call_site())
@@ -14,7 +16,7 @@ pub fn capacity_literal(capacity: usize) -> LitInt {
/// Identifier for the free queue
pub fn fq_ident(task: &Ident) -> Ident {
- Ident::new(&format!("{}_FQ", task.to_string()), Span::call_site())
+ mark_internal_name(&format!("{}_FQ", task.to_string()))
}
/// Generates a `Mutex` implementation
@@ -60,15 +62,12 @@ pub fn impl_mutex(
/// Generates an identifier for the `INPUTS` buffer (`spawn` & `schedule` API)
pub fn inputs_ident(task: &Ident) -> Ident {
- Ident::new(&format!("{}_INPUTS", task), Span::call_site())
+ mark_internal_name(&format!("{}_INPUTS", task))
}
/// Generates an identifier for the `INSTANTS` buffer (`schedule` API)
pub fn monotonic_instants_ident(task: &Ident, monotonic: &Ident) -> Ident {
- Ident::new(
- &format!("{}_{}_INSTANTS", task, monotonic),
- Span::call_site(),
- )
+ mark_internal_name(&format!("{}_{}_INSTANTS", task, monotonic))
}
pub fn interrupt_ident() -> Ident {
@@ -77,8 +76,7 @@ pub fn interrupt_ident() -> Ident {
}
pub fn timer_queue_marker_ident() -> Ident {
- let span = Span::call_site();
- Ident::new("TIMER_QUEUE_MARKER", span)
+ mark_internal_name(&"TIMER_QUEUE_MARKER")
}
/// Whether `name` is an exception with configurable priority
@@ -98,38 +96,24 @@ pub fn is_exception(name: &Ident) -> bool {
)
}
+/// Mark a name as internal
+pub fn mark_internal_name(name: &str) -> Ident {
+ Ident::new(&format!("{}_{}", RTIC_INTERNAL, name), Span::call_site())
+}
+
/// Generate an internal identifier for monotonics
pub fn internal_monotonics_ident(task: &Ident, monotonic: &Ident, ident_name: &str) -> Ident {
- Ident::new(
- &format!(
- "__rtic_internal_{}_{}_{}",
- task.to_string(),
- monotonic.to_string(),
- ident_name,
- ),
- Span::call_site(),
- )
+ mark_internal_name(&format!(
+ "{}_{}_{}",
+ task.to_string(),
+ monotonic.to_string(),
+ ident_name,
+ ))
}
/// Generate an internal identifier for tasks
pub fn internal_task_ident(task: &Ident, ident_name: &str) -> Ident {
- Ident::new(
- &format!("__rtic_internal_{}_{}", task.to_string(), ident_name,),
- Span::call_site(),
- )
-}
-
-/// Mark an ident as internal
-pub fn mark_internal_ident(ident: &Ident) -> Ident {
- Ident::new(
- &format!("__rtic_internal_{}", ident.to_string()),
- Span::call_site(),
- )
-}
-
-/// Mark an ident as internal
-pub fn mark_internal_name(name: &str) -> Ident {
- Ident::new(&format!("__rtic_internal_{}", name), Span::call_site())
+ mark_internal_name(&format!("{}_{}", task.to_string(), ident_name))
}
fn link_section_index() -> usize {
@@ -215,7 +199,7 @@ pub fn shared_resources_ident(ctxt: Context, app: &App) -> Ident {
s.push_str("SharedResources");
- Ident::new(&s, Span::call_site())
+ mark_internal_name(&s)
}
/// Generates a pre-reexport identifier for the "local resources" struct
@@ -228,7 +212,7 @@ pub fn local_resources_ident(ctxt: Context, app: &App) -> Ident {
s.push_str("LocalResources");
- Ident::new(&s, Span::call_site())
+ mark_internal_name(&s)
}
/// Generates an identifier for a ready queue
@@ -236,7 +220,7 @@ pub fn local_resources_ident(ctxt: Context, app: &App) -> Ident {
/// There may be several task dispatchers, one for each priority level.
/// The ready queues are SPSC queues
pub fn rq_ident(priority: u8) -> Ident {
- Ident::new(&format!("P{}_RQ", priority), Span::call_site())
+ mark_internal_name(&format!("P{}_RQ", priority))
}
/// Generates an identifier for the `enum` of `schedule`-able tasks
@@ -260,33 +244,28 @@ pub fn suffixed(name: &str) -> Ident {
/// Generates an identifier for a timer queue
pub fn tq_ident(name: &str) -> Ident {
- Ident::new(&format!("TQ_{}", name), Span::call_site())
+ mark_internal_name(&format!("TQ_{}", name))
}
/// Generates an identifier for monotonic timer storage
pub fn monotonic_ident(name: &str) -> Ident {
- Ident::new(&format!("MONOTONIC_STORAGE_{}", name), Span::call_site())
+ mark_internal_name(&format!("MONOTONIC_STORAGE_{}", name))
}
pub fn static_shared_resource_ident(name: &Ident) -> Ident {
- Ident::new(
- &format!("shared_resource_{}", name.to_string()),
- Span::call_site(),
- )
+ mark_internal_name(&format!("shared_resource_{}", name.to_string()))
}
pub fn static_local_resource_ident(name: &Ident) -> Ident {
- Ident::new(
- &format!("local_resource_{}", name.to_string()),
- Span::call_site(),
- )
+ mark_internal_name(&format!("local_resource_{}", name.to_string()))
}
pub fn declared_static_local_resource_ident(name: &Ident, task_name: &Ident) -> Ident {
- Ident::new(
- &format!("local_{}_{}", task_name.to_string(), name.to_string()),
- Span::call_site(),
- )
+ mark_internal_name(&format!(
+ "local_{}_{}",
+ task_name.to_string(),
+ name.to_string()
+ ))
}
/// The name to get better RT flag errors
diff --git a/src/export.rs b/src/export.rs
index e449ef41..927e951e 100644
--- a/src/export.rs
+++ b/src/export.rs
@@ -13,6 +13,7 @@ pub use cortex_m::{
peripheral::{scb::SystemHandler, syst::SystClkSource, DWT, NVIC},
Peripherals,
};
+pub use heapless::sorted_linked_list::SortedLinkedList;
pub use heapless::spsc::Queue;
pub use heapless::BinaryHeap;
pub use rtic_monotonic as monotonic;
diff --git a/src/lib.rs b/src/lib.rs
index cd511996..ca52ec1e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -43,8 +43,6 @@ pub use rtic_monotonic::{self, embedded_time as time, Monotonic};
#[doc(hidden)]
pub mod export;
#[doc(hidden)]
-mod linked_list;
-#[doc(hidden)]
mod tq;
/// Sets the given `interrupt` as pending
diff --git a/src/linked_list.rs b/src/linked_list.rs
deleted file mode 100644
index bbb935f8..00000000
--- a/src/linked_list.rs
+++ /dev/null
@@ -1,597 +0,0 @@
-use core::fmt;
-use core::marker::PhantomData;
-use core::mem::MaybeUninit;
-use core::ops::{Deref, DerefMut};
-use core::ptr;
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-struct LinkedIndex(u16);
-
-impl LinkedIndex {
- #[inline]
- const unsafe fn new_unchecked(value: u16) -> Self {
- LinkedIndex(value)
- }
-
- #[inline]
- const fn none() -> Self {
- LinkedIndex(u16::MAX)
- }
-
- #[inline]
- const fn option(self) -> Option<u16> {
- if self.0 == u16::MAX {
- None
- } else {
- Some(self.0)
- }
- }
-}
-
-/// A node in the linked list.
-pub struct Node<T> {
- val: MaybeUninit<T>,
- next: LinkedIndex,
-}
-
-/// Iterator for the linked list.
-pub struct Iter<'a, T, Kind, const N: usize>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- list: &'a LinkedList<T, Kind, N>,
- index: LinkedIndex,
-}
-
-impl<'a, T, Kind, const N: usize> Iterator for Iter<'a, T, Kind, N>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- type Item = &'a T;
-
- fn next(&mut self) -> Option<Self::Item> {
- let index = self.index.option()?;
-
- let node = self.list.node_at(index as usize);
- self.index = node.next;
-
- Some(self.list.read_data_in_node_at(index as usize))
- }
-}
-
-/// Comes from [`LinkedList::find_mut`].
-pub struct FindMut<'a, T, Kind, const N: usize>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- list: &'a mut LinkedList<T, Kind, N>,
- is_head: bool,
- prev_index: LinkedIndex,
- index: LinkedIndex,
- maybe_changed: bool,
-}
-
-impl<'a, T, Kind, const N: usize> FindMut<'a, T, Kind, N>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- fn pop_internal(&mut self) -> T {
- if self.is_head {
- // If it is the head element, we can do a normal pop
- unsafe { self.list.pop_unchecked() }
- } else {
- // Somewhere in the list
-
- // Re-point the previous index
- self.list.node_at_mut(self.prev_index.0 as usize).next =
- self.list.node_at_mut(self.index.0 as usize).next;
-
- // Release the index into the free queue
- self.list.node_at_mut(self.index.0 as usize).next = self.list.free;
- self.list.free = self.index;
-
- self.list.extract_data_in_node_at(self.index.0 as usize)
- }
- }
-
- /// This will pop the element from the list.
- ///
- /// Complexity is O(1).
- #[inline]
- pub fn pop(mut self) -> T {
- self.pop_internal()
- }
-
- /// This will resort the element into the correct position in the list in needed.
- /// Same as calling `drop`.
- ///
- /// Complexity is worst-case O(N).
- #[inline]
- pub fn finish(self) {
- drop(self)
- }
-}
-
-impl<T, Kind, const N: usize> Drop for FindMut<'_, T, Kind, N>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- fn drop(&mut self) {
- // Only resort the list if the element has changed
- if self.maybe_changed {
- let val = self.pop_internal();
- unsafe { self.list.push_unchecked(val) };
- }
- }
-}
-
-impl<T, Kind, const N: usize> Deref for FindMut<'_, T, Kind, N>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- self.list.read_data_in_node_at(self.index.0 as usize)
- }
-}
-
-impl<T, Kind, const N: usize> DerefMut for FindMut<'_, T, Kind, N>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.maybe_changed = true;
- self.list.read_mut_data_in_node_at(self.index.0 as usize)
- }
-}
-
-impl<T, Kind, const N: usize> fmt::Debug for FindMut<'_, T, Kind, N>
-where
- T: PartialEq + PartialOrd + core::fmt::Debug,
- Kind: kind::Kind,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("FindMut")
- .field("prev_index", &self.prev_index)
- .field("index", &self.index)
- .field(
- "prev_value",
- &self
- .list
- .read_data_in_node_at(self.prev_index.option().unwrap() as usize),
- )
- .field(
- "value",
- &self
- .list
- .read_data_in_node_at(self.index.option().unwrap() as usize),
- )
- .finish()
- }
-}
-
-/// The linked list.
-pub struct LinkedList<T, Kind, const N: usize>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- list: MaybeUninit<[Node<T>; N]>,
- head: LinkedIndex,
- free: LinkedIndex,
- _kind: PhantomData<Kind>,
-}
-
-impl<T, Kind, const N: usize> LinkedList<T, Kind, N>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- /// Internal helper to not do pointer arithmetic all over the place.
- #[inline]
- fn node_at(&self, index: usize) -> &Node<T> {
- // Safety: The entire `self.list` is initialized in `new`, which makes this safe.
- unsafe { &*(self.list.as_ptr() as *const Node<T>).add(index) }
- }
-
- /// Internal helper to not do pointer arithmetic all over the place.
- #[inline]
- fn node_at_mut(&mut self, index: usize) -> &mut Node<T> {
- // Safety: The entire `self.list` is initialized in `new`, which makes this safe.
- unsafe { &mut *(self.list.as_mut_ptr() as *mut Node<T>).add(index) }
- }
-
- /// Internal helper to not do pointer arithmetic all over the place.
- #[inline]
- fn write_data_in_node_at(&mut self, index: usize, data: T) {
- unsafe {
- self.node_at_mut(index).val.as_mut_ptr().write(data);
- }
- }
-
- /// Internal helper to not do pointer arithmetic all over the place.
- #[inline]
- fn read_data_in_node_at(&self, index: usize) -> &T {
- unsafe { &*self.node_at(index).val.as_ptr() }
- }
-
- /// Internal helper to not do pointer arithmetic all over the place.
- #[inline]
- fn read_mut_data_in_node_at(&mut self, index: usize) -> &mut T {
- unsafe { &mut *self.node_at_mut(index).val.as_mut_ptr() }
- }
-
- /// Internal helper to not do pointer arithmetic all over the place.
- #[inline]
- fn extract_data_in_node_at(&mut self, index: usize) -> T {
- unsafe { self.node_at(index).val.as_ptr().read() }
- }
-
- /// Internal helper to not do pointer arithmetic all over the place.
- /// Safety: This can overwrite existing allocated nodes if used improperly, meaning their
- /// `Drop` methods won't run.
- #[inline]
- unsafe fn write_node_at(&mut self, index: usize, node: Node<T>) {
- (self.list.as_mut_ptr() as *mut Node<T>)
- .add(index)
- .write(node)
- }
-
- /// Create a new linked list.
- pub fn new() -> Self {
- let mut list = LinkedList {
- list: MaybeUninit::uninit(),
- head: LinkedIndex::none(),
- free: unsafe { LinkedIndex::new_unchecked(0) },
- _kind: PhantomData,
- };
-
- let len = N as u16;
- let mut free = 0;
-
- if len == 0 {
- list.free = LinkedIndex::none();
- return list;
- }
-
- // Initialize indexes
- while free < len - 1 {
- unsafe {
- list.write_node_at(
- free as usize,
- Node {
- val: MaybeUninit::uninit(),
- next: LinkedIndex::new_unchecked(free + 1),
- },
- );
- }
- free += 1;
- }
-
- // Initialize final index
- unsafe {
- list.write_node_at(
- free as usize,
- Node {
- val: MaybeUninit::uninit(),
- next: LinkedIndex::none(),
- },
- );
- }
-
- list
- }
-
- /// Push unchecked
- ///
- /// Complexity is O(N).
- ///
- /// # Safety
- ///
- /// Assumes that the list is not full.
- pub unsafe fn push_unchecked(&mut self, value: T) {
- let new = self.free.0;
- // Store the data and update the next free spot
- self.write_data_in_node_at(new as usize, value);
- self.free = self.node_at(new as usize).next;
-
- if let Some(head) = self.head.option() {
- // Check if we need to replace head
- if self
- .read_data_in_node_at(head as usize)
- .partial_cmp(self.read_data_in_node_at(new as usize))
- != Kind::ordering()
- {
- self.node_at_mut(new as usize).next = self.head;
- self.head = LinkedIndex::new_unchecked(new);
- } else {
- // It's not head, search the list for the correct placement
- let mut current = head;
-
- while let Some(next) = self.node_at(current as usize).next.option() {
- if self
- .read_data_in_node_at(next as usize)
- .partial_cmp(self.read_data_in_node_at(new as usize))
- != Kind::ordering()
- {
- break;
- }
-
- current = next;
- }
-
- self.node_at_mut(new as usize).next = self.node_at(current as usize).next;
- self.node_at_mut(current as usize).next = LinkedIndex::new_unchecked(new);
- }
- } else {
- self.node_at_mut(new as usize).next = self.head;
- self.head = LinkedIndex::new_unchecked(new);
- }
- }
-
- /// Pushes an element to the linked list and sorts it into place.
- ///
- /// Complexity is O(N).
- pub fn push(&mut self, value: T) -> Result<(), T> {
- if !self.is_full() {
- Ok(unsafe { self.push_unchecked(value) })
- } else {
- Err(value)
- }
- }
-
- /// Get an iterator over the sorted list.
- pub fn iter(&self) -> Iter<'_, T, Kind, N> {
- Iter {
- list: self,
- index: self.head,
- }
- }
-
- /// Find an element in the list.
- pub fn find_mut<F>(&mut self, mut f: F) -> Option<FindMut<'_, T, Kind, N>>
- where
- F: FnMut(&T) -> bool,
- {
- let head = self.head.option()?;
-
- // Special-case, first element
- if f(self.read_data_in_node_at(head as usize)) {
- return Some(FindMut {
- is_head: true,
- prev_index: LinkedIndex::none(),
- index: self.head,
- list: self,
- maybe_changed: false,
- });
- }
-
- let mut current = head;
-
- while let Some(next) = self.node_at(current as usize).next.option() {
- if f(self.read_data_in_node_at(next as usize)) {
- return Some(FindMut {
- is_head: false,
- prev_index: unsafe { LinkedIndex::new_unchecked(current) },
- index: unsafe { LinkedIndex::new_unchecked(next) },
- list: self,
- maybe_changed: false,
- });
- }
-
- current = next;
- }
-
- None
- }
-
- /// Peek at the first element.
- pub fn peek(&self) -> Option<&T> {
- self.head
- .option()
- .map(|head| self.read_data_in_node_at(head as usize))
- }
-
- /// Pop unchecked
- ///
- /// # Safety
- ///
- /// Assumes that the list is not empty.
- pub unsafe fn pop_unchecked(&mut self) -> T {
- let head = self.head.0;
- let current = head;
- self.head = self.node_at(head as usize).next;
- self.node_at_mut(current as usize).next = self.free;
- self.free = LinkedIndex::new_unchecked(current);
-
- self.extract_data_in_node_at(current as usize)
- }
-
- /// Pops the first element in the list.
- ///
- /// Complexity is O(1).
- pub fn pop(&mut self) -> Result<T, ()> {
- if !self.is_empty() {
- Ok(unsafe { self.pop_unchecked() })
- } else {
- Err(())
- }
- }
-
- /// Checks if the linked list is full.
- #[inline]
- pub fn is_full(&self) -> bool {
- self.free.option().is_none()
- }
-
- /// Checks if the linked list is empty.
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.head.option().is_none()
- }
-}
-
-impl<T, Kind, const N: usize> Drop for LinkedList<T, Kind, N>
-where
- T: PartialEq + PartialOrd,
- Kind: kind::Kind,
-{
- fn drop(&mut self) {
- let mut index = self.head;
-
- while let Some(i) = index.option() {
- let node = self.node_at_mut(i as usize);
- index = node.next;
-
- unsafe {
- ptr::drop_in_place(node.val.as_mut_ptr());
- }
- }
- }
-}
-
-impl<T, Kind, const N: usize> fmt::Debug for LinkedList<T, Kind, N>
-where
- T: PartialEq + PartialOrd + core::fmt::Debug,
- Kind: kind::Kind,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_list().entries(self.iter()).finish()
- }
-}
-
-/// Min sorted linked list.
-pub struct Min;
-
-/// Max sorted linked list.
-pub struct Max;
-
-/// Sealed traits and implementations for `linked_list`
-pub mod kind {
- use super::{Max, Min};
- use core::cmp::Ordering;
-
- /// The linked list kind: min first or max first
- pub unsafe trait Kind {
- #[doc(hidden)]
- fn ordering() -> Option<Ordering>;
- }
-
- unsafe impl Kind for Min {
- #[inline]
- fn ordering() -> Option<Ordering> {
- Some(Ordering::Less)
- }
- }
-
- unsafe impl Kind for Max {
- #[inline]
- fn ordering() -> Option<Ordering> {
- Some(Ordering::Greater)
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- // Note this useful idiom: importing names from outer (for mod tests) scope.
- use super::*;
-
- #[test]
- fn test_peek() {
- let mut ll: LinkedList<u32, Max, 3> = LinkedList::new();
-
- ll.push(1).unwrap();
- assert_eq!(ll.peek().unwrap(), &1);
-
- ll.push(2).unwrap();
- assert_eq!(ll.peek().unwrap(), &2);
-
- ll.push(3).unwrap();
- assert_eq!(ll.peek().unwrap(), &3);
-
- let mut ll: LinkedList<u32, Min, 3> = LinkedList::new();
-
- ll.push(2).unwrap();
- assert_eq!(ll.peek().unwrap(), &2);
-
- ll.push(1).unwrap();
- assert_eq!(ll.peek().unwrap(), &1);
-
- ll.push(3).unwrap();
- assert_eq!(ll.peek().unwrap(), &1);
- }
-
- #[test]
- fn test_full() {
- let mut ll: LinkedList<u32, Max, 3> = LinkedList::new();
- ll.push(1).unwrap();
- ll.push(2).unwrap();
- ll.push(3).unwrap();
-
- assert!(ll.is_full())
- }
-
- #[test]
- fn test_empty() {
- let ll: LinkedList<u32, Max, 3> = LinkedList::new();
-
- assert!(ll.is_empty())
- }
-
- #[test]
- fn test_zero_size() {
- let ll: LinkedList<u32, Max, 0> = LinkedList::new();
-
- assert!(ll.is_empty());
- assert!(ll.is_full());
- }
-
- #[test]
- fn test_rejected_push() {
- let mut ll: LinkedList<u32, Max, 3> = LinkedList::new();
- ll.push(1).unwrap();
- ll.push(2).unwrap();
- ll.push(3).unwrap();
-
- // This won't fit
- let r = ll.push(4);
-
- assert_eq!(r, Err(4));
- }
-
- #[test]
- fn test_updating() {
- let mut ll: LinkedList<u32, Max, 3> = LinkedList::new();
- ll.push(1).unwrap();
- ll.push(2).unwrap();
- ll.push(3).unwrap();
-
- let mut find = ll.find_mut(|v| *v == 2).unwrap();
-
- *find += 1000;
- find.finish();
-
- assert_eq!(ll.peek().unwrap(), &1002);
-
- let mut find = ll.find_mut(|v| *v == 3).unwrap();
-
- *find += 1000;
- find.finish();
-
- assert_eq!(ll.peek().unwrap(), &1003);
-
- // Remove largest element
- ll.find_mut(|v| *v == 1003).unwrap().pop();
-
- assert_eq!(ll.peek().unwrap(), &1002);
- }
-}
diff --git a/src/tq.rs b/src/tq.rs
index cd44abe2..dcaccc9e 100644
--- a/src/tq.rs
+++ b/src/tq.rs
@@ -1,9 +1,9 @@
use crate::{
- linked_list::{LinkedList, Min},
time::{Clock, Instant},
Monotonic,
};
use core::cmp::Ordering;
+use heapless::sorted_linked_list::{LinkedIndexU16, Min, SortedLinkedList};
#[inline(always)]
fn unwrapper<T, E>(val: Result<T, E>) -> T {
@@ -14,7 +14,9 @@ fn unwrapper<T, E>(val: Result<T, E>) -> T {
}
}
-pub struct TimerQueue<Mono, Task, const N: usize>(pub LinkedList<NotReady<Mono, Task>, Min, N>)
+pub struct TimerQueue<Mono, Task, const N: usize>(
+ pub SortedLinkedList<NotReady<Mono, Task>, LinkedIndexU16, Min, N>,
+)
where
Mono: Monotonic,
Task: Copy;
@@ -24,10 +26,6 @@ where
Mono: Monotonic,
Task: Copy,
{
- pub fn new() -> Self {
- TimerQueue(LinkedList::new())
- }
-
/// # Safety
///
/// Writing to memory with a transmute in order to enable