Live data from Hacker News

Using the Rust standard library with the NuttX RTOS

lupyuen.org

21–28 of 28 posts

Re: Using the Rust standard library with the NuttX RTOS

#21
post #17

Some years into Rust firmware with no classic RTOS experience: I get the feeling that embedded async Rust is a little like an RTOS library toolkit. Why do you need an OS abstraction when you can handcraft an embedded async runtime? Component reuse?

The boundaries are fuzzy, but I look at an RTOS as something you reach for when dealing with non-cooperative processes existing on the same device. I recognize that in C embedded code bases, RTOS is often used by default, regardless of this. Soemtimes it's to get a collection of higher level features, like an allocator, file system etc.

> non-cooperative processes existing on the same device

That sounds like a real-world problem you could avoid by design. Is that because of 3rd-party vendoring?

> Soemtimes it's to get a collection of higher level features, like an allocator, file system etc.

I can relate to those needs, but I’m still unsure why not expose those in your runtime?

Is embassy-rs with enough interaction between tasks an RTOS? Do you need an external API to be an OS? Do you need specific scheduling rules, or is it enough to know that certain tasks will never be blocked arbitrary long time?

Re: Using the Rust standard library with the NuttX RTOS

#22
post #21

Earlier quoted context omitted.

The boundaries are fuzzy, but I look at an RTOS as something you reach for when dealing with non-cooperative processes existing on the same device. I recognize that in C embedded code bases, RTOS is often used by default, regardless of this. Soemtimes it's to get a collection of higher level features, like an allocator, file system etc.

> non-cooperative processes existing on the same device That sounds like a real-world problem you could avoid by design. Is that because of 3rd-party vendoring? > Soemtimes it's to get a collection of higher level features, like an allocator, file system etc. I can relate to those needs, but I’m still unsure why not expose those in your runtime? Is embassy-rs with enough interaction between tasks an RTOS? Do you need…

It's fuzzy. Re non-cooperative: Example: your browser and text editor both running at the same time on your PC etc.

Re embassy: Not an RTOS in the way Nuttx, Free RTOS are etc, but if someone wants to apply the label, sure.

The way most people use "RTOS", RTIC and Embassy are not it.

Re: Using the Rust standard library with the NuttX RTOS

#23
post #17

Some years into Rust firmware with no classic RTOS experience: I get the feeling that embedded async Rust is a little like an RTOS library toolkit. Why do you need an OS abstraction when you can handcraft an embedded async runtime? Component reuse?

The classic role of an RTOS (realtime operating system) is to run applications that are, well, realtime. Like the anti-lock brake controller in your car, or the fly-by-wire system in the F-117A that compensates for its natural aerodynamic instability, or the motor controller for a 2-ton industrial robot that's whizzing around at many meters per second, or a pacemaker that's adjusting your heart rhythm, or the controller for some piece of a bazillion-dollar ASML EUV lithography system. These are applications where a failure to finish your computations on time has Majorly Bad Consequences.

In these kinds of applications, you need hard realtime guarantees, which usually means things like:

- everything is preemptive

- lock order is very explicitly defined

- memory is statically allocated

- every computation (including interrupts) has a bounded (and guaranteed, and often formally proven) processing time

Embedded async Rust (AFAIK) isn't suitable for building applications like these.

Having said that, the meaning of "RTOS" has shifted over time to something like what you're implying: a collection of primitives that's slimmer than a "real" operating system that allows running an application on embedded hardware. And in that sense, embedded async Rust is a viable option.

[1] https://en.wikipedia.org/wiki/Lockheed_F-117_Nighthawk#:~:te...

Re: Using the Rust standard library with the NuttX RTOS

#24
post #23
post #17

Some years into Rust firmware with no classic RTOS experience: I get the feeling that embedded async Rust is a little like an RTOS library toolkit. Why do you need an OS abstraction when you can handcraft an embedded async runtime? Component reuse?

The classic role of an RTOS (realtime operating system) is to run applications that are, well, realtime. Like the anti-lock brake controller in your car, or the fly-by-wire system in the F-117A that compensates for its natural aerodynamic instability, or the motor controller for a 2-ton industrial robot that's whizzing around at many meters per second, or a pacemaker that's adjusting your heart rhythm, or the control…

Thank you for the elaborate explanation.

I understand the definition of real-time.

I just don't understand why you need an operating system, compared to building a real-time firmware application with a runtime that contains a scheduler, an allocator, and what else you might want from an OS.

> Embedded async Rust (AFAIK) isn't suitable for building applications like these.

Could you elaborate why?

> in that sense, embedded async Rust is a viable option

Gotcha! So whether it's an OS or a runtime is more of an origin story.

Like whether a DSL originates as a config file or as a library.

Re: Using the Rust standard library with the NuttX RTOS

#25
post #24
post #23

Earlier quoted context omitted.

The classic role of an RTOS (realtime operating system) is to run applications that are, well, realtime. Like the anti-lock brake controller in your car, or the fly-by-wire system in the F-117A that compensates for its natural aerodynamic instability, or the motor controller for a 2-ton industrial robot that's whizzing around at many meters per second, or a pacemaker that's adjusting your heart rhythm, or the control…

Thank you for the elaborate explanation. I understand the definition of real-time. I just don't understand why you need an operating system, compared to building a real-time firmware application with a runtime that contains a scheduler, an allocator, and what else you might want from an OS. > Embedded async Rust (AFAIK) isn't suitable for building applications like these. Could you elaborate why? > in that sense, emb…

Async Rust (by default) can allocate memory, which is (almost always) nondeterministic. I'm not sure how hard it is to guarantee that nothing is using it so that all allocations happen deterministically.

Async Rust schedules (mostly) cooperatively, which means one errant task, or too many tasks, can block higher-priority, time-critical work from occurring. Embassy has an interrupt executor, which helps somewhat, but it essentially ties each task to a dedicated interrupt, and AFAICT requires that all high-priority work must happen in interrupt context. Usually you want to stay in an ISR for the absolute shortest possible time, and not be forced to choose between either running in an ISR or missing a deadline.

I'm not saying it's impossible to build a hard realtime system in async Rust if you're really careful, just that it doesn't provide the usual set of primitives that allow you to easily reason about worst-case execution time, which is a primary concern for such systems.

For me—as someone who has written embedded code professionally, but I'm just some guy, so take this with a grain of salt—the line between RTOS and runtime is whether it has a preemptive scheduler and affordances (usually prioritized tasks with support for handling priority inversion) that allow you to easily prioritize different tasks and ensure bounded worst-case runtime. It almost always also comes with synchronization primitives, like mutexes, mailboxes, queues, etc. All facilities provided by the RTOS need to either guarantee (and document) that they run in bounded time, or be easy to identify and avoid if you need bounded worst-case time.

Re: Using the Rust standard library with the NuttX RTOS

#26
post #25
post #24

Earlier quoted context omitted.

Thank you for the elaborate explanation. I understand the definition of real-time. I just don't understand why you need an operating system, compared to building a real-time firmware application with a runtime that contains a scheduler, an allocator, and what else you might want from an OS. > Embedded async Rust (AFAIK) isn't suitable for building applications like these. Could you elaborate why? > in that sense, emb…

Async Rust (by default) can allocate memory, which is (almost always) nondeterministic. I'm not sure how hard it is to guarantee that nothing is using it so that all allocations happen deterministically. Async Rust schedules (mostly) cooperatively, which means one errant task, or too many tasks, can block higher-priority, time-critical work from occurring. Embassy has an interrupt executor, which helps somewhat, but…

> Async Rust (by default) can allocate memory

For bare-metal Rust firmware, you would always use no-std, which excludes a default allocator.

I understand from what you're saying that the principal difference between embassy-rs and what you'd expect from an RTOS is the choice of scheduling; as far as I can see, embassy-rs'es cooperative scheduler is even defended as highly intended.

The advantage of cooperative scheduling is that you don't need threads and context switching, since every yield gives control to the next task. And, as you say, the downside is that you can't reason about when yielding happens, so you can only hope that tasks yield often.

> interrupt executor [...] essentially ties each task to a dedicated interrupt, and AFAICT requires that all high-priority work must happen in interrupt context.

Hmm, that seems bad.

And how so is RTIC disqualified? It seems not classically preemptive.

https://rtic.rs/2/book/en/#rtic---the-past-current-and-futur...

https://interrupt.memfault.com/blog/embedded-async-rust#coop...

https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown

Re: Using the Rust standard library with the NuttX RTOS

#27
post #25
post #24

Earlier quoted context omitted.

Thank you for the elaborate explanation. I understand the definition of real-time. I just don't understand why you need an operating system, compared to building a real-time firmware application with a runtime that contains a scheduler, an allocator, and what else you might want from an OS. > Embedded async Rust (AFAIK) isn't suitable for building applications like these. Could you elaborate why? > in that sense, emb…

Async Rust (by default) can allocate memory, which is (almost always) nondeterministic. I'm not sure how hard it is to guarantee that nothing is using it so that all allocations happen deterministically. Async Rust schedules (mostly) cooperatively, which means one errant task, or too many tasks, can block higher-priority, time-critical work from occurring. Embassy has an interrupt executor, which helps somewhat, but…

> Async Rust (by default) can allocate memory

Strictly speaking, async rust never allocates. In fact, no language features do; allocation is a library concern in Rust.

What does allocate memory are the executors created for non-embedded environments. But just like any user-written code, you can use different implementations that do something else instead. Like you’d imagine, ones for embedded environments would use some statically allocated memory that’s bounded in size. Heck, you can go so far as to just leave them on the stack, like lilos: https://github.com/cbiffle/lilos/blob/main/doc/intro.adoc#us...

Not trying to say this means that you’re incorrect about any of the other things you’re talking about; I haven’t worked on realtime systems so I can’t speak on them.

Post reply on HN