reserve main and let application define thread(s)

Dear RIOTers,

today's question from Murat and my past efforts with native have one thing in common: our environments have a hard (or impossible) to change dependency on main() as the system's entry point.

For native, I was able to navigate around this, but past mails to this list show that this has (negative) implications for c++ (which are unfixed as of today). Murat says with PsoC it is impossible to navigate around this restriction.

I imagine we might see more platforms with a fixed idea of main in the future where RIOT's use of main for the first application thread function is a problem.

My proposal: Let the application Makefile export one or possibly several names to be used for the initial application thread(s). kernel_init will then take care of creating those. The function name "main" will be reserved for boards/cpus to implement. In case of native/PsoC, the cpu's or board's main function can then call kernel_init (after possibly taking care of their respective initialization).

Bonus benefits/implications: The application gets to define the name(s) of (all) it's thread(s), the setting of this thread's priority, stacksize, flags etc. become more obvious, it will be possible to have applications without any application thread (maybe auto_init is enough for a router in the future?), and possibly more I didn't think of immediately :wink:

Please discuss!

Cheers, Ludwig

Hi!

My proposal: Let the application Makefile export one or possibly several names to be used for the initial application thread(s). kernel_init will then take care of creating those. The function name "main" will be reserved for boards/cpus to implement. In case of native/PsoC, the cpu's or board's main function can then call kernel_init (after possibly taking care of their respective initialization).

+1

Cheers, Oleg

+1 for making RIOT a little bit more flexible in this regard.

BTW: The proposal would also make testing a little bit easier.

Best,

Philipp

Hey,

+1 for not using main() as application entry point(s).

Hi,

>My proposal: >Let the application Makefile export one or possibly several names to >be used for the initial application thread(s). kernel_init will then >take care of creating those. I'd like to see a nice (idea on how to do an) implementation of this... I hope we don't end up with too much macro magic.

A solution without any macro magic would be to require "application_init" to exist, call that from kernel_init, and let the application create its own threads. Not overly convenient, but as the usual workflow for creating applications is copy'n'paste of an existing application it wouldn't hurt much either.

Cheers, Ludwig

Hi,

> >My proposal: > >Let the application Makefile export one or possibly several names to > >be used for the initial application thread(s). kernel_init will then > >take care of creating those. > I'd like to see a nice (idea on how to do an) implementation of this... > I hope we don't end up with too much macro magic.

A solution without any macro magic would be to require "application_init" to exist, call that from kernel_init, and let the application create its own threads. Not overly convenient, but as the usual workflow for creating applications is copy'n'paste of an existing application it wouldn't hurt much either.

I created quick&dirty branches for both methods:

plain c:

macro magic:

Not sure which one I dislike better :wink:

Cheers, Ludwig

Hi,

I created quick&dirty branches for both methods:

plain c: GitHub - LudwigKnuepfer/RIOT at wip/remove-main-application-init macro magic: GitHub - LudwigKnuepfer/RIOT at wip/remove-main-make

Not sure which one I dislike better :wink:

:wink:

I think we should come up with a method that enables inclusion of multiple application threads. Maybe we can even replace auto_init in the process.

We could have something like

struct _auto_thread {   char* name;   char* stack;   int stacksize;   ... };

struct _auto_threads = {    {"idle", idle_stack, STACKSIZE_IDLE, PRIORITY_IDLE, NULL },    {"default", main_stack, STACKSIZE_MAIN, PRIORITY_MAIN, NULL },    {"application", app_stack, ... } };

The second struct we create during the build process and write it to a file that gets includes by kernel_init.c. There, we just traverse the list in order to start the threads.

For the makefiles we devise a way to declare these threads. Maybe something easily parsable like

THREADS += "(application;PRIORITY_MAIN+1;STACKSIZE_MAIN+STACKSIZE_PRINTF;dependency1,transceiver)"

... with a lot of sensible defaults so John Duino can just do

THREADS += my_app

We could also introduce some kind of "image build description" file that holds the necessary thread configuration:

E.g., defining one thread named "default" using a default stacksize, default function name (default_thread), with a dependency on transceiver: ----- examples/default/default.yaml: default:   depends: [ transceiver ]

Hi,

I created quick&dirty branches for both methods:

plain c: GitHub - LudwigKnuepfer/RIOT at wip/remove-main-application-init macro magic: GitHub - LudwigKnuepfer/RIOT at wip/remove-main-make

Not sure which one I dislike better :wink:

I like the main-application-init version because it is still somewhat simple to follow. Perhaps it would be possible to still keep the trampoline but make it execute application_init instead of main and let auto_init() execute from the trampoline. This eliminates the need to modify the example applications.

:wink:

I think we should come up with a method that enables inclusion of multiple application threads. Maybe we can even replace auto_init in the process.

We could have something like

struct _auto_thread {         char* name;         char* stack;         int stacksize;         ... };

struct _auto_threads = {   {"idle", idle_stack, STACKSIZE_IDLE, PRIORITY_IDLE, NULL },   {"default", main_stack, STACKSIZE_MAIN, PRIORITY_MAIN, NULL },   {"application", app_stack, ... } };

The second struct we create during the build process and write it to a file that gets includes by kernel_init.c. There, we just traverse the list in order to start the threads.

For the makefiles we devise a way to declare these threads. Maybe something easily parsable like

THREADS += "(application;PRIORITY_MAIN+1;STACKSIZE_MAIN+STACKSIZE_PRINTF;dependency1,transceiver)"

... with a lot of sensible defaults so John Duino can just do

THREADS += my_app

We could also introduce some kind of "image build description" file that holds the necessary thread configuration:

E.g., defining one thread named "default" using a default stacksize, default function name (default_thread), with a dependency on transceiver: ----- examples/default/default.yaml: default:         depends: [ transceiver ] -----

Defaults and modules: ----- modules.yaml: _defaults:         stacksize: STACKSIZE_MAIN

transceiver:         depends: [ pkt_buf ]         stacksize: INTERESTING_DEFINE

dumb_module:         thread: false # this module doesn't have a thread         init: true # we will call "dumb_module_init" on bootup -----

All that we parse and auto-generate the corresponding C code.

Not sure if we're entering a world of pain this way. :wink:

This is a good looking solution for a large project with a clear and well-specified build environment etc. but I think in this case we will be over-complicating the build system.

BR, Joakim Gebart www.eistec.se

Hi,

>> >> I created quick&dirty branches for both methods: >> >> plain c: >> GitHub - LudwigKnuepfer/RIOT at wip/remove-main-application-init >> macro magic: >> GitHub - LudwigKnuepfer/RIOT at wip/remove-main-make >> >> Not sure which one I dislike better :wink:

I like the main-application-init version because it is still somewhat simple to follow. Perhaps it would be possible to still keep the trampoline but make it execute application_init instead of main and let auto_init() execute from the trampoline. This eliminates the need to modify the example applications.

My reason for moving autoinit to the application threads was that it is currently also executed in a thread context. I wasn't sure (and too lazy to find out) if there are good reasons for this.

The test and example applications would need to be modified anyways. First to add the application_init function, and also because the main function need to be renamed.

Cheers, Ludwig

Hi,

>I created quick&dirty branches for both methods: > >plain c: >GitHub - LudwigKnuepfer/RIOT at wip/remove-main-application-init >macro magic: >GitHub - LudwigKnuepfer/RIOT at wip/remove-main-make > >Not sure which one I dislike better :wink: :wink:

I think we should come up with a method that enables inclusion of multiple application threads. Maybe we can even replace auto_init in the process.

A possible removal of auto_init is a separate concern from my point of view, so I'd like to keep it out of the discussion for now. If you disagree you need to elaborate, because I don't see how this fits in.

We could have something like ... All that we parse and auto-generate the corresponding C code.

Not sure if we're entering a world of pain this way. :wink:

Call me bourgeois, but I would rather use macros than generating C code somewhere in the build system. (Or you could try to convince me with the power of code :wink:

I liked the idea with the list, though.

Cheers, Ludwig