Skip to content

Conversation

@kaspar030
Copy link
Contributor

@kaspar030 kaspar030 commented Oct 26, 2016

I've been playing around with asynchronous event (callbacks). This is my current code, which I think might make it possible to write more predictable asynchronous applications, compared to using message queues.

PR'ing it now so others can take an early look.

@kaspar030 kaspar030 added State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Type: new feature The issue requests / The PR implemements a new feature for RIOT Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR labels Oct 26, 2016
@miri64
Copy link
Member

miri64 commented Oct 26, 2016

PR #6000 🎉

@miri64
Copy link
Member

miri64 commented Oct 26, 2016

Are there still plans on your side to merge this with the event timer in #5999?

@kaspar030
Copy link
Contributor Author

yes, but I wanted to get this PR'ed for numerological reasons. ;)

-----Original Message-----
From: Martine Lenders notifications@github.com
To: RIOT-OS/RIOT RIOT@noreply.github.com
Cc: Kaspar Schleiser kaspar@schleiser.de, Author author@noreply.github.com
Sent: Mi., 26 Okt. 2016 22:57
Subject: Re: [RIOT-OS/RIOT] sys: add asynchronous event system (#6000)

Are there still plans on your side to merge this with the event timer in #5999?

You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub:
#6000 (comment)

@miri64 miri64 self-assigned this Nov 10, 2016
@miri64 miri64 added this to the Release 2017.01 milestone Nov 10, 2016
@haukepetersen
Copy link
Contributor

As talked offline, this PR would be very useful for integrating events into SAUL!

@kaspar030: would you mind to

  • add documentation
  • add some kind of test or unittest for both testing and demonstration purposes
    thanks!

@miri64 miri64 mentioned this pull request Jan 4, 2017
@miri64
Copy link
Member

miri64 commented Jan 24, 2017

Postponed due to feature freeze.

@miri64 miri64 modified the milestones: Release 2017.04, Release 2017.01 Jan 24, 2017
@miri64
Copy link
Member

miri64 commented Oct 2, 2017

Any plans to further work on this?

@kaspar030
Copy link
Contributor Author

Yes! I've been using it for the latest jerryscript work. I'll update this PR soon.

@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 Discussion: RFC The issue/PR is used as a discussion starting point about the item of the issue/PR State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet labels Oct 22, 2017
@kaspar030
Copy link
Contributor Author

This is ready for review.

@kaspar030
Copy link
Contributor Author

Are there still plans on your side to merge this with the event timer in #5999?

This PR contains some code for timing events, but for now they're xtimer based. If we see it would make sense, we can extend or modify later.

@kaspar030
Copy link
Contributor Author

add documentation

Done.

add some kind of test or unittest for both testing and demonstration purposes

Done.


/**
* @ingroup sys_event
* @brief Provides functionality to trigger events after timeout
Copy link
Member

Choose a reason for hiding this comment

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

Question for clarification: Is this to replace evtimer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope. This is so that users of the event module can also have timed events. It would probably be a good idea to implement event_timer_t on top of evtimer. The similarity of the names is unfortunately confusing...

Copy link
Member

Choose a reason for hiding this comment

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

Well this PR provides an event queue implementation, evtimer is a timed event queue. Shouldn't there be some way to merge them? What is event_timer_t?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is, maybe, but not a trivial one... Also, the use-cases are quite different. evtimer basically runs thread-independent, with it's event handlers being run in ISR context.
This event queue is much more under user control.

What is event_timer_t?

I meant event_timeout_t, the method of haveing timed events within event queues.

Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

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

Some preliminary review.

* one thread, e.g., in order to create a state-machine like process flow.
* This is not (easily) possible using msg queues, as they might fill up.
* 4. an event can only be queued in one event queue at the same time.
* Notifying many queues using only one event object is impossible.
Copy link
Member

Choose a reason for hiding this comment

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

Wording: I doubt the impossibility of this. I might however be convinced that it is not possible with this implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

/**
* @brief Thread flag use to notify available events in an event queue
*/
#define THREAD_FLAG_EVENT 0x1
Copy link
Member

Choose a reason for hiding this comment

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

Params? Also, not sure how flag colisions are handled in thread_flags in general.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about it... making this configurable per queue adds 33% to the queue structure's size...
I hoped that we can get by with one queue per thread, in which case a globally configurable constant might be ok...

OK to leave as is and gather experience?

Copy link
Member

Choose a reason for hiding this comment

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

Params?

That was a typo... what I meant was "parans" ;-). As such I think you misunderstood the second half: I'm actually not sure if other modules using thread_flags won't collide with the flag you define here, so can you put my mind here at ease?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

parans

fixed

I'm actually not sure if other modules using thread_flags won't collide with the flag you define here, so can you put my mind here at ease?

Maybe half. :) Users of thread_flags might actually collide by using the same thread flag. I don't see that as a huge problem (unlike crashing msg ids), as thread flags are supposed to be used in a "notifying" way, meaning "there might be something you might want to look at".

As said, I'd like to gather some experience before deciding whether the flag number needs to be changed and/or made configurable.

*
* This will set the calling thread as owner of @p queue.
*
* @param[in,out] queue event queue object to initialize
Copy link
Member

Choose a reason for hiding this comment

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

I would argue it is just an out parameter. Or are there any fields required to be set before 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.

fixed

*
* Examples:
*
* // simple event handler
Copy link
Member

Choose a reason for hiding this comment

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

Guard with

~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
...
~~~~~~~~~~~~~~~~~~~~~~~~~~~

for maximum syntax flavor ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

*
* It is pretty much defined as:
*
* while((event = event_wait(queue))) {
Copy link
Member

Choose a reason for hiding this comment

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

Use C-fences?

~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
...
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@@ -0,0 +1,80 @@
/*
Copy link
Member

Choose a reason for hiding this comment

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

Please add a readme and/or a pexpect script.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@kaspar030
Copy link
Contributor Author

(I had a rebase mishap, that's fixed now)

  • fixed ~~~~~~~ {.c}
  • added parens

Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

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

Final review. Apart from a few nits in style and wording:

  • I'm not happy about the usage of implicit sub-modules, better use explicit ones.
  • event_timeout work on a microsecond scale, so why are their tests on a second scale. Wastes time during testing ;-).

@@ -0,0 +1,5 @@
SRC := event.c

SUBMODULES = 1
Copy link
Member

Choose a reason for hiding this comment

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

I don't think that this is managed pretty transparent here. For core I was understanding of that, but in sys the sub-folders for sub-modules is already established (also you don't need pseudo-modules then ;-)).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand transparent.
Using submodules here saves two folders and two makefiles with 2 lines each.

Copy link
Member

Choose a reason for hiding this comment

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

But makes it harder for newcomers to understand what to include ... (that's what I meant with transparent)

event_callback->callback(event_callback->arg);
}

void event_callback_init(event_callback_t *event_callback, void (callback)(void*), void *arg)
Copy link
Member

Choose a reason for hiding this comment

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

extra space before void *arg

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

event_callback->callback(event_callback->arg);
}

void event_callback_init(event_callback_t *event_callback, void (callback)(void*), void *arg)
Copy link
Member

Choose a reason for hiding this comment

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

Missing space in-between void* in the callback parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup


#include "event/timeout.h"

static void _event_timeout_callback(void* arg)
Copy link
Member

Choose a reason for hiding this comment

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

s/\* / \*/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup

* @ingroup sys
* @brief Provides an Event loop
*
* This module offers an event queue framework not unlike libevent or libuev.
Copy link
Member

Choose a reason for hiding this comment

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

Maybe make it a little easier on non-native speakers and remove the double negative.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

*/
typedef struct {
event_t super; /**< event_t structure that gets extended */
void (*callback)(void*); /**< callback function */
Copy link
Member

Choose a reason for hiding this comment

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

s/void*/void */

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep

Copy link
Member

Choose a reason for hiding this comment

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

Not applied ;-)

* @param[in] callback callback to set up
* @param[in] arg callback argument to set up
*/
void event_callback_init(event_callback_t *event_callback, void (*callback)(void*), void *arg);
Copy link
Member

Choose a reason for hiding this comment

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

s/void*/void */

* @param[in] callback callback to set up
* @param[in] arg callback argument to set up
*/
void event_callback_init(event_callback_t *event_callback, void (*callback)(void*), void *arg);
Copy link
Member

Choose a reason for hiding this comment

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

Remove one space before void *arg

{ \
.super.handler=_event_callback_handler, \
.callback=_cb, \
.arg=(void*)_arg \
Copy link
Member

Choose a reason for hiding this comment

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

s/void\*/void \*/

printf("posting timed callback with timeout 1sec\n");
event_timeout_init(&event_timeout, &queue, (event_t*)&event_callback);
before = xtimer_now_usec();
event_timeout_set(&event_timeout, 1000000);
Copy link
Member

Choose a reason for hiding this comment

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

I think this can be smaller by at least one magnitude (maybe 100000).

Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

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

Running uncrustify over your code revealed some more minor coding-style related issues.

{ \
.super.handler=_event_callback_handler, \
.callback=_cb, \
.arg=(void*)_arg \
Copy link
Member

Choose a reason for hiding this comment

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

Please add spaces before and after the =s

void event_loop(event_queue_t *queue)
{
event_t *event;
while((event = event_wait(queue))) {
Copy link
Member

Choose a reason for hiding this comment

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

Space between while and (



static event_t event = { .handler=callback };
static event_t event2 = { .handler=callback };
Copy link
Member

Choose a reason for hiding this comment

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

spaces missing around inner assignments.

{
puts("[START] event test application.\n");

event_queue_t queue = { .waiter=(thread_t*)sched_active_thread };
Copy link
Member

Choose a reason for hiding this comment

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

Spaces missing around inner assignment

Copy link
Member

Choose a reason for hiding this comment

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

s/thread_t\*/thread_t \*/

const char *text;
} custom_event_t;

static custom_event_t custom_event = { .super.handler=custom_callback, .text="CUSTOM CALLBACK" };
Copy link
Member

Choose a reason for hiding this comment

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

Here as well.

event_timeout_t event_timeout;

printf("posting timed callback with timeout 1sec\n");
event_timeout_init(&event_timeout, &queue, (event_t*)&event_callback);
Copy link
Member

Choose a reason for hiding this comment

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

s/event_t\*/event_t \*/

Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

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

Another test another nit ;-)

*
* This will remove a queued event from an event queue.
*
* @note: due to the underlying list implementation, this will run in O(n).
Copy link
Member

Choose a reason for hiding this comment

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

remove the : please. It parses weirdly in Doxygen

note with colon

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

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

I think this will be my last comment ^^"

* printf("triggered custom event with text: \"%s\"\n", custom_event->text);
* }
*
* static custom_event_t custom_event = { .super.callback=custom_handler, .text="CUSTOM EVENT" };
Copy link
Member

Choose a reason for hiding this comment

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

Here as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

* printf("triggered 0x%08x\n", (unsigned)event);
* }
*
* static event_t event = { .handler=handler };
Copy link
Member

Choose a reason for hiding this comment

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

Sorry, only noticed this during reading the parsed doc: spaces around inner =

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@kaspar030
Copy link
Contributor Author

@miri64 sorry for all the style errors.

I'm not happy about the usage of implicit sub-modules, better use explicit ones.

Hm. Using submodules saves two folders and two Makefiles. Can we merge as is and discuss whether submodules should be used out of this PR?

event_timeout work on a microsecond scale, so why are their tests on a second scale. Wastes time during testing ;-).

Good idea. Done.

@miri64
Copy link
Member

miri64 commented Nov 6, 2017

Can we merge as is and discuss whether submodules should be used out of this PR?

Begrudgingly...

@miri64
Copy link
Member

miri64 commented Nov 6, 2017

Please squash

@miri64
Copy link
Member

miri64 commented Nov 6, 2017

PR #6000 now has 666 additions. That alone is a reason against the explicit submodules, for now ^^

Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

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

ACK

@miri64
Copy link
Member

miri64 commented Nov 6, 2017

and go

@miri64 miri64 merged commit 0954dba into RIOT-OS:master Nov 6, 2017
@kaspar030 kaspar030 deleted the add_event_system branch November 6, 2017 13:26
@kaspar030
Copy link
Contributor Author

Thanks for reviewing!

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

Labels

CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants