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 #9326

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ ifneq (,$(filter gnrc_netif,$(USEMODULE)))
USEMODULE += fmt
endif

ifneq (,$(filter gnrc_netif_events,$(USEMODULE)))
USEMODULE += core_thread_flags
USEMODULE += event
endif

ifneq (,$(filter ieee802154 nrfmin,$(USEMODULE)))
ifneq (,$(filter gnrc_ipv6, $(USEMODULE)))
USEMODULE += gnrc_sixlowpan
Expand Down
1 change: 1 addition & 0 deletions examples/gnrc_networking/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ USEMODULE += ps
USEMODULE += netstats_l2
USEMODULE += netstats_ipv6
USEMODULE += netstats_rpl
USEMODULE += gnrc_netif_events

# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
Expand Down
1 change: 1 addition & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ PSEUDOMODULES += gnrc_netdev_default
PSEUDOMODULES += gnrc_neterr
PSEUDOMODULES += gnrc_netapi_callbacks
PSEUDOMODULES += gnrc_netapi_mbox
PSEUDOMODULES += gnrc_netif_events
PSEUDOMODULES += gnrc_pktbuf_cmd
PSEUDOMODULES += gnrc_sixlowpan_border_router_default
PSEUDOMODULES += gnrc_sixlowpan_default
Expand Down
19 changes: 19 additions & 0 deletions sys/include/net/gnrc/netif.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@

#include "kernel_types.h"
#include "msg.h"
#ifdef MODULE_GNRC_NETIF_EVENTS
#include "event.h"
#endif /* MODULE_GNRC_NETIF_EVENTS */
#include "net/ipv6/addr.h"
#include "net/gnrc/netapi.h"
#include "net/gnrc/pkt.h"
Expand Down Expand Up @@ -75,6 +78,22 @@ typedef struct {
* @see net_gnrc_netif_flags
*/
uint32_t flags;
#if defined(MODULE_GNRC_NETIF_EVENTS) || DOXYGEN
/**
* @brief Event queue for asynchronous events
*/
event_queue_t evq;
/**
* @brief Pointer to ISR event
*
* This pointer gives a way to allocate ISR events on the stack of each
* gnrc_netif thread, instead of having a single global instance which will
* not work if the system has more than one network interface.
* The _event_cb function of gnrc_netif.c uses this pointer to be able to
* post events from interrupt context.
*/
void *event_isr; /* void * to keep implementation details private to gnrc_netif.c */
#endif /* MODULE_GNRC_NETIF_EVENTS */
#if (GNRC_NETIF_L2ADDR_MAXLEN > 0)
/**
* @brief The link-layer address currently used as the source address
Expand Down
93 changes: 90 additions & 3 deletions sys/net/gnrc/netif/gnrc_netif.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@

#define _NETIF_NETAPI_MSG_QUEUE_SIZE (8)

#ifdef MODULE_GNRC_NETIF_EVENTS
/**
* @brief Event type used for passing netdev pointers together with the event
*/
typedef struct {
event_t super;
netdev_t *dev;
} event_netdev_t;
Copy link
Member

Choose a reason for hiding this comment

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

If you don't want to make this type public, I'd prefer to prefix it with _ to make the usage code easier to follow.

#endif /* MODULE_GNRC_NETIF_EVENTS */

static gnrc_netif_t _netifs[GNRC_NETIF_NUMOF];

static void _update_l2addr_from_dev(gnrc_netif_t *netif);
Expand Down Expand Up @@ -1295,20 +1305,88 @@ static void _configure_netdev(netdev_t *dev)
#endif
}

#ifdef MODULE_GNRC_NETIF_EVENTS
/**
* @brief Call the ISR handler from an event
*
* @param[in] evp pointer to the event
*/
static void _event_handler_isr(event_t *evp)
{
netdev_t *dev = ((event_netdev_t*)evp)->dev;
dev->driver->isr(dev);
}
#endif /* MODULE_GNRC_NETIF_EVENTS */

/**
* @brief Process any pending events and wait for IPC messages
*
* This function will block until an IPC message is received. Events posted to
* the event queue will be processed while waiting for messages.
*
* @param[in] netif gnrc_netif instance to operate on
* @param[out] msg pointer to message buffer to write the first received message
*
* @return >0 if msg contains a new message
*/
static void _process_events_await_msg(gnrc_netif_t *netif, msg_t *msg)
{
#ifdef MODULE_GNRC_NETIF_EVENTS
while (1) {
/* Using messages for external IPC, and events for internal events */

/* First drain the queues before blocking the thread */
/* Events will be handled before messages */
DEBUG("gnrc_netif: handling events\n");
event_t *evp;
/* We can not use event_loop() or event_wait() because then we would not
* wake up when a message arrives */
while ((evp = event_get(&netif->evq))) {
DEBUG("gnrc_netif: event %p\n", (void *)evp);
if (evp->handler) {
evp->handler(evp);
}
}
/* non-blocking msg check */
int msg_waiting = msg_try_receive(msg);
if (msg_waiting > 0) {
return;
}
DEBUG("gnrc_netif: waiting for events\n");
/* Block the thread until something interesting happens */
thread_flags_wait_any(THREAD_FLAG_MSG_WAITING | THREAD_FLAG_EVENT);
}
#else /* MODULE_GNRC_NETIF_EVENTS */
(void) netif;
/* Only messages used for event handling */
DEBUG("gnrc_netif: waiting for incoming messages\n");
msg_receive(msg);
#endif /* MODULE_GNRC_NETIF_EVENTS */
}

static void *_gnrc_netif_thread(void *args)
{
gnrc_netapi_opt_t *opt;
gnrc_netif_t *netif;
netdev_t *dev;
int res;
msg_t reply = { .type = GNRC_NETAPI_MSG_TYPE_ACK };
msg_t msg, msg_queue[_NETIF_NETAPI_MSG_QUEUE_SIZE];
msg_t msg_queue[_NETIF_NETAPI_MSG_QUEUE_SIZE];

DEBUG("gnrc_netif: starting thread %i\n", sched_active_pid);
netif = args;
gnrc_netif_acquire(netif);
dev = netif->dev;
netif->pid = sched_active_pid;
#ifdef MODULE_GNRC_NETIF_EVENTS
event_netdev_t ev_isr = {
.super = { .handler = _event_handler_isr, },
.dev = dev,
};
netif->event_isr = &ev_isr;
/* set up the event queue */
event_queue_init(&netif->evq);
#endif /* MODULE_GNRC_NETIF_EVENTS */
/* setup the link-layer's message queue */
msg_init_queue(msg_queue, _NETIF_NETAPI_MSG_QUEUE_SIZE);
/* register the event callback with the device driver */
Expand Down Expand Up @@ -1339,9 +1417,13 @@ static void *_gnrc_netif_thread(void *args)
gnrc_netif_release(netif);

while (1) {
DEBUG("gnrc_netif: waiting for incoming messages\n");
msg_receive(&msg);
msg_t msg;
/* msg will be filled by _process_events_await_msg.
* The function will not return until a message has been received. */
_process_events_await_msg(netif, &msg);

/* dispatch netdev, MAC and gnrc_netapi messages */
DEBUG("gnrc_netif: message %u\n", (unsigned)msg.type);
switch (msg.type) {
case NETDEV_MSG_TYPE_EVENT:
Copy link
Member

Choose a reason for hiding this comment

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

I believe this case can be #ifndef'd

DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_EVENT received\n");
Expand Down Expand Up @@ -1417,12 +1499,17 @@ 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) {
#ifdef MODULE_GNRC_NETIF_EVENTS
event_netdev_t *etp = netif->event_isr;
event_post(&netif->evq, &etp->super);
#else /* MODULE_GNRC_NETIF_EVENTS */
msg_t msg = { .type = NETDEV_MSG_TYPE_EVENT,
.content = { .ptr = netif } };

if (msg_send(&msg, netif->pid) <= 0) {
puts("gnrc_netif: possibly lost interrupt.");
}
#endif /* MODULE_GNRC_NETIF_EVENTS */
}
else {
DEBUG("gnrc_netif: event triggered -> %i\n", event);
Expand Down