Skip to content

Commit

Permalink
gnrc_netif: Add support for internal event loop
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Joakim Nohlgård committed Aug 24, 2018
1 parent bc667ec commit 9980882
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 50 deletions.
5 changes: 5 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ ifneq (,$(filter gnrc_netif,$(USEMODULE)))
USEMODULE += netif
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 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 event instance table
*
* This pointer gives a way to allocate 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 *events;
#endif /* MODULE_GNRC_NETIF_EVENTS */
#if (GNRC_NETIF_L2ADDR_MAXLEN > 0)
/**
* @brief The link-layer address currently used as the source address
Expand Down
173 changes: 123 additions & 50 deletions sys/net/gnrc/netif/gnrc_netif.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@

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

typedef struct {
event_netdev_t isr;
} gnrc_netif_events_t;
#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 @@ -1271,6 +1285,19 @@ 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 */

static void *_gnrc_netif_thread(void *args)
{
gnrc_netapi_opt_t *opt;
Expand All @@ -1285,6 +1312,17 @@ static void *_gnrc_netif_thread(void *args)
gnrc_netif_acquire(netif);
dev = netif->dev;
netif->pid = sched_active_pid;
#ifdef MODULE_GNRC_NETIF_EVENTS
gnrc_netif_events_t event_table = {
.isr = {
.super = { .handler = _event_handler_isr, },
.dev = dev,
},
};
netif->events = &event_table;
/* 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 All @@ -1305,63 +1343,93 @@ static void *_gnrc_netif_thread(void *args)
gnrc_netif_release(netif);

while (1) {
DEBUG("gnrc_netif: waiting for incoming messages\n");
msg_receive(&msg);
/* dispatch netdev, MAC and gnrc_netapi messages */
switch (msg.type) {
case NETDEV_MSG_TYPE_EVENT:
DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_EVENT received\n");
dev->driver->isr(dev);
break;
case GNRC_NETAPI_MSG_TYPE_SND:
DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_SND received\n");
res = netif->ops->send(netif, msg.content.ptr);
if (res < 0) {
DEBUG("gnrc_netif: error sending packet %p (code: %u)\n",
msg.content.ptr, res);
int msg_waiting = 0;
#ifdef MODULE_GNRC_NETIF_EVENTS
/* Using messages for external IPC, and events for internal events */
DEBUG("gnrc_netif: waiting for events\n");
/* We can not use event_loop() or event_wait() because then we would not
* wake up when a message arrives */
thread_flags_t flags = thread_flags_wait_any(
THREAD_FLAG_MSG_WAITING | THREAD_FLAG_EVENT);
/* Events will be handled before messages */
if (flags & THREAD_FLAG_EVENT) {
DEBUG("gnrc_netif: handling events\n");
event_t *evp;
while ((evp = event_get(&netif->evq))) {
DEBUG("gnrc_netif: event %p\n", (void *)evp);
if (evp->handler) {
evp->handler(evp);
}
break;
case GNRC_NETAPI_MSG_TYPE_SET:
opt = msg.content.ptr;
}
}
if (flags & THREAD_FLAG_MSG_WAITING) {
/* non-blocking msg check */
msg_waiting = msg_try_receive(&msg);
}
#else /* MODULE_GNRC_NETIF_EVENTS */
/* Only messages used for event handling */
DEBUG("gnrc_netif: waiting for incoming messages\n");
msg_waiting = msg_receive(&msg);
#endif /* MODULE_GNRC_NETIF_EVENTS */
while (msg_waiting > 0) {
/* dispatch netdev, MAC and gnrc_netapi messages */
DEBUG("gnrc_netif: message %u\n", (unsigned)msg.type);
switch (msg.type) {
case NETDEV_MSG_TYPE_EVENT:
DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_EVENT received\n");
dev->driver->isr(dev);
break;
case GNRC_NETAPI_MSG_TYPE_SND:
DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_SND received\n");
res = netif->ops->send(netif, msg.content.ptr);
if (res < 0) {
DEBUG("gnrc_netif: error sending packet %p (code: %u)\n",
msg.content.ptr, res);
}
break;
case GNRC_NETAPI_MSG_TYPE_SET:
opt = msg.content.ptr;
#ifdef MODULE_NETOPT
DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_SET received. opt=%s\n",
netopt2str(opt->opt));
DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_SET received. opt=%s\n",
netopt2str(opt->opt));
#else
DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_SET received. opt=%d\n",
opt->opt);
DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_SET received. opt=%d\n",
opt->opt);
#endif
/* set option for device driver */
res = netif->ops->set(netif, opt);
DEBUG("gnrc_netif: response of netif->ops->set(): %i\n", res);
reply.content.value = (uint32_t)res;
msg_reply(&msg, &reply);
break;
case GNRC_NETAPI_MSG_TYPE_GET:
opt = msg.content.ptr;
/* set option for device driver */
res = netif->ops->set(netif, opt);
DEBUG("gnrc_netif: response of netif->ops->set(): %i\n", res);
reply.content.value = (uint32_t)res;
msg_reply(&msg, &reply);
break;
case GNRC_NETAPI_MSG_TYPE_GET:
opt = msg.content.ptr;
#ifdef MODULE_NETOPT
DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_GET received. opt=%s\n",
netopt2str(opt->opt));
DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_GET received. opt=%s\n",
netopt2str(opt->opt));
#else
DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_GET received. opt=%d\n",
opt->opt);
DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_GET received. opt=%d\n",
opt->opt);
#endif
/* get option from device driver */
res = netif->ops->get(netif, opt);
DEBUG("gnrc_netif: response of netif->ops->get(): %i\n", res);
reply.content.value = (uint32_t)res;
msg_reply(&msg, &reply);
break;
default:
if (netif->ops->msg_handler) {
DEBUG("gnrc_netif: delegate message of type 0x%04x to "
"netif->ops->msg_handler()\n", msg.type);
netif->ops->msg_handler(netif, &msg);
}
else {
DEBUG("gnrc_netif: unknown message type 0x%04x"
"(no message handler defined)\n", msg.type);
}
break;
/* get option from device driver */
res = netif->ops->get(netif, opt);
DEBUG("gnrc_netif: response of netif->ops->get(): %i\n", res);
reply.content.value = (uint32_t)res;
msg_reply(&msg, &reply);
break;
default:
if (netif->ops->msg_handler) {
DEBUG("gnrc_netif: delegate message of type 0x%04x to "
"netif->ops->msg_handler()\n", msg.type);
netif->ops->msg_handler(netif, &msg);
}
else {
DEBUG("gnrc_netif: unknown message type 0x%04x"
"(no message handler defined)\n", msg.type);
}
break;
}
msg_waiting = msg_try_receive(&msg);
}
}
/* never reached */
Expand All @@ -1383,12 +1451,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
gnrc_netif_events_t *etp = netif->events;
event_post(&netif->evq, &etp->isr.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

0 comments on commit 9980882

Please sign in to comment.