-
Notifications
You must be signed in to change notification settings - Fork 143
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
[fiber] Stackful cooperative scheduling via Fibers #743
Conversation
cb86910
to
403a232
Compare
Shouldn't the function rather be named |
Yes, but I'm still working to port fibers to AVR, and haven't gotten to the API yet. |
403a232
to
267fbea
Compare
I've added a context switch based on avr-fibers and the GCC calling convention and register layout, however, it doesn't work entirely and as I cannot debug my AVR hardware, I've only been poking around in darkness as to why. In my mind it should just work, but I cannot even jump into the beginning of a fiber call. I'm going to use simavr to try and debug it. |
f5d372f
to
55c7da2
Compare
I fixed the AVR fibers, turns out the ATmega2560 is using a 3 byte PC. 🙄 |
9fb5836
to
5b3b722
Compare
I'm not sure the x86_64 context switch is working correctly on Windows, I didn't understand what the previous implementation was doing with |
5b3b722
to
6cbc12e
Compare
I compared the x86_64 context switch to the implementation in boost context and found big differences for the Microsoft ABI. They also save XMM6-XMM15 floating point registers and other things. It looks like we are also missing some x87 floating point state for Unix x86_64 platforms. There is some info in the boost context docs. |
Oh boy… I'll check out if we can use setjmp/longjmp instead on Hosted. That would also give us ARM64 Linux support. |
6cbc12e
to
e0039f8
Compare
I'll review tomorrow. |
I've moved all stacks into the fastest DMA-able memory and added a guard option We'll have to see how annoying it is to have two incompatible API next to each other… I will also restructure the one commit into a few different ones, they are all squashed together until I got things working. |
There is still something wrong with the
It also crashes when I correctly initialize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
f0719bd
to
a8e5c18
Compare
I think the waitable implementation is too clever for me, it tries to reorder the list of fibers for low latency and I think it does it wrongly? I would prefer to have a dumber polling based implementation first to explore the usefulness of the API. The current implementation also doesn't work from an ISR context, which is what is needed to implement interrupt driven peripheral drivers. I've removed the Waitables for now, since we also don't have a Protothread/Resumables version of those and therefore aren't necessary to replace them. |
baa8246
to
dfdddc9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's merge it without the waitables. They can be added later if required.
dfdddc9
to
3936a28
Compare
Just an idea. If the fiber knows the stack size it only costs a few instructions extra to check for overflow during stack swap. It would be a nice option to have. |
This continues the work in #439. The changes/additions so far:
Main function
The main function is not a fiber anymore, the developer has to manually start the scheduler.
modm::fiber::yield()
will return if scheduler is not running, therefore looping in the main functions. This will most likely work fine for interrupt/flags driven peripheral access like I2C, SPI and UART, however, won't work for any class that requires an update() function to be polled (but that didn't work withRF_CALL_BLOCKING
either).The
scheduler::run()
function will return to the main function if all fibers stop running (or if all functions have yielded). This can be used for sleeping and idle thread functionality.This also treats the main function consistently across all platforms and carries no performance overhead if not using fibers.
I've also moved all classes into the
modm::fiber
namespace, since I'm worried about compatiblity with FreeRTOS and I don't want people believing thatmodm::yield()
makes their code magically reentrant or something stupid like that. In general users should not have to manually yield, but rather use some higher-level primitive or modm API anyways.Cortex-M Context Switch
I've optimized the context switch assembly by using the push LR, pop PC pair correctly. This significantly speeds up the context switch. For FPU enabled devices, we only need to store the upper 16 floating point registers, since the lower ones are not saved across subfunction calls according to the EABI. This does double the switching time, perhaps in future we can investigate optimizations via the FPU flags register.
Fibers run on the PSP, while the main function and the interrupts use the MSP whose size is defined by the existing lbuild option
modm:platform:cortex-m:main_stack_size
.Guard Option
There is an invisible guard option
modm:__fibers
which prevents the fibers from being shown in modm.io modules and the doxygen docs until it is ready. This is particularly important for adding new peripheral drivers that may use a completely different API without resumable functions and shouldn't be exposed to the users right now.Stack Placement
On STM32F4 with CCM, the main stack has been moved into RAM, since the CCM is not DMA-able. On all other STM32 the main and
modm_faststack
are placed in the fastest DMA-able memory. We will have to see how well the Cortex-M7 DTCM is really accessible for DMA, we'll deal with that later.TODO:
Integrate puncover to get max stack size analysis.not trivial, will investigate laterARM64 supportCannot test it, delegating to future