embassy-rs / embassy

Modern embedded framework, using Rust and async.
https://embassy.dev
Apache License 2.0
5.66k stars 790 forks source link

Pre-RFC: Investigate switching to intrusive waker lists by default #3109

Open jamesmunns opened 5 months ago

jamesmunns commented 5 months ago

This needs a more formal write up, but the root issue is that:

As one potential fix to this is using the primitives from maitake-sync:

There is however one major blocker: maitake-sync currently uses a spinlock mutex for its blocking mutex, and is not generic over different blocking mutex, like the RawMutex trait of embassy-sync. The author of maitake-sync, @hawkw (I am also a maintainer, but Eliza has done the vast majority of heavy lifting), has mentioned that she is open to parameterizing the maitake-sync collections similarly to how embassy-sync does it.

So my concrete proposal would be:

This will require a fair bit of work, but should IDEALLY not have any publicly breaking interface changes for users of embassy-sync, though it may have some (mostly benefitial, ideally) functional changes.

I expect this change would:

Overall, I think this is worth investigating/discussing, as it has come up a number of times in chat (not a ton! But enough now that it is a semi-known failure mode).

Some open questions include:

CC: @hawkw @ivmarkov @Dirbaio

ivmarkov commented 5 months ago

(UPDATED)

  • Split out the RawMutex traits into a separate crate (embassy-sync-mutex, or something?), to allow for both embassy-sync and maitake-sync to rely on this

Splitting out RawMutex into its own micro-crate (ala embassy-time-driver and embassy-net-driver) - that is - if you decide against forking a subset of maintake-sync into embassy-sync - might have use-cases beyond your idea of re-using it in maintake-sync so that embassy-sync can depend on maintake-sync rather than fork it.

For example, that would give "easier time" to RawMutex implementor code that lives outside the embassy-sync crate. esp-idf-hal is currently such one, by providing two separate mutex implementations - one - based on "disable all interrupts (+ spinlocks for multi-core)" and another - based on regular FreeRTOS mutexes.

The thing is, the "one size fits all" approach of critical-section just does not work for traditional RTOSes, where you might need different types of blocking mutexes, depending on the context where you would like to use those. Abstracting by using RawMutex instead (and sure - by introducing generics that way) is one way to solve that in driver crates.

Currently, esp-idf-hal depends directly on embassy-sync, which is a bit painful. For example, our next release would be a breaking one, because embassy-sync currently went from 0.5 to 0.6. That's definitely not the only reason but could've been the only reason to issue a breaking release, which is not ideal.

jamesmunns commented 5 months ago

Splitting out RawMutex into its own micro-crate (ala embassy-time-driver and embassy-net-driver) - that is - if you decide against forking a subset of maintake-sync into embassy-sync - might have use-cases beyond your idea of re-using it in maintake-sync so that embassy-sync can depend on maintake-sync rather than fork it.

Just confirming that I agree 100%! I didn't spell this out, but I definitely think this is a positive.

hawkw commented 4 months ago

Regarding abstracting over raw mutex types, I would encourage investigating whether the lock_api crate can be used for that purpose --- it's pretty widespread in the non-embedded world, as parking-lot uses lock-api, but it also claims to have no-std support. I would look into whether its traits are suitable for our purpose. If they are, it's probably better to use the commonly-used trait rather than inventing a new version of it.

xgroleau commented 3 months ago

This would be great as this would also fix #1204 when using multiple executor with different interrupt priorities which would make embassy better equipped when users needs to do real time operations.

peterkrull commented 5 days ago

I'm just leaving a comment here to express interest in using WaitQueue as well. Presumably it would simplify the type signatures of the PubSubChannel and Watch channels since the number of senders/receivers would no longer need to be defined at compile time, and obtaining a receiver would always succeed.