aboutsummaryrefslogtreecommitdiff
path: root/book/en/src/internals/non-reentrancy.md
diff options
context:
space:
mode:
Diffstat (limited to 'book/en/src/internals/non-reentrancy.md')
-rw-r--r--book/en/src/internals/non-reentrancy.md84
1 files changed, 84 insertions, 0 deletions
diff --git a/book/en/src/internals/non-reentrancy.md b/book/en/src/internals/non-reentrancy.md
new file mode 100644
index 00000000..408a012e
--- /dev/null
+++ b/book/en/src/internals/non-reentrancy.md
@@ -0,0 +1,84 @@
+# Non-reentrancy
+
+In RTFM, tasks handlers are *not* reentrant. Reentering a task handler can break
+Rust aliasing rules and lead to *undefined behavior*. A task handler can be
+reentered in one of two ways: in software or by hardware.
+
+## In software
+
+To reenter a task handler in software its underlying interrupt handler must be
+invoked using FFI (see example below). FFI requires `unsafe` code so end users
+are discouraged from directly invoking an interrupt handler.
+
+``` rust
+#[rtfm::app(device = ..)]
+const APP: () = {
+ static mut X: u64 = 0;
+
+ #[init]
+ fn init(c: init::Context) { .. }
+
+ #[interrupt(binds = UART0, resources = [X])]
+ fn foo(c: foo::Context) {
+ let x: &mut u64 = c.resources.X;
+
+ *x = 1;
+
+ //~ `bar` can preempt `foo` at this point
+
+ *x = 2;
+
+ if *x == 2 {
+ // something
+ }
+ }
+
+ #[interrupt(binds = UART1, priority = 2)]
+ fn bar(c: foo::Context) {
+ extern "C" {
+ fn UART0();
+ }
+
+ // this interrupt handler will invoke task handler `foo` resulting
+ // in mutable aliasing of the static variable `X`
+ unsafe { UART0() }
+ }
+};
+```
+
+The RTFM framework must generate the interrupt handler code that calls the user
+defined task handlers. We are careful in making these handlers `unsafe` and / or
+impossible to call from user code.
+
+The above example expands into:
+
+``` rust
+fn foo(c: foo::Context) {
+ // .. user code ..
+}
+
+fn bar(c: bar::Context) {
+ // .. user code ..
+}
+
+const APP: () = {
+ // everything in this block is not visible to user code
+
+ #[no_mangle]
+ unsafe fn USART0() {
+ foo(..);
+ }
+
+ #[no_mangle]
+ unsafe fn USART1() {
+ bar(..);
+ }
+};
+```
+
+## By hardware
+
+A task handler can also be reentered without software intervention. This can
+occur if the same handler is assigned to two or more interrupts in the vector
+table but there's no syntax for this kind of configuration in the RTFM
+framework.