Skip to content
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

gnrc_netif: Add support for internal event loop #13669

Merged
merged 1 commit into from
Apr 28, 2020

Conversation

bergzand
Copy link
Member

Adapted from #9326

Contribution description

From #9326:
Enabled by the gnrc_netif_events pseudo module. Using an internal event loop eliminates the risk of lost interrupts and lets ISR events always be handled before any send/receive requests from other threads are processed.
The events in the event loop is also a potential hook for MAC layers and other link layer modules which may need a way to inject and process events before any external IPC messages are handled.

Testing procedure

There is an extra commit in the PR to add the pseudomodule to examples/gnrc_networking. The example should still function as before.

Issues/PRs references

Adapted from #9326

@bergzand bergzand added Area: network Area: Networking Type: new feature The issue requests / The PR implemements a new feature for RIOT CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Mar 20, 2020
@bergzand bergzand requested review from miri64 and jia200x March 20, 2020 13:31
*/
static void _process_events_await_msg(gnrc_netif_t *netif, msg_t *msg)
{
#ifdef MODULE_GNRC_NETIF_EVENTS
Copy link
Member

Choose a reason for hiding this comment

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

I suggest to change this to a regular if-else chain (with IS_ACTIVE). Then we get compile checks for free

Copy link
Member Author

Choose a reason for hiding this comment

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

That's not possible, some members of gnrc_netif_t are only available when this module is enabled. Modifying this to IS_ACTIVE will result in compilation failures when GNRC_NETIF_EVENTS is not enabled.

Copy link
Member

Choose a reason for hiding this comment

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

you can simply define a static inline function:

static inline _get_evq(netif_t *netif)
{
#if IS_ACTIVE(MODULE_GNRC_NETIF_EVENTS)
    return netif->evq;
#else 
    return NULL;
#endif 
}

Then you call that function in the while loop.

Copy link
Member Author

Choose a reason for hiding this comment

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

This function does not compile when evq is not a member of gnrc_netif_t, which is the case when MODULE_GNRC_NETIF_EVENTS because of the ifdef guards here

Copy link
Member

Choose a reason for hiding this comment

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

This function does not compile when evq is not a member of gnrc_netif_t, which is the case when MODULE_GNRC_NETIF_EVENTS because of the ifdef guards here

Then it should still work with @jia200x's last proposal.

Copy link
Member Author

Choose a reason for hiding this comment

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

Then it should still work with @jia200x's last proposal.

Oh, of course, I misread his last suggestion.

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, while this is possible, it is starting to become more and more messy. For the solution posted by @jia200x I have to include both event.h and thread_flags.h. For thread_flags.h to be included it is required to enable MODULE_CORE_THREAD_FLAGS increasing the build size whether we're using MODULE_GNRC_NETIF_EVENTS or not.

Conditionally including event.h and thread_flags.h doesn't work because the code between the regular if-else chain (with IS_ACTIVE) requires those for one of the branches to compile.

Am I missing something silly here that allows me to get this to work or is the current #ifdef really the only way out here? I honestly don't want to start guarding every individual troublesome call in this snippet if we can avoid it.

Copy link
Member

Choose a reason for hiding this comment

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

It should be IS_USED() btw not, IS_ACTIVE(). If you use #if (not if () it should work even if you #ifdef the calls above. Let me give you some suggestions.

Copy link
Member

Choose a reason for hiding this comment

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

The root of the problem here is the #error in thread_flags header. It's misplaced IMO. It should be in the C file that defines the thread flags function.

I can open a PR to move it (unless you are faster :), it should be a low hanging fruit.

Copy link
Member

Choose a reason for hiding this comment

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

It's there: #13671

And @miri64 is right. It should be IS_USED for modules

@jia200x
Copy link
Member

jia200x commented Mar 20, 2020

codewise looks fine, just some minor comments above

*/
static void _process_events_await_msg(gnrc_netif_t *netif, msg_t *msg)
{
#ifdef MODULE_GNRC_NETIF_EVENTS
Copy link
Member

Choose a reason for hiding this comment

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

It should be IS_USED() btw not, IS_ACTIVE(). If you use #if (not if () it should work even if you #ifdef the calls above. Let me give you some suggestions.

sys/include/net/gnrc/netif.h Outdated Show resolved Hide resolved
sys/include/net/gnrc/netif.h Outdated Show resolved Hide resolved
sys/net/gnrc/netif/gnrc_netif.c Outdated Show resolved Hide resolved
sys/net/gnrc/netif/gnrc_netif.c Outdated Show resolved Hide resolved
sys/net/gnrc/netif/gnrc_netif.c Outdated Show resolved Hide resolved
sys/net/gnrc/netif/gnrc_netif.c Outdated Show resolved Hide resolved
@bergzand
Copy link
Member Author

bergzand commented Apr 1, 2020

Reworked, comments should be addressed with this.

@jia200x
Copy link
Member

jia200x commented Apr 1, 2020

Great! I will give it a deeper look in a few hours

miri64
miri64 previously requested changes Apr 1, 2020
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.

One minor thing ;-)

sys/net/gnrc/netif/gnrc_netif.c Outdated Show resolved Hide resolved
*/
static void _event_handler_isr(event_t *evp)
{
(void)evp;
Copy link
Member

Choose a reason for hiding this comment

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

Why this? evp is used just in the line below.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, leftover from shuffling around the #ifdefs, will remove

@miri64
Copy link
Member

miri64 commented Apr 1, 2020

This compiles for me and would result in less #ifdef hell:

diff --git a/sys/net/gnrc/netif/gnrc_netif.c b/sys/net/gnrc/netif/gnrc_netif.c
index 34f7c5f5c..ad62a6ac1 100644
--- a/sys/net/gnrc/netif/gnrc_netif.c
+++ b/sys/net/gnrc/netif/gnrc_netif.c
@@ -1359,7 +1359,6 @@ void gnrc_netif_default_init(gnrc_netif_t *netif)
 #endif
 }
 
-#if IS_USED(MODULE_GNRC_NETIF_EVENTS)
 /**
  * @brief   Call the ISR handler from an event
  *
@@ -1367,11 +1366,13 @@ void gnrc_netif_default_init(gnrc_netif_t *netif)
  */
 static void _event_handler_isr(event_t *evp)
 {
-    (void)evp;
+#if IS_USED(MODULE_GNRC_NETIF_EVENTS)
     gnrc_netif_t *netif = container_of(evp, gnrc_netif_t, event_isr);
     netif->dev->driver->isr(netif->dev);
-}
+#else
+    (void)evp;
 #endif
+}
 
 /**
  * @brief   Retrieve the netif event queue if enabled
@@ -1452,11 +1453,11 @@ static void *_gnrc_netif_thread(void *args)
     gnrc_netif_acquire(netif);
     dev = netif->dev;
     netif->pid = sched_active_pid;
-#if IS_USED(MODULE_GNRC_NETIF_EVENTS)
-    netif->event_isr.handler = _event_handler_isr,
-    /* set up the event queue */
-    event_queue_init(&netif->evq);
-#endif /* MODULE_GNRC_NETIF_EVENTS */
+    if (IS_USED(MODULE_GNRC_NETIF_EVENTS)) {
+        netif->event_isr.handler = _event_handler_isr,
+        /* set up the event queue */
+        event_queue_init(&netif->evq);
+    }
     /* setup the link-layer's message queue */
     msg_init_queue(msg_queue, CONFIG_GNRC_NETIF_MSG_QUEUE_SIZE);
     /* register the event callback with the device driver */

@bergzand
Copy link
Member Author

bergzand commented Apr 1, 2020

This compiles for me and would result in less #ifdef hell:

This doesn't compile for me if I don't compile with gnrc_netif_events included 😢

@miri64
Copy link
Member

miri64 commented Apr 1, 2020

This compiles for me and would result in less #ifdef hell:

This doesn't compile for me if I don't compile with gnrc_netif_events included 😢

I might have forgotten, that gnrc_networking includes that module now 😅

@miri64 miri64 dismissed their stale review April 1, 2020 13:45

Change request was addressed

@jia200x
Copy link
Member

jia200x commented Apr 1, 2020

Tested on samr21-xpro. The gnrc_networking example works OK with and without the gnrc_netif_events module.


DEBUG("gnrc_netif: starting thread %i\n", sched_active_pid);
netif = args;
gnrc_netif_acquire(netif);
dev = netif->dev;
netif->pid = sched_active_pid;
#if IS_USED(MODULE_GNRC_NETIF_EVENTS)
Copy link
Member

Choose a reason for hiding this comment

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

Just nitpick comment, this could be moved to it's own function (e.g gnrc_netif_events_init()). Then you remove the #ifdef

Copy link
Member Author

Choose a reason for hiding this comment

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

That's just shuffling around #ifdef's right? Instead of the #ifdef in the init function they are moved to the new function. Do you think this makes the code more readable?

Copy link
Member

Choose a reason for hiding this comment

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

I mean:

if (IS_USED(MODULE_GNRC_NETIF_EVENTS)) {
    gnrc_netif_events_init();
}

Might be a matter of personal taste here, so I'm OK with what you decide. But in the other comment the msg_t logic is guarded

Copy link
Member Author

Choose a reason for hiding this comment

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

I prefer to leave this as is for now, it keeps the initialization code in one place as much as possible and I don't think the ifdef decreases readability much in this case.

Copy link
Member

Choose a reason for hiding this comment

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

ok! np

@@ -1487,12 +1585,16 @@ static void _event_cb(netdev_t *dev, netdev_event_t event)
gnrc_netif_t *netif = (gnrc_netif_t *) dev->context;

if (event == NETDEV_EVENT_ISR) {
#if IS_USED(MODULE_GNRC_NETIF_EVENTS)
Copy link
Member

Choose a reason for hiding this comment

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

Same here. What speaks againts:

static inline gnrc_netif_events_post(gnrc_netif_t *netif)
{
#if IS_USED(GNRC_NETIF_EVENTS)
    event_post(&netif->evq, &netif->event_isr);
#else
    (void) netif;
#endif
}

?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nothing, implemented this in the latest fixup

@jia200x
Copy link
Member

jia200x commented Apr 15, 2020

please squash

Enabled by the gnrc_netif_events pseudo module. Using an internal event
loop within the gnrc_netif thread eliminates the risk of lost interrupts
and lets ISR events always be handled before any send/receive requests
from other threads are processed.
The events in the event loop is also a potential hook for MAC layers and
other link layer modules which may need to inject and process events
before any external IPC messages are handled.

Co-Authored-By: Koen Zandberg <[email protected]>
@bergzand
Copy link
Member Author

Squashed!

I've also removed the "REMOVEME" commit that added the event module to gnrc_networking.

@bergzand
Copy link
Member Author

@jia200x Ping!

Copy link
Member

@jia200x jia200x left a comment

Choose a reason for hiding this comment

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

Ok, it looks good to me! ACK

@miri64 miri64 merged commit 633d0f4 into RIOT-OS:master Apr 28, 2020
@miri64 miri64 added this to the Release 2020.07 milestone Jun 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: network Area: Networking 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.

3 participants