Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to claim resources without a token? #84

Closed
bergus opened this issue Jul 10, 2018 · 3 comments
Closed

How to claim resources without a token? #84

bergus opened this issue Jul 10, 2018 · 3 comments

Comments

@bergus
Copy link

bergus commented Jul 10, 2018

I am trying to use the clean architecture for my device - i.e. the main application logic is not dependent on the hardware, but is written with a generic output trait that can be instantiated with different types.

pub trait Output {
    fn write(Message);
}
pub struct App<O: Output> {
    out: O,}
impl<O: Output> App<O> {
    pub fn new(out: O) -> Self {
        Self { out,}
    }
    pub fn process(&mut self, msg: Message) {// heavy lifting
        self.out.write();}
}

For testing, I can instantiate the Output with a growing vector where I can inspect the results after processing various example inputs.
In the application, I can instantiate the Output with a producer that writes into a buffer, getting consumed from the serial port interrupt:

// pseudo code :-)
use my_library::App;
use buffer::{Buffer, BufferConsumer, BufferProducer};
use hal::Uart;

struct SerialApp {
    input: BufferConsumer,
    app: App<SerialBufferProducer>
}
struct SerialBufferProducer(BufferProducer);
rtfm::app! {
    resources: {
        static app: SerialApp;
        static serial_rx: BufferProducer;
        static serial_tx: BufferConsumer;
        static uart: Uart;
    },
    idle: {
        resources: [app],
    },
    tasks: {
        USART1: {
            path: rxtx,
            resources: [uart, serial_rx, serial_tx],
            enabled: true,
        }
    },
}
fn init(mut p: init::Peripherals) -> init::LateResources {
    static mut rx_buffer: Buffer = Buffer::empty();
    static mut tx_buffer: Buffer = Buffer::empty();
    let (rx_consumer, rx_producer) = unsafe { rx_buffer.split() };
    let (tx_consumer, tx_producer) = unsafe { tx_buffer.split() };
    init::LateResources {
        app: SerialApp::new(rx_consumer, SerialBufferProducer(tx_producer)),
        serial_rx: rx_producer,
        serial_tx: tx_consumer,
        uart: Uart::init(p.USART1),
    }
}
fn idle(t: &mut Threshold, mut r: idle::Resources) -> ! {
    loop {
        if let Some(msg) = r.serial_app.input.read() {
            r.serial_app.app.process(msg);
        }
    }
}
pub fn rxtx(_: &mut ::Threshold, mut r: ::USART1::Resources) {
    if let Some(byte) = r.uart.received() {
        r.serial_rx.write(byte);
    }
    if r.uart.can_send() {
        if let Some(byte) = r.serial_tx.read() {
            r.uart.send(byte);
        } else {
            r.uart.disable_tx_event();
        }
    }
}

Here's the catch: the SerialBufferProducer wrapper that implements the app Output is supposed to enable the uart tx event after writing to the buffer, and it would need to claim the uart resource for that!

Let's assume that

  • I want to use the app in other tasks as well, so I can't just instantiate it within idle and use its token and uart resource in the construction of the SerialBufferProducer.
  • there is no other way to guarantee atomical access, like splitting the uart resource or using bit banding - I really need to prevent other uart-using interrupts

I think I need a way to access a uart resource in the init function so that I can put it into the SerialBufferProducer, and then a way to claim it without being passed a token. The clean architecture prevents me from passing the token that is accessible at the call site of process through to the write call. What do you think?

@japaric
Copy link
Collaborator

japaric commented Nov 3, 2018

How to claim resources without a token?

That's how Mutex.lock works in v0.4.0; you don't need a token -- the Threshold token is gone in v0.4.0.

I think I need a way to access a uart resource in the init function

This is not possible. Resource proxies (the structs that implement the Mutex trait) are tied to the stack frame of the task that owns them; they are not Send, either, so even if you could create one in init you would not be able to move into any task.

If you need fine-grained locks, i.e. a struct that contains a resource proxy, you'll have to write a generic struct (e.g. struct Foo<R> where R: Mutex<Data = u32> { resource: R, state: State } and re-instantiate it in every task where you need it.

@bergus
Copy link
Author

bergus commented Nov 6, 2018

Thanks, I'll take a look at mutexes. It'll be hard to do initialisation different, though.

@japaric
Copy link
Collaborator

japaric commented May 8, 2019

I think the original question has been answer. If you have additional questions please open a new issue.

@japaric japaric closed this as completed May 8, 2019
andrewgazelka pushed a commit to andrewgazelka/cortex-m-rtic that referenced this issue Nov 3, 2021
84: refactor the linker script r=therealprof a=japaric

to make it more compatible with LLD. This commit contains no functional changes.

fixes rtic-rs#70

Overview of changes:

- Alignment checks are enabled now that rust-lld (LLD 7.0) supports the modulo
operator.

- Removed some private symbols (e.g. __foo) in favor of ADDR and SIZEOF.

- Turned .got into a NOLOAD section now that rust-lld supports it.

- Replaced `ABSOLUTE(.)` with `.` as an old LLD overlap bug seems to be gone and
ABSOLUTE seems to cause problems, like rtic-rs#70, on bigger programs.

- Made the linker assertion messages more uniform.

- Extended test suite to check that linking works with both rust-lld and GNU
LD.

r? therealprof (chosen at random)

Co-authored-by: Jorge Aparicio <jorge@japaric.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants