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

Implement Protothreads as Fibers #1001

Merged
merged 9 commits into from
May 14, 2023

Conversation

salkinium
Copy link
Member

@salkinium salkinium commented Apr 16, 2023

Adds a modm:processing:protothread:use_fiber option that makes the modm::Protothread behave like a fiber with a default stack.
The only change required is to replace the main loop calling all the protothread run() functions with the modm::fiber::Scheduler::run(); function.

  • Remove modm:__fibers guard option and make the modm:processing:fiber module available by default.
  • ReImplement the Protothread class by inheriting from the Fiber class.
  • Reimplement the RF_* and PT_* macros.
  • Adapt the manual implementations of resumable function (SPI transfer) to use yields.
  • Separate Stack and Task and combine into Fiber class.
  • Much more Documentation
  • Simpler instantiation of Scheduler class. One scheduler class per (hardware) thread, fibers must be added only within the thread context, not from the outside.
  • Fibers can be restarted now!
  • Simpler unregister scheme that save a bit of stack.
  • More accurate minimal stack sizes.
  • Stack usage measurement through watermarking!
  • Simpler context API.
  • Fibers can be placed into .noinit sections, since they are constructed only at runtime.

@chris-durand
Copy link
Member

chris-durand commented Apr 16, 2023

Thanks for starting to work on this.

I have the feeling that the resumable function compatibility layer could be much simpler than the proposed solution. The resumable function mechanism itself shouldn't be required anymore using fibers. Can't we define all the resumable classes as empty no-ops and just use modm::yield() from the WAIT_ macros? Many other macros could be doing nothing. RF_BEGIN/END could be empty, RF_CALL(x()) is x(), RF_RETURN(x) is return x, ResumableResult<T> is an alias for T and so on? Or do we really need the nesting level checking in fiber mode?

I really want to get rid of all the potential undefined behaviour issues with resumable functions (like in #993) when fibers are enabled. EDIT: Your solution should not have that anymore.

A long time ago I have played around with this. That was my first prototype of that simple concept which completely ignored protothreads, but it let's you use resumable drivers from fibers: chris-durand@5f3c900

@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch 2 times, most recently from 934f34b to 11c06d9 Compare April 16, 2023 02:49
@salkinium
Copy link
Member Author

Yeah, good point. I wanted to have something completely drop-in replacable, but it makes no sense to only go half-way.

@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch 2 times, most recently from 260778d to 40d4bde Compare April 16, 2023 12:43
@salkinium
Copy link
Member Author

I made the resumables transparent now, which is nice, because you can now simply call "ex-resumabe" functions without any macros at all. This even works without a scheduler at all (yield() simply returns in-place), which is the case inside the main function or when there is only one fiber running. So wins all around.

@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch 3 times, most recently from bd11fc2 to 7b813b5 Compare April 17, 2023 20:57
@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch 2 times, most recently from fb58e6a to 7ff65db Compare April 30, 2023 19:39
@salkinium
Copy link
Member Author

salkinium commented Apr 30, 2023

Ok, I've refactored a lot of the implementation to make fiber consume a little bit less stack and be restartable.
Long-term goals to be implemented some time later:

  • Support for signalling from interrupt context, ie. wake this fiber up.
  • Support for Semaphores and Mutexes, Message Queues between fibers.
  • Support for schedulers in FreeRTOS threads, using thread-local storage.
  • Perhaps use the FPU lazy-stacking feature to speed up the fiber context switch.
  • Use Stack Limit Registers on ARMv8-M devices.
  • Refactor more examples and more drivers to use fibers directly.
  • Add static stack usage calculator, integrate puncover? watermarking

@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch from 7ff65db to 42b5add Compare April 30, 2023 22:37
@chris-durand chris-durand self-requested a review April 30, 2023 22:41
@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch from 42b5add to ca214fe Compare April 30, 2023 23:00
@salkinium salkinium marked this pull request as ready for review April 30, 2023 23:01
@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch from ca214fe to 0ebf256 Compare May 6, 2023 19:02
@salkinium salkinium requested a review from rleh May 6, 2023 19:04
@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch from 0ebf256 to a762500 Compare May 6, 2023 19:10
@salkinium
Copy link
Member Author

Ok, this is now quite polished. I refactored the context API and implementation so that stack watermarking can be used to measure stack usage on all platforms. Fixed some minor things on AVR. I'm very happy with this now.

If you want to review and it's a bit much, then focus more on the usability of the fiber API, rather than the implementation. It's easier to get the implementation right, since it simply crashes if its wrong ;-P

@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch 3 times, most recently from d047f6e to 63fc9b6 Compare May 6, 2023 20:39
@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch 3 times, most recently from b9f93ec to 965efe7 Compare May 6, 2023 22:19
@salkinium
Copy link
Member Author

Man, this crap macOS CI is a pain to maintain without containers.

@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch from 965efe7 to f2692ca Compare May 7, 2023 20:49
@salkinium
Copy link
Member Author

I added a bunch more doxygen documentation and moved the stack usage into the fiber context.

@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch 2 times, most recently from 9d02a37 to 17772ef Compare May 7, 2023 22:22
Copy link
Member

@chris-durand chris-durand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice!

src/modm/driver/time/cycle_counter.hpp.in Outdated Show resolved Hide resolved
src/modm/driver/time/cycle_counter.lb Show resolved Hide resolved
src/modm/processing/fiber/task.hpp Outdated Show resolved Hide resolved
src/modm/processing/fiber/stack.hpp.in Show resolved Hide resolved
src/modm/processing/fiber/stack.hpp.in Outdated Show resolved Hide resolved
src/modm/processing/fiber/scheduler.hpp.in Outdated Show resolved Hide resolved
src/modm/processing/fiber/scheduler.hpp.in Show resolved Hide resolved
@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch from 17772ef to f8d650d Compare May 14, 2023 18:29
- Fiber compound class with integrated stack.
- Fibers can be restarted.
- Fiber stack usage measurement.
- Correct stack word type on AVRs.
- Simpler context API.
@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch from f8d650d to 8b07dba Compare May 14, 2023 18:50
Adds an lbuild option to replace the Protothread and (Nested)Resumable
implementation with a fiber one that is almost entirely backwards
compatible.
@salkinium salkinium force-pushed the feature/protothread_fiber_macros branch from 8b07dba to c1bf519 Compare May 14, 2023 19:11
@salkinium salkinium merged commit 260143c into modm-io:develop May 14, 2023
@salkinium
Copy link
Member Author

Alright, thanks!

My next plans are to implement light-weight mutex, semaphore, signals, and queues, so that we can have a smarter/simpler scheduler than the linked list right now.

My ultimate goal is to have a composable fiber implementation that still works with FreeRTOS above and C++ coroutines below:

  • Completely Separate Devices
    • Asynchronous MultiCore Execution
      • Preemptive, Stackful Threads
        • Cooperative, Stackful Fibers
          • Cooperative, Stackless C++ Coroutines or C Protothreads/Resumables
            • Blocking Functions
              • Nested Interrupts

@hshose
Copy link
Contributor

hshose commented Mar 13, 2024

Huge shout-out to everyone who helped implement the Fibers 🥇

I just started using them for the first time in a larger project and about 1h in, it feels so much nicer then the @%$!!@# PROTOTHREADS already 😸

Although, default stack size could be 1k (at leasts thats what I need for even mild use of MODM_LOG_XXX)

Also, my systems default arm gcc 13 can be used again, no more #1012 ❤️

Maybe, this comment should have gone to #743 too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

4 participants