modm-io / modm

modm: a C++23 library generator for AVR and ARM Cortex-M devices
https://modm.io
Mozilla Public License 2.0
748 stars 132 forks source link

[fiber] multi stack size ? #1030

Closed lukh closed 1 year ago

lukh commented 1 year ago

Is there any ways to create fibers "stacks" with various stack size ? I got stuck while porting legacy protohread code with fiber, (5x "protothread") running out of RAM (stm32f072)

I would need to create 4 fibers with 256bytes of stacks, and 1 with 512. How would I implement that ? Thanks

chris-durand commented 1 year ago

Hi @lukh, you can pass the stack size as a template argument to modm::Fiber, e.g. modm::Fiber<256> for 256 bytes and modm::Fiber<512> for 512 bytes, respectively.

lukh commented 1 year ago

thanks, since it is for protothread, I did try to update "protothread.hpp":

line 29/30 template <size_t ProtoThread_StackSize = MODM_PROTOTHREAD_STACK_SIZE> class Protothread : public modm::Fiber< ProtoThread_StackSize >

But my cpp20+ is limited and can't get through the compile error:

modm/src/modm/processing/protothread/protothread.hpp: In constructor 'modm::pt::Protothread<ProtoThread_StackSize>::Protothread(modm::fiber::Start)': modm/src/modm/processing/protothread/protothread.hpp:34:17: error: class 'modm::pt::Protothread<ProtoThread_StackSize>' does not have any field named 'Fiber' 34 | : Fiber([this](){ while(update()) modm::fiber::yield(); }, start)

salkinium commented 1 year ago

I designed it to be as backward compatible as possible, therefore the Protothread class is not a template, otherwise you'd need to change all protothreads to inherit from modm::pt::Protothread<> to satisfy the default template argument, which defeats the point of backward compatibility. Therefore the global stack size.

You can instead convert the protothread into a fiber manually by removing the inheritance and calling the update function directly in a fiber:

class MyThread : modm::pt::Protothread
{
public:
    bool update() {...}
};
MyThread thread;

becomes

class MyThread // no inheritance => no stack
{
public:
    bool update() {...}
};
MyThread proto_thread;
modm::Fiber<256> thread([](){ proto_thread.update() });

You can of course also just move the entire update function into the fiber lambda, but that may require more work if you have a lot of member variables.

salkinium commented 1 year ago

Were you able to apply my ideas to your project?

lukh commented 1 year ago

sorry for the long delay. Yes it did work ! (well, I needed / still need to optimize code, but it will work) Was a pretty smooth migration, regarding the changes and the "emergency" level. Thanks a lot