## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Using indirection for faster message passing

Message passing always involves copying the payload from the sender into a static variable and then from the static variable into the receiver. Thus sending a large buffer, like a `[u8; 128]`, as a message involves two expensive `memcpy`s.

Indirection can minimize message passing overhead: instead of sending the buffer by value, one can send an owning pointer into the buffer.

One can use a global memory allocator to achieve indirection (`alloc::Box`, `alloc::Rc`, etc.), which requires using the nightly channel as of Rust v1.37.0, or one can use a statically allocated memory pool like `heapless::Pool`.

As this example of approach goes completely outside of RTIC resource model with shared and local the program would rely on the correctness of the memory allocator, in this case `heapless::pool`.

Here's an example where `heapless::Pool` is used to "box" buffers of 128 bytes.

    #![allow(unused)]
    fn main() {
    //! examples/pool.rs

    #![deny(unsafe_code)]
    #![deny(warnings)]
    // pool!() generates a struct without docs
    //#![deny(missing_docs)]
    #![no_main]
    #![no_std]

    use heapless::{
        pool,
        pool::singleton::{Box, Pool},
    };
    use panic_semihosting as _;
    use rtic::app;

    // Declare a pool of 128-byte memory blocks
    pool!(P: [u8; 128]);

    #[app(device = lm3s6965, dispatchers = [SSI0, QEI0])]
    mod app {
        use crate::{Box, Pool};
        use cortex_m_semihosting::debug;
        use lm3s6965::Interrupt;

        // Import the memory pool into scope
        use super::P;

        #[shared]
        struct Shared {}

        #[local]
        struct Local {}

        #[init(local = [memory: [u8; 512] = [0; 512]])]
        fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
            // Increase the capacity of the memory pool by ~4
            P::grow(cx.local.memory);

            rtic::pend(Interrupt::I2C0);

            (Shared {}, Local {}, init::Monotonics())
        }

        #[task(binds = I2C0, priority = 2)]
        fn i2c0(_: i2c0::Context) {
            // claim a memory block, initialize it and ..
            let x = P::alloc().unwrap().init([0u8; 128]);

            // .. send it to the `foo` task
            foo::spawn(x).ok().unwrap();

            // send another block to the task `bar`
            bar::spawn(P::alloc().unwrap().init([0u8; 128]))
                .ok()
                .unwrap();
        }

        #[task]
        fn foo(_: foo::Context, _x: Box<P>) {
            // explicitly return the block to the pool
            drop(_x);

            debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
        }

        #[task(priority = 2)]
        fn bar(_: bar::Context, _x: Box<P>) {
            // this is done automatically so we can omit the call to `drop`
            // drop(x);
        }
    }
    }

    $ cargo run --target thumbv7m-none-eabi --example pool