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.

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.


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

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

extern crate panic_semihosting;

use alloc_singleton::stable::pool::{Box, Pool};
use cortex_m_semihosting::{debug, hprintln};
use lm3s6965::Interrupt;
use rtfm::app;

#[app(device = lm3s6965)]
const APP: () = {
    #[Singleton(Send)]
    static mut M: [u32; 2] = [0; 2];

    static mut P: Pool<M> = ();

    #[init(resources = [M])]
    fn init() -> init::LateResources {
        rtfm::pend(Interrupt::I2C0);

        init::LateResources {
            P: Pool::new(resources.M),
        }
    }

    #[interrupt(
        priority = 2,
        resources = [P],
        spawn = [foo, bar],
    )]
    fn I2C0() {
        spawn.foo(resources.P.alloc(1).unwrap()).unwrap();
        spawn.bar(resources.P.alloc(2).unwrap()).unwrap();
    }

    #[task(resources = [P])]
    fn foo(x: Box<M>) {
        hprintln!("foo({})", x).unwrap();

        resources.P.lock(|p| p.dealloc(x));

        debug::exit(debug::EXIT_SUCCESS);
    }

    #[task(priority = 2, resources = [P])]
    fn bar(x: Box<M>) {
        hprintln!("bar({})", x).unwrap();

        resources.P.dealloc(x);
    }

    extern "C" {
        fn UART0();
        fn UART1();
    }
};
}
$ cargo run --example singleton
bar(2)
foo(1)