Skip to content

sys: add shared event threads#12474

Merged
gschorcht merged 2 commits intoRIOT-OS:masterfrom
kaspar030:add_event_threads
Feb 7, 2020
Merged

sys: add shared event threads#12474
gschorcht merged 2 commits intoRIOT-OS:masterfrom
kaspar030:add_event_threads

Conversation

@kaspar030
Copy link
Contributor

Contribution description

Following the discussion in #12459, this PR shows how shared event threads could be implemented using sys/event.

This is basically a refactored version of https://github.com/haukepetersen/RIOT/tree/add_eventhandlerthread.

Testing procedure

Issues/PRs references

@kaspar030 kaspar030 added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR Area: sys Area: System labels Oct 16, 2019
@kaspar030
Copy link
Contributor Author

With per-thread stack sizes, the array is not so simple anymore ;(. The ifdef based configuration looks quite ugly.

@jia200x
Copy link
Member

jia200x commented Oct 16, 2019

Hi @kaspar030

AFAIS this is a follow up of #12459 (support for multiple threads using events). The mechanism is exactly the same. The event_thread module is a tasklets implementation.

Why don't we continue the discussion in #12459 first instead of opening a PR with the same principle? Or is this intended to be just a PoC?

@kaspar030
Copy link
Contributor Author

Why don't we continue the discussion in #12459 first instead of opening a PR with the same principle? Or is this intended to be just a PoC?

Well, my whole point is that "tasklets" are just event loops in dedicated threads. IMO that doesn't justify a new API. So yes, this is a PoC.

@haukepetersen
Copy link
Contributor

As suggested, lets continue the discussion in #12459 for now.

@maribu
Copy link
Member

maribu commented Oct 17, 2019

The implementations of both the tasklet/irq_handler and the shared event thread only differ very little, as they both spawn (a) worker thread(s) that work on event queues.

This are the differences:

  • The irq_handler uses a bool to track if the event is already in the queue. This is not needed, as [event_post() will not touch the event queue if the event is already in the list]. But maybe this check with the bool is a bit faster and it allows for the return value of -EALREADY. (But maybe we adapt event_post() to return that, so it can be passed through? Or maybe there is simply no need to know that the even was already queued?)
  • The irq_handler/tasklet exposes a void * argument. By putting even_t in a struct and using container_of() this could also be achieved here, but might be a bit more effort to use.

For end users the option to having a void * argument with little effort could be nice. But that could be implemented as static inline functions on top of this API using the same implementation and having no overhead.

@maribu
Copy link
Member

maribu commented Oct 17, 2019

To be more concrete maybe a sketch of adding the void * version on top of this:

typedef struct {
    even_t event;
    void *arg;
} event_with_arg_t;

static inline void event_post_with_arg(event_with_arg_t *ev, void *arg)
{
    unsigned state = irq_disable();
    ev->arg = arg;
    event_post(&ev->event);
    irq_restore(state);
}

static inline void *event_get_arg(event_t *event_with_arg)
{
    event_with_arg_t *ev = (event_with_arg_t *)event_with_arg;
    return ev->arg;
}

This might be a bit more accessible for application developers if they actually need a void * argument.

@haukepetersen
Copy link
Contributor

To be more concrete maybe a sketch of adding the void * version on top of this:

Its already there for quite a while: event/callback.h

@maribu
Copy link
Member

maribu commented Oct 17, 2019

OK. Then there is no need to for an additional API.

@haukepetersen
Copy link
Contributor

OK. Then there is no need to for an additional API.

We getting closer to the point that @kaspar030 was raising in the first place :-)

@maribu
Copy link
Member

maribu commented Oct 17, 2019

@kaspar030: Mind to steal the idea of using foo_params.h for configuration from #12480? With that, I'd say this fulfills all requirements that were stated so far.

@jia200x
Copy link
Member

jia200x commented Oct 17, 2019

OK. Then there is no need to for an additional API.

See #12459 (comment)

That's my point of view. But of course, that doesn't affect the way the modules work nor the problems we are trying to solve. So, I'm fine with how most people want to proceed ;)

@kaspar030
Copy link
Contributor Author

@kaspar030: Mind to steal the idea of using foo_params.h for configuration from #12480?

I think it is not that easy, as #12480 defines the stacks within the header. If we ensure that it is only included from event_threads.c, that is ok, otherwise we'll have multiple definitions.
I'll try.

#define EVENT_THREAD_LOWEST_STACKSIZE ISR_STACKSIZE
#endif
#ifndef EVENT_THREAD_LOWEST_PRIO
#define EVENT_THREAD_LOWEST_PRIO (THREAD_PRIORITY_IDLE - 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

We would have at most exactly two priorities and two threads, right? Shouldn't the lowest thread priority be (THREAD_PRIORITY_MAIN - 1)? Otherwise drivers would have to use again the high priority thread to ensure that their events are at least handled before the main thread is executed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Otherwise drivers would have to use again the high priority thread to ensure that their events are at least handled before the main thread is executed.

Maybe they want to, as in, "do this when there is time". That's why I've made it just one higher than idle.

How about I add a third priority ("medium"), which is just one higher than main? Or does the current very-low one make sense at all?

I mean, this is just the auto configuration, cpus / boards / applications can freely launch more handler threads...

Copy link
Contributor

Choose a reason for hiding this comment

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

How about I add a third priority ("medium"), which is just one higher than main? Or does the current very-low one make sense at all?

What priority should a thread have that is used by a driver to handle an interrupt from the hardware? IMHO, its priority should be at least higher than the priority of the main thread. A medium priority thread seems to be more important than a very low priority thread.

I mean, this is just the auto configuration, cpus / boards / applications can freely launch more handler threads...

Yes of course, but drivers can only use threads that are known from the auto configuration. Otherwise, they would need an additional thread parameter for the initializtion. This in turn would prevent the auto initialization.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What priority should a thread have that is used by a driver to handle an interrupt from the hardware?

I guess that depends... It is easy to add more priorities, so I propose I add one more middle priority (one higher than main) and see how far we go with that.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍 The three priorities high (0), medium (main-1) and low (idle-1) probably meet the requirements of most use cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added medium priority

@jia200x
Copy link
Member

jia200x commented Oct 21, 2019

(I copy&paste the comment from #12480 to continue the discussion here)

I think having multiple queues for now is a good approach. Eventually everything could be represented with a couple of queues, but this gives as a lot of flexibility for now.
One could think of:

#ifndef NET_RX_PRIO
#define NET_RX_PRIO TASKLET_PRIO_HIGH
#endif

#ifndef FOO_PRIO
#define FOO_PRIO TASKLET_PRIO_LOW
#endif

So, this gives the developer the mechanism to adapt the OS depending of the real time requirements.

@jia200x
Copy link
Member

jia200x commented Nov 1, 2019

can we continue with this? The netif rework is waiting for a feature for handling radio events from within the OS (:

This was referenced Nov 13, 2019
@kaspar030 kaspar030 force-pushed the add_event_threads branch 2 times, most recently from 0eaf8bd to 3581aef Compare January 9, 2020 14:06
@kaspar030
Copy link
Contributor Author

can we continue with this?

I've added a test script for the test application and license / doxygen to the main code.

@kaspar030
Copy link
Contributor Author

  • rebased, squashed, conceptually not WIP anymore.

@kaspar030 kaspar030 changed the title sys: add shared event threads (WIP) sys: add shared event threads Jan 9, 2020
@kaspar030 kaspar030 added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR labels Jan 9, 2020
@kaspar030
Copy link
Contributor Author

@jia200x want to take another look?

@kaspar030 kaspar030 added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Jan 16, 2020
@@ -0,0 +1,5 @@
include ../Makefile.tests_common

USEMODULE += event_thread_highest event_thread_medium event_thread_lowest
Copy link
Member

Choose a reason for hiding this comment

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

Can we define these as configuration values (CFLAGS) that depend on the module "event_thread"? Otherwise it's hard to configure it using Kconfig.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

how hard?

@jia200x
Copy link
Member

jia200x commented Jan 27, 2020

Code-wise looks OK. Same for the fundamentals.
I will test it with the script (and maybe I rebase it into one of my PRs where I need this feature).

I only have some comments regarding the "event_thread_***" pseudomodules. Also, it would be great if you can add the Kconfig file for this module.

@kaspar030
Copy link
Contributor Author

I only have some comments regarding the "event_thread_***" pseudomodules. Also, it would be great if you can add the Kconfig file for this module.

Would you be OK with keeping Kconfig out of this PR for now? Kconfig is quite new to me...

@jia200x
Copy link
Member

jia200x commented Feb 7, 2020

Would you be OK with keeping Kconfig out of this PR for now? Kconfig is quite new to me...

Ok, let's do it in a follow up then

@kaspar030
Copy link
Contributor Author

@maribu @gschorcht @jia200x I think all comments (apart from Kconfig) were addressed. Mind to take another look?

Copy link
Member

@maribu maribu left a comment

Choose a reason for hiding this comment

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

ACK. Very nicely boiled down the idea to small and maintainable code :-)

Some boards have to little RAM to compile the test and there is still a bug in the LPC2387 CPU (ISR_STACKSIZE is defined as ((unsigned) &__stack_irq_size), which is a super strange construct; why should an address of a variable be considered to be a size?). I suggest to blacklist that CPU for now, until that issue is fixed. (I could do so, unless @benpicco is faster ;-))

@gschorcht
Copy link
Contributor

ACK from my side, please squash.

@kaspar030
Copy link
Contributor Author

Some boards have to little RAM to compile the test

yup, added them to Makefile.ci.

there is still a bug in the LPC2387 CPU (ISR_STACKSIZE is defined as ((unsigned) &__stack_irq_size), which is a super strange construct; why should an address of a variable be considered to be a size?)

Yeah, the linker can only provide addresses, but arbitrary values in those... I've adde arch_arm7 to FEATURES_BLACKLIST.

@kaspar030
Copy link
Contributor Author

  • squashed, adressed last comments

@gschorcht
Copy link
Contributor

All lights are green, let's go.

@gschorcht gschorcht merged commit 3514eec into RIOT-OS:master Feb 7, 2020
@gschorcht
Copy link
Contributor

gschorcht commented Feb 7, 2020

@kaspar030 Thanks for the contribution. @maribu We should restart with the process you tried in PR #12486.

@kaspar030
Copy link
Contributor Author

Thanks everyone!

@kaspar030 kaspar030 deleted the add_event_threads branch February 7, 2020 22:03
@leandrolanzieri leandrolanzieri added this to the Release 2020.04 milestone Feb 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: sys Area: System CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants