diff options
| author | Jorge Aparicio <jorge@japaric.io> | 2019-02-11 21:40:53 +0100 |
|---|---|---|
| committer | Jorge Aparicio <jorge@japaric.io> | 2019-02-11 21:40:53 +0100 |
| commit | 0007a35a274ab2d07eb937e41971ea5e2c1cb5ff (patch) | |
| tree | 98361d6d3dfced4b068771c31163b324573294b7 /book/en/src | |
| parent | 68a937a72a3a6d261076803d38b7d9b2cb9e3067 (diff) | |
change layout of books
Diffstat (limited to 'book/en/src')
| -rw-r--r-- | book/en/src/SUMMARY.md | 16 | ||||
| -rw-r--r-- | book/en/src/by-example.md | 16 | ||||
| -rw-r--r-- | book/en/src/by-example/app.md | 105 | ||||
| -rw-r--r-- | book/en/src/by-example/new.md | 67 | ||||
| -rw-r--r-- | book/en/src/by-example/resources.md | 119 | ||||
| -rw-r--r-- | book/en/src/by-example/singletons.md | 26 | ||||
| -rw-r--r-- | book/en/src/by-example/tasks.md | 63 | ||||
| -rw-r--r-- | book/en/src/by-example/timer-queue.md | 97 | ||||
| -rw-r--r-- | book/en/src/by-example/tips.md | 77 | ||||
| -rw-r--r-- | book/en/src/by-example/types-send-sync.md | 60 | ||||
| -rw-r--r-- | book/en/src/internals.md | 6 | ||||
| -rw-r--r-- | book/en/src/internals/ceilings.md | 3 | ||||
| -rw-r--r-- | book/en/src/internals/tasks.md | 3 | ||||
| -rw-r--r-- | book/en/src/internals/timer-queue.md | 3 | ||||
| -rw-r--r-- | book/en/src/preface.md | 16 |
15 files changed, 677 insertions, 0 deletions
diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md new file mode 100644 index 0000000..051d1ac --- /dev/null +++ b/book/en/src/SUMMARY.md @@ -0,0 +1,16 @@ +# Summary + +[Preface](./preface.md) +- [RTFM by example](./by-example.md) + - [The `app` attribute](./by-example/app.md) + - [Resources](./by-example/resources.md) + - [Tasks](./by-example/tasks.md) + - [Timer queue](./by-example/timer-queue.md) + - [Singletons](./by-example/singletons.md) + - [Types, Send and Sync](./by-example/types-send-sync.md) + - [Starting a new project](./by-example/new.md) + - [Tips & tricks](./by-example/tips.md) +- [Under the hood](./internals.md) + - [Ceiling analysis](./internals/ceilings.md) + - [Task dispatcher](./internals/tasks.md) + - [Timer queue](./internals/timer-queue.md) diff --git a/book/en/src/by-example.md b/book/en/src/by-example.md new file mode 100644 index 0000000..0e09b03 --- /dev/null +++ b/book/en/src/by-example.md @@ -0,0 +1,16 @@ +# RTFM by example + +This part of the book introduces the Real Time For the Masses (RTFM) framework +to new users by walking them through examples of increasing complexity. + +All examples in this part of the book can be found in the GitHub [repository] of +the project, and most of the examples can be run on QEMU so no special hardware +is required to follow along. + +[repository]: https://github.com/japaric/cortex-m-rtfm + +To run the examples on your laptop / PC you'll need the `qemu-system-arm` +program. Check [the embedded Rust book] for instructions on how to set up an +embedded development environment that includes QEMU. + +[the embedded Rust book]: https://rust-embedded.github.io/book/intro/install.html diff --git a/book/en/src/by-example/app.md b/book/en/src/by-example/app.md new file mode 100644 index 0000000..996b8c1 --- /dev/null +++ b/book/en/src/by-example/app.md @@ -0,0 +1,105 @@ +# The `app` attribute + +This is the smallest possible RTFM application: + +``` rust +{{#include ../../../../examples/smallest.rs}} +``` + +All RTFM applications use the [`app`] attribute (`#[app(..)]`). This attribute +must be applied to a `const` item that contains items. The `app` attribute has +a mandatory `device` argument that takes a *path* as a value. This path must +point to a *peripheral access crate* (PAC) generated using [`svd2rust`] +**v0.14.x**. The `app` attribute will expand into a suitable entry point so it's +not required to use the [`cortex_m_rt::entry`] attribute. + +[`app`]: ../../api/cortex_m_rtfm_macros/attr.app.html +[`svd2rust`]: https://crates.io/crates/svd2rust +[`cortex_m_rt::entry`]: ../../api/cortex_m_rt_macros/attr.entry.html + +> **ASIDE**: Some of you may be wondering why we are using a `const` item as a +> module and not a proper `mod` item. The reason is that using attributes on +> modules requires a feature gate, which requires a nightly toolchain. To make +> RTFM work on stable we use the `const` item instead. When more parts of macros +> 1.2 are stabilized we'll move from a `const` item to a `mod` item and +> eventually to a crate level attribute (`#![app]`). + +## `init` + +Within the pseudo-module the `app` attribute expects to find an initialization +function marked with the `init` attribute. This function must have signature +`[unsafe] fn()`. + +This initialization function will be the first part of the application to run. +The `init` function will run *with interrupts disabled* and has exclusive access +to Cortex-M and device specific peripherals through the `core` and `device` +variables, which are injected in the scope of `init` by the `app` attribute. Not +all Cortex-M peripherals are available in `core` because the RTFM runtime takes +ownership of some of them -- for more details see the [`rtfm::Peripherals`] +struct. + +`static mut` variables declared at the beginning of `init` will be transformed +into `&'static mut` references that are safe to access. + +[`rtfm::Peripherals`]: ../../api/rtfm/struct.Peripherals.html + +The example below shows the types of the `core` and `device` variables and +showcases safe access to a `static mut` variable. + +``` rust +{{#include ../../../../examples/init.rs}} +``` + +Running the example will print `init` to the console and then exit the QEMU +process. + +``` console +$ cargo run --example init +{{#include ../../../../ci/expected/init.run}}``` + +## `idle` + +A function marked with the `idle` attribute can optionally appear in the +pseudo-module. This function is used as the special *idle task* and must have +signature `[unsafe] fn() - > !`. + +When present, the runtime will execute the `idle` task after `init`. Unlike +`init`, `idle` will run *with interrupts enabled* and it's not allowed to return +so it runs forever. + +When no `idle` function is declared, the runtime sets the [SLEEPONEXIT] bit and +then sends the microcontroller to sleep after running `init`. + +[SLEEPONEXIT]: https://developer.arm.com/products/architecture/cpu-architecture/m-profile/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit + +Like in `init`, `static mut` variables will be transformed into `&'static mut` +references that are safe to access. + +The example below shows that `idle` runs after `init`. + +``` rust +{{#include ../../../../examples/idle.rs}} +``` + +``` console +$ cargo run --example idle +{{#include ../../../../ci/expected/idle.run}}``` + +## `interrupt` / `exception` + +Just like you would do with the `cortex-m-rt` crate you can use the `interrupt` +and `exception` attributes within the `app` pseudo-module to declare interrupt +and exception handlers. In RTFM, we refer to interrupt and exception handlers as +*hardware* tasks. + +``` rust +{{#include ../../../../examples/interrupt.rs}} +``` + +``` console +$ cargo run --example interrupt +{{#include ../../../../ci/expected/interrupt.run}}``` + +So far all the RTFM applications we have seen look no different that the +applications one can write using only the `cortex-m-rt` crate. In the next +section we start introducing features unique to RTFM. diff --git a/book/en/src/by-example/new.md b/book/en/src/by-example/new.md new file mode 100644 index 0000000..ae49ef2 --- /dev/null +++ b/book/en/src/by-example/new.md @@ -0,0 +1,67 @@ +# Starting a new project + +Now that you have learned about the main features of the RTFM framework you can +try it out on your hardware by following these instructions. + +1. Instantiate the [`cortex-m-quickstart`] template. + +[`cortex-m-quickstart`]: https://github.com/rust-embedded/cortex-m-quickstart#cortex-m-quickstart + +``` console +$ # for example using `cargo-generate` +$ cargo generate \ + --git https://github.com/rust-embedded/cortex-m-quickstart \ + --name app + +$ # follow the rest of the instructions +``` + +2. Add a peripheral access crate (PAC) that was generated using [`svd2rust`] + **v0.14.x**, or a board support crate that depends on one such PAC as a + dependency. Make sure that the `rt` feature of the crate is enabled. + +[`svd2rust`]: https://crates.io/crates/svd2rust + +In this example, I'll use the [`lm3s6965`] device crate. This device crate +doesn't have an `rt` Cargo feature; that feature is always enabled. + +[`lm3s6965`]: https://crates.io/crates/lm3s6965 + +This device crate provides a linker script with the memory layout of the target +device so `memory.x` and `build.rs` need to be removed. + +``` console +$ cargo add lm3s6965 --vers 0.1.3 + +$ rm memory.x build.rs +``` + +3. Add the `cortex-m-rtfm` crate as a dependency and, if you need it, enable the + `timer-queue` feature. + +``` console +$ cargo add cortex-m-rtfm +``` + +4. Write your RTFM application. + +Here I'll use the `init` example from the `cortex-m-rtfm` crate. + +``` console +$ curl \ + -L https://github.com/japaric/cortex-m-rtfm/raw/v0.4.0/examples/init.rs \ + > src/main.rs +``` + +That example depends on the `panic-semihosting` crate: + +``` console +$ cargo add panic-semihosting +``` + +5. Build it, flash it and run it. + +``` console +$ # NOTE: I have uncommented the `runner` option in `.cargo/config` +$ cargo run +{{#include ../../../../ci/expected/init.run}}``` diff --git a/book/en/src/by-example/resources.md b/book/en/src/by-example/resources.md new file mode 100644 index 0000000..efdeaa2 --- /dev/null +++ b/book/en/src/by-example/resources.md @@ -0,0 +1,119 @@ +## Resources + +One of the limitations of the attributes provided by the `cortex-m-rt` crate is +that sharing data (or peripherals) between interrupts, or between an interrupt +and the `entry` function, requires a `cortex_m::interrupt::Mutex`, which +*always* requires disabling *all* interrupts to access the data. Disabling all +the interrupts is not always required for memory safety but the compiler doesn't +have enough information to optimize the access to the shared data. + +The `app` attribute has a full view of the application thus it can optimize +access to `static` variables. In RTFM we refer to the `static` variables +declared inside the `app` pseudo-module as *resources*. To access a resource the +context (`init`, `idle`, `interrupt` or `exception`) must first declare the +resource in the `resources` argument of its attribute. + +In the example below two interrupt handlers access the same resource. No `Mutex` +is required in this case because the two handlers run at the same priority and +no preemption is possible. The `SHARED` resource can only be accessed by these +two handlers. + +``` rust +{{#include ../../../../examples/resource.rs}} +``` + +``` console +$ cargo run --example resource +{{#include ../../../../ci/expected/resource.run}}``` + +## Priorities + +The priority of each handler can be declared in the `interrupt` and `exception` +attributes. It's not possible to set the priority in any other way because the +runtime takes ownership of the `NVIC` peripheral; it's also not possible to +change the priority of a handler / task at runtime. Thanks to this restriction +the framework has knowledge about the *static* priorities of all interrupt and +exception handlers. + +Interrupts and exceptions can have priorities in the range `1..=(1 << +NVIC_PRIO_BITS)` where `NVIC_PRIO_BITS` is a constant defined in the `device` +crate. The `idle` task has a priority of `0`, the lowest priority. + +Resources that are shared between handlers that run at different priorities +require critical sections for memory safety. The framework ensures that critical +sections are used but *only where required*: for example, no critical section is +required by the highest priority handler that has access to the resource. + +The critical section API provided by the RTFM framework (see [`Mutex`]) is +based on dynamic priorities rather than on disabling interrupts. The consequence +is that these critical sections will prevent *some* handlers, including all the +ones that contend for the resource, from *starting* but will let higher priority +handlers, that don't contend for the resource, run. + +[`Mutex`]: ../../api/rtfm/trait.Mutex.html + +In the example below we have three interrupt handlers with priorities ranging +from one to three. The two handlers with the lower priorities contend for the +`SHARED` resource. The lowest priority handler needs to [`lock`] the +`SHARED` resource to access its data, whereas the mid priority handler can +directly access its data. The highest priority handler is free to preempt +the critical section created by the lowest priority handler. + +[`lock`]: ../../api/rtfm/trait.Mutex.html#method.lock + +``` rust +{{#include ../../../../examples/lock.rs}} +``` + +``` console +$ cargo run --example lock +{{#include ../../../../ci/expected/lock.run}}``` + +## Late resources + +Unlike normal `static` variables, which need to be assigned an initial value +when declared, resources can be initialized at runtime. We refer to these +runtime initialized resources as *late resources*. Late resources are useful for +*moving* (as in transferring ownership) peripherals initialized in `init` into +interrupt and exception handlers. + +Late resources are declared like normal resources but that are given an initial +value of `()` (the unit value). Late resources must be initialized at the end of +the `init` function using plain assignments (e.g. `FOO = 1`). + +The example below uses late resources to stablish a lockless, one-way channel +between the `UART0` interrupt handler and the `idle` function. A single producer +single consumer [`Queue`] is used as the channel. The queue is split into +consumer and producer end points in `init` and then each end point is stored +in a different resource; `UART0` owns the producer resource and `idle` owns +the consumer resource. + +[`Queue`]: ../../api/heapless/spsc/struct.Queue.html + +``` rust +{{#include ../../../../examples/late.rs}} +``` + +``` console +$ cargo run --example late +{{#include ../../../../ci/expected/late.run}}``` + +## `static` resources + +`static` variables can also be used as resources. Tasks can only get `&` +(shared) references to these resources but locks are never required to access +their data. You can think of `static` resources as plain `static` variables that +can be initialized at runtime and have better scoping rules: you can control +which tasks can access the variable, instead of the variable being visible to +all the functions in the scope it was declared in. + +In the example below a key is loaded (or created) at runtime and then used from +two tasks that run at different priorities. + +``` rust +{{#include ../../../../examples/static.rs}} +``` + +``` console +$ cargo run --example static +{{#include ../../../../ci/expected/static.run}}``` diff --git a/book/en/src/by-example/singletons.md b/book/en/src/by-example/singletons.md new file mode 100644 index 0000000..0823f05 --- /dev/null +++ b/book/en/src/by-example/singletons.md @@ -0,0 +1,26 @@ +# Singletons + +The `app` attribute is aware of [`owned-singleton`] crate and its [`Singleton`] +attribute. When this attribute is applied to one of the resources the runtime +will perform the `unsafe` initialization of the singleton for you, ensuring that +only a single instance of the singleton is ever created. + +[`owned-singleton`]: ../../api/owned_singleton/index.html +[`Singleton`]: ../../api/owned_singleton_macros/attr.Singleton.html + +Note that when using the `Singleton` attribute you'll need to have the +`owned_singleton` in your dependencies. + +Below is an example that uses the `Singleton` attribute on a chunk of memory +and then uses the singleton instance as a fixed-size memory pool using one of +the [`alloc-singleton`] abstractions. + +[`alloc-singleton`]: https://crates.io/crates/alloc-singleton + +``` rust +{{#include ../../../../examples/singleton.rs}} +``` + +``` console +$ cargo run --example singleton +{{#include ../../../../ci/expected/singleton.run}}``` diff --git a/book/en/src/by-example/tasks.md b/book/en/src/by-example/tasks.md new file mode 100644 index 0000000..edcdbed --- /dev/null +++ b/book/en/src/by-example/tasks.md @@ -0,0 +1,63 @@ +# Software tasks + +RTFM treats interrupt and exception handlers as *hardware* tasks. Hardware tasks +are invoked by the hardware in response to events, like pressing a button. RTFM +also supports *software* tasks which can be spawned by the software from any +execution context. + +Software tasks can also be assigned priorities and are dispatched from interrupt +handlers. RTFM requires that free interrupts are declared in an `extern` block +when using software tasks; these free interrupts will be used to dispatch the +software tasks. An advantage of software tasks over hardware tasks is that many +tasks can be mapped to a single interrupt handler. + +Software tasks are declared by applying the `task` attribute to functions. To be +able to spawn a software task the name of the task must appear in the `spawn` +argument of the context attribute (`init`, `idle`, `interrupt`, etc.). + +The example below showcases three software tasks that run at 2 different +priorities. The three tasks map to 2 interrupts handlers. + +``` rust +{{#include ../../../../examples/task.rs}} +``` + +``` console +$ cargo run --example task +{{#include ../../../../ci/expected/task.run}}``` + +## Message passing + +The other advantage of software tasks is that messages can be passed to these +tasks when spawning them. The type of the message payload must be specified in +the signature of the task handler. + +The example below showcases three tasks, two of them expect a message. + +``` rust +{{#include ../../../../examples/message.rs}} +``` + +``` console +$ cargo run --example message +{{#include ../../../../ci/expected/message.run}}``` + +## Capacity + +Task dispatchers do *not* use any dynamic memory allocation. The memory required +to store messages is statically reserved. The framework will reserve enough +space for every context to be able to spawn each task at most once. This is a +sensible default but the "inbox" capacity of each task can be controlled using +the `capacity` argument of the `task` attribute. + +The example below sets the capacity of the software task `foo` to 4. If the +capacity is not specified then the second `spawn.foo` call in `UART0` would +fail. + +``` rust +{{#include ../../../../examples/capacity.rs}} +``` + +``` console +$ cargo run --example capacity +{{#include ../../../../ci/expected/capacity.run}}``` diff --git a/book/en/src/by-example/timer-queue.md b/book/en/src/by-example/timer-queue.md new file mode 100644 index 0000000..167939c --- /dev/null +++ b/book/en/src/by-example/timer-queue.md @@ -0,0 +1,97 @@ +# Timer queue + +When the `timer-queue` feature is enabled the RTFM framework includes a *global +timer queue* that applications can use to *schedule* software tasks to run at +some time in the future. + +> **NOTE**: The timer-queue feature can't be enabled when the target is +> `thumbv6m-none-eabi` because there's no timer queue support for ARMv6-M. This +> may change in the future. + +> **NOTE**: When the `timer-queue` feature is enabled you will *not* be able to +> use the `SysTick` exception as a hardware task because the runtime uses it to +> implement the global timer queue. + +To be able to schedule a software task the name of the task must appear in the +`schedule` argument of the context attribute. When scheduling a task the +[`Instant`] at which the task should be executed must be passed as the first +argument of the `schedule` invocation. + +[`Instant`]: ../../api/rtfm/struct.Instant.html + +The RTFM runtime includes a monotonic, non-decreasing, 32-bit timer which can be +queried using the `Instant::now` constructor. A [`Duration`] can be added to +`Instant::now()` to obtain an `Instant` into the future. The monotonic timer is +disabled while `init` runs so `Instant::now()` always returns the value +`Instant(0 /* clock cycles */)`; the timer is enabled right before the +interrupts are re-enabled and `idle` is executed. + +[`Duration`]: ../../api/rtfm/struct.Duration.html + +The example below schedules two tasks from `init`: `foo` and `bar`. `foo` is +scheduled to run 8 million clock cycles in the future. Next, `bar` is scheduled +to run 4 million clock cycles in the future. `bar` runs before `foo` since it +was scheduled to run first. + +> **IMPORTANT**: The examples that use the `schedule` API or the `Instant` +> abstraction will **not** properly work on QEMU because the Cortex-M cycle +> counter functionality has not been implemented in `qemu-system-arm`. + +``` rust +{{#include ../../../../examples/schedule.rs}} +``` + +Running the program on real hardware produces the following output in the console: + +``` text +{{#include ../../../../ci/expected/schedule.run}} +``` + +## Periodic tasks + +Software tasks have access to the `Instant` at which they were scheduled to run +through the `scheduled` variable. This information and the `schedule` API can be +used to implement periodic tasks as shown in the example below. + +``` rust +{{#include ../../../../examples/periodic.rs}} +``` + +This is the output produced by the example. Note that there is zero drift / +jitter even though `schedule.foo` was invoked at the *end* of `foo`. Using +`Instant::now` instead of `scheduled` would have resulted in drift / jitter. + +``` text +{{#include ../../../../ci/expected/periodic.run}} +``` + +## Baseline + +For the tasks scheduled from `init` we have exact information about their +`scheduled` time. For hardware tasks there's no `scheduled` time because these +tasks are asynchronous in nature. For hardware tasks the runtime provides a +`start` time, which indicates the time at which the task handler started +executing. + +Note that `start` is **not** equal to the arrival time of the event that fired +the task. Depending on the priority of the task and the load of the system the +`start` time could be very far off from the event arrival time. + +What do you think will be the value of `scheduled` for software tasks that are +*spawned* instead of scheduled? The answer is that spawned tasks inherit the +*baseline* time of the context that spawned it. The baseline of hardware tasks +is `start`, the baseline of software tasks is `scheduled` and the baseline of +`init` is `start = Instant(0)`. `idle` doesn't really have a baseline but tasks +spawned from it will use `Instant::now()` as their baseline time. + +The example below showcases the different meanings of the *baseline*. + +``` rust +{{#include ../../../../examples/baseline.rs}} +``` + +Running the program on real hardware produces the following output in the console: + +``` text +{{#include ../../../../ci/expected/baseline.run}} +``` diff --git a/book/en/src/by-example/tips.md b/book/en/src/by-example/tips.md new file mode 100644 index 0000000..8f71599 --- /dev/null +++ b/book/en/src/by-example/tips.md @@ -0,0 +1,77 @@ +# Tips & tricks + +## Generics + +Resources shared between two or more tasks implement the `Mutex` trait in *all* +contexts, even on those where a critical section is not required to access the +data. This lets you easily write generic code that operates on resources and can +be called from different tasks. Here's one such example: + +``` rust +{{#include ../../../../examples/generics.rs}} +``` + +``` console +$ cargo run --example generics +{{#include ../../../../ci/expected/generics.run}}``` + +This also lets you change the static priorities of tasks without having to +rewrite code. If you consistently use `lock`s to access the data behind shared +resources then your code will continue to compile when you change the priority +of tasks. + +## Conditional compilation + +You can use conditional compilation (`#[cfg]`) on resources (`static [mut]` +items) and tasks (`fn` items). The effect of using `#[cfg]` attributes is that +the resource / task will *not* be injected into the prelude of tasks that use +them (see `resources`, `spawn` and `schedule`) if the condition doesn't hold. + +The example below logs a message whenever the `foo` task is spawned, but only if +the program has been compiled using the `dev` profile. + +``` rust +{{#include ../../../../examples/cfg.rs}} +``` + +## Running tasks from RAM + +The main goal of moving the specification of RTFM applications to attributes in +RTFM v0.4.x was to allow inter-operation with other attributes. For example, the +`link_section` attribute can be applied to tasks to place them in RAM; this can +improve performance in some cases. + +> **IMPORTANT**: In general, the `link_section`, `export_name` and `no_mangle` +> attributes are very powerful but also easy to misuse. Incorrectly using any of +> these attributes can cause undefined behavior; you should always prefer to use +> safe, higher level attributes around them like `cortex-m-rt`'s `interrupt` and +> `exception` attributes. +> +> In the particular case of RAM functions there's no +> safe abstraction for it in `cortex-m-rt` v0.6.5 but there's an [RFC] for +> adding a `ramfunc` attribute in a future release. + +[RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100 + +The example below shows how to place the higher priority task, `bar`, in RAM. + +``` rust +{{#include ../../../../examples/ramfunc.rs}} +``` + +Running this program produces the expected output. + +``` console +$ cargo run --example ramfunc +{{#include ../../../../ci/expected/ramfunc.run}}``` + +One can look at the output of `cargo-nm` to confirm that `bar` ended in RAM +(`0x2000_0000`), whereas `foo` ended in Flash (`0x0000_0000`). + +``` console +$ cargo nm --example ramfunc --release | grep ' foo::' +{{#include ../../../../ci/expected/ramfunc.grep.foo}}``` + +``` console +$ cargo nm --example ramfunc --release | grep ' bar::' +{{#include ../../../../ci/expected/ramfunc.grep.bar}}``` diff --git a/book/en/src/by-example/types-send-sync.md b/book/en/src/by-example/types-send-sync.md new file mode 100644 index 0000000..da53cf9 --- /dev/null +++ b/book/en/src/by-example/types-send-sync.md @@ -0,0 +1,60 @@ +# Types, Send and Sync + +The `app` attribute injects a context, a collection of variables, into every +function. All these variables have predictable, non-anonymous types so you can +write plain functions that take them as arguments. + +The API reference specifies how these types are generated from the input. You +can also generate documentation for you binary crate (`cargo doc --bin <name>`); +in the documentation you'll find `Context` structs (e.g. `init::Context` and +`idle::Context`) whose fields represent the variables injected into each +function. + +The example below shows the different types generates by the `app` attribute. + +``` rust +{{#include ../../../../examples/types.rs}} +``` + +## `Send` + +[`Send`] is a marker trait for "types that can be transferred across thread +boundaries", according to its definition in `core`. In the context of RTFM the +`Send` trait is only required where it's possible to transfer a value between +tasks that run at *different* priorities. This occurs in a few places: in message +passing, in shared `static mut` resources and in the initialization of late +resources. + +[`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html + +The `app` attribute will enforce that `Send` is implemented where required so +you don't need to worry much about it. It's more important to know where you do +*not* need the `Send` trait: on types that are transferred between tasks that +run at the *same* priority. This occurs in two places: in message passing and in +shared `static mut` resources. + +The example below shows where a type that doesn't implement `Send` can be used. + +``` rust +{{#include ../../../../examples/not-send.rs}} +``` + +## `Sync` + +Similarly, [`Sync`] is a marker trait for "types for which it is safe to share +references between threads", according to its definition in `core`. In the +context of RTFM the `Sync` trait is only required where it's possible for two, +or more, tasks that run at different priority to hold a shared reference to a +resource. This only occurs with shared `static` resources. + +[`Sync`]: https://doc.rust-lang.org/core/marker/trait.Sync.html + +The `app` attribute will enforce that `Sync` is implemented where required but +it's important to know where the `Sync` bound is not required: in `static` +resources shared between tasks that run at the *same* priority. + +The example below shows where a type that doesn't implement `Sync` can be used. + +``` rust +{{#include ../../../../examples/not-sync.rs}} +``` diff --git a/book/en/src/internals.md b/book/en/src/internals.md new file mode 100644 index 0000000..0ef55e6 --- /dev/null +++ b/book/en/src/internals.md @@ -0,0 +1,6 @@ +# Under the hood + +This section describes the internals of the RTFM framework at a *high level*. +Low level details like the parsing and code generation done by the procedural +macro (`#[app]`) will not be explained here. The focus will be the analysis of +the user specification and the data structures used by the runtime. diff --git a/book/en/src/internals/ceilings.md b/book/en/src/internals/ceilings.md new file mode 100644 index 0000000..2c645a4 --- /dev/null +++ b/book/en/src/internals/ceilings.md @@ -0,0 +1,3 @@ +# Ceiling analysis + +**TODO** diff --git a/book/en/src/internals/tasks.md b/book/en/src/internals/tasks.md new file mode 100644 index 0000000..85f783f --- /dev/null +++ b/book/en/src/internals/tasks.md @@ -0,0 +1,3 @@ +# Task dispatcher + +**TODO** diff --git a/book/en/src/internals/timer-queue.md b/book/en/src/internals/timer-queue.md new file mode 100644 index 0000000..7059285 --- /dev/null +++ b/book/en/src/internals/timer-queue.md @@ -0,0 +1,3 @@ +# Timer queue + +**TODO** diff --git a/book/en/src/preface.md b/book/en/src/preface.md new file mode 100644 index 0000000..d8f64fd --- /dev/null +++ b/book/en/src/preface.md @@ -0,0 +1,16 @@ +<h1 align="center">Real Time For the Masses</h1> + +<p align="center">A concurrency framework for building real time systems</p> + +# Preface + +This book contains user level documentation for the Real Time For the Masses +(RTFM) framework. The API reference can be found [here](../api/rtfm/index.html). + +There is a translation of this book in [Russian]. + +[Russian]: ../ru/index.html + +{{#include ../../../README.md:5:46}} + +{{#include ../../../README.md:52:}} |
