1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #5526 from miri64/gnrc_netreg/api/mbox-extension

gnrc_netreg: mbox and arbitrary callback support
This commit is contained in:
Cenk Gündoğan 2016-10-25 22:59:46 +02:00 committed by GitHub
commit a74f429fc5
12 changed files with 268 additions and 17 deletions

View File

@ -57,6 +57,10 @@ ifneq (,$(filter gnrc_conn_udp,$(USEMODULE)))
USEMODULE += gnrc_udp
endif
ifneq (,$(filter gnrc_netapi_mbox,$(USEMODULE)))
USEMODULE += core_mbox
endif
ifneq (,$(filter netdev2_tap,$(USEMODULE)))
USEMODULE += netif
USEMODULE += netdev2_eth

View File

@ -12,6 +12,8 @@ PSEUDOMODULES += gnrc_ipv6_router
PSEUDOMODULES += gnrc_ipv6_router_default
PSEUDOMODULES += gnrc_netdev_default
PSEUDOMODULES += gnrc_neterr
PSEUDOMODULES += gnrc_netapi_callbacks
PSEUDOMODULES += gnrc_netapi_mbox
PSEUDOMODULES += gnrc_pktbuf
PSEUDOMODULES += gnrc_sixlowpan_border_router_default
PSEUDOMODULES += gnrc_sixlowpan_default

View File

@ -94,7 +94,7 @@ static void start_server(char *port_str)
uint16_t port;
/* check if server is already running */
if (server.pid != KERNEL_PID_UNDEF) {
if (server.target.pid != KERNEL_PID_UNDEF) {
printf("Error: server already running on port %" PRIu32 "\n",
server.demux_ctx);
return;
@ -106,7 +106,7 @@ static void start_server(char *port_str)
return;
}
/* start server (which means registering pktdump for the chosen port) */
server.pid = gnrc_pktdump_pid;
server.target.pid = gnrc_pktdump_pid;
server.demux_ctx = (uint32_t)port;
gnrc_netreg_register(GNRC_NETTYPE_UDP, &server);
printf("Success: started UDP server on port %" PRIu16 "\n", port);
@ -115,13 +115,13 @@ static void start_server(char *port_str)
static void stop_server(void)
{
/* check if server is running at all */
if (server.pid == KERNEL_PID_UNDEF) {
if (server.target.pid == KERNEL_PID_UNDEF) {
printf("Error: server was not running\n");
return;
}
/* stop server */
gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &server);
server.pid = KERNEL_PID_UNDEF;
server.target.pid = KERNEL_PID_UNDEF;
puts("Success: stopped UDP server");
}

View File

@ -21,6 +21,36 @@
* @file
* @brief Generic interface to communicate with GNRC modules
*
* @defgroup net_gnrc_netapi_mbox Mailbox IPC extension
* @ingroup net_gnrc_netapi
* @brief @ref core_mbox "Mailbox IPC" extension for @ref net_gnrc_netapi
* @{
*
* @details The submodule `gnrc_netapi_mbox` provides an extension for
* @ref core_mbox "Mailbox IPC".
*
* To use, add the module `gnrc_netapi_mbox` to the `USEMODULE` macro in your
* application's Makefile:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk}
* USEMODULE += gnrc_netapi_mbox
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* @}
*
* @defgroup net_gnrc_netapi_callbacks Callback extension
* @ingroup net_gnrc_netapi
* @brief Callback extension for @ref net_gnrc_netapi
* @{
* @details The submodule `gnrc_netapi_callbacks` provides an extension for
* callbacks to run GNRC thread-less.
*
* To use, add the module `gnrc_netapi_callbacks` to the `USEMODULE` macro in
* your application's Makefile:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk}
* USEMODULE += gnrc_netapi_callbacks
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* @}
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/

View File

@ -27,10 +27,27 @@
#include "net/gnrc/nettype.h"
#include "net/gnrc/pkt.h"
#ifdef MODULE_GNRC_NETAPI_MBOX
#include "mbox.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS) || \
defined(DOXYGEN)
typedef enum {
GNRC_NETREG_TYPE_DEFAULT = 0,
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(DOXYGEN)
GNRC_NETREG_TYPE_MBOX,
#endif
#if defined(MODULE_GNRC_NETAPI_CALLBACKS) || defined(DOXYGEN)
GNRC_NETREG_TYPE_CB,
#endif
} gnrc_netreg_type_t;
#endif
/**
* @brief Demux context value to get all packets of a certain type.
*
@ -47,7 +64,72 @@ extern "C" {
*
* @return An initialized netreg entry
*/
#define GNRC_NETREG_ENTRY_INIT_PID(demux_ctx, pid) { NULL, demux_ctx, pid }
#ifdef MODULE_GNRC_NETAPI_MBOX
#define GNRC_NETREG_ENTRY_INIT_PID(demux_ctx, pid) { NULL, demux_ctx, \
GNRC_NETREG_TYPE_DEFAULT, \
{ pid } }
#else
#define GNRC_NETREG_ENTRY_INIT_PID(demux_ctx, pid) { NULL, demux_ctx, { pid } }
#endif
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(DOXYGEN)
/**
* @brief Initializes a netreg entry statically with mbox
*
* @param[in] demux_ctx The @ref gnrc_netreg_entry_t::demux_ctx "demux context"
* for the netreg entry
* @param[in] mbox Target @ref core_mbox "mailbox" for the registry entry
*
* @note Only available with @ref net_gnrc_netapi_mbox.
*
* @return An initialized netreg entry
*/
#define GNRC_NETREG_ENTRY_INIT_MBOX(demux_ctx, mbox) { NULL, demux_ctx, \
GNRC_NETREG_TYPE_MBOX, \
{ .mbox = mbox } }
#endif
#if defined(MODULE_GNRC_NETAPI_CALLBACKS) || defined(DOXYGEN)
/**
* @brief Initializes a netreg entry statically with callback
*
* @param[in] demux_ctx The @ref gnrc_netreg_entry_t::demux_ctx "demux context"
* for the netreg entry
* @param[in] cb Target callback for the registry entry
*
* @note Only available with @ref net_gnrc_netapi_callbacks.
*
* @return An initialized netreg entry
*/
#define GNRC_NETREG_ENTRY_INIT_CB(demux_ctx, cbd) { NULL, demux_ctx, \
GNRC_NETREG_TYPE_CB, \
{ .cbd = cbd } }
/**
* @brief Packet handler callback for netreg entries with callback.
*
* @pre `cmd` $\in$ { @ref GNRC_NETAPI_MSG_TYPE_RCV, @ref GNRC_NETAPI_MSG_TYPE_SND }
*
* @note Only available with @ref net_gnrc_netapi_callbacks.
*
* @param[in] cmd @ref net_gnrc_netapi command type. Must be either
* @ref GNRC_NETAPI_MSG_TYPE_SND or
* @ref GNRC_NETAPI_MSG_TYPE_RCV
* @param[in] pkt The packet to handle.
* @param[in] ctx Application context.
*/
typedef void (*gnrc_netreg_entry_cb_t)(uint16_t cmd, gnrc_pktsnip_t *pkt,
void *ctx);
/**
* @brief Callback + Context descriptor
* @note Only available with @ref net_gnrc_netapi_callbacks.
*/
typedef struct {
gnrc_netreg_entry_cb_t cb; /**< the callback */
void *ctx; /**< application context for the callback */
} gnrc_netreg_entry_cbd_t;
#endif
/**
* @brief Entry to the @ref net_gnrc_netreg
@ -68,7 +150,36 @@ typedef struct gnrc_netreg_entry {
* ports in UDP/TCP, or similar.
*/
uint32_t demux_ctx;
kernel_pid_t pid; /**< The PID of the registering thread */
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS) || \
defined(DOXYGEN)
/**
* @brief Type of the registry entry
*
* @note Only available with @ref net_gnrc_netapi_mbox or
* @ref net_gnrc_netapi_callbacks.
*/
gnrc_netreg_type_t type;
#endif
union {
kernel_pid_t pid; /**< The PID of the registering thread */
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(DOXYGEN)
/**
* @brief Target @ref core_mbox "mailbox" for the registry entry
*
* @note Only available with @ref net_gnrc_netapi_mbox.
*/
mbox_t *mbox;
#endif
#if defined(MODULE_GNRC_NETAPI_CALLBACKS) || defined(DOXYGEN)
/**
* @brief Target callback for the registry entry
*
* @note Only available with @ref net_gnrc_netapi_callbacks.
*/
gnrc_netreg_entry_cbd_t *cbd;
#endif
} target; /**< Target for the registry entry */
} gnrc_netreg_entry_t;
/**
@ -91,9 +202,56 @@ static inline void gnrc_netreg_entry_init_pid(gnrc_netreg_entry_t *entry,
{
entry->next = NULL;
entry->demux_ctx = demux_ctx;
entry->pid = pid;
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS)
entry->type = GNRC_NETREG_TYPE_DEFAULT;
#endif
entry->target.pid = pid;
}
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(DOXYGEN)
/**
* @brief Initializes a netreg entry dynamically with mbox
*
* @param[out] entry A netreg entry
* @param[in] demux_ctx The @ref gnrc_netreg_entry_t::demux_ctx "demux context"
* for the netreg entry
* @param[in] mbox Target @ref core_mbox "mailbox" for the registry entry
*
* @note Only available with @ref net_gnrc_netapi_mbox.
*/
static inline void gnrc_netreg_entry_init_mbox(gnrc_netreg_entry_t *entry,
uint32_t demux_ctx,
mbox_t *mbox)
{
entry->next = NULL;
entry->demux_ctx = demux_ctx;
entry->type = GNRC_NETREG_TYPE_MBOX;
entry->target.mbox = mbox;
}
#endif
#if defined(MODULE_GNRC_NETAPI_CALLBACKS) || defined(DOXYGEN)
/**
* @brief Initializes a netreg entry dynamically with callback
*
* @param[out] entry A netreg entry
* @param[in] demux_ctx The @ref gnrc_netreg_entry_t::demux_ctx "demux context"
* for the netreg entry
* @param[in] mbox Target callback for the registry entry
*
* @note Only available with @ref net_gnrc_netapi_callbacks.
*/
static inline void gnrc_netreg_entry_init_cb(gnrc_netreg_entry_t *entry,
uint32_t demux_ctx,
gnrc_netreg_entry_cbd_t *cbd)
{
entry->next = NULL;
entry->demux_ctx = demux_ctx;
entry->type = GNRC_NETREG_TYPE_CB;
entry->target.cbd = cbd;
}
#endif
/**
* @brief Registers a thread to the registry.
*

View File

@ -52,7 +52,7 @@ int conn_ip_create(conn_ip_t *conn, const void *addr, size_t addr_len, int famil
void conn_ip_close(conn_ip_t *conn)
{
assert(conn->l4_type == GNRC_NETTYPE_UNDEF);
if (conn->netreg_entry.pid != KERNEL_PID_UNDEF) {
if (conn->netreg_entry.target.pid != KERNEL_PID_UNDEF) {
gnrc_netreg_unregister(conn->l3_type, &conn->netreg_entry);
}
}

View File

@ -56,9 +56,9 @@ int conn_udp_create(conn_udp_t *conn, const void *addr, size_t addr_len,
void conn_udp_close(conn_udp_t *conn)
{
assert(conn->l4_type == GNRC_NETTYPE_UDP);
if (conn->netreg_entry.pid != KERNEL_PID_UNDEF) {
if (conn->netreg_entry.target.pid != KERNEL_PID_UNDEF) {
gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &conn->netreg_entry);
conn->netreg_entry.pid = KERNEL_PID_UNDEF;
conn->netreg_entry.target.pid = KERNEL_PID_UNDEF;
}
}

View File

@ -18,6 +18,7 @@
* @}
*/
#include "mbox.h"
#include "msg.h"
#include "net/gnrc/netreg.h"
#include "net/gnrc/pktbuf.h"
@ -74,6 +75,22 @@ static inline int _snd_rcv(kernel_pid_t pid, uint16_t type, gnrc_pktsnip_t *pkt)
return ret;
}
#ifdef MODULE_GNRC_NETAPI_MBOX
static inline int _snd_rcv_mbox(mbox_t *mbox, uint16_t type, gnrc_pktsnip_t *pkt)
{
msg_t msg;
/* set the outgoing message's fields */
msg.type = type;
msg.content.ptr = (void *)pkt;
/* send message */
int ret = mbox_try_put(mbox, &msg);
if (ret < 1) {
DEBUG("gnrc_netapi: dropped message to %p (was full)\n", mbox);
}
return ret;
}
#endif
int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx,
uint16_t cmd, gnrc_pktsnip_t *pkt)
{
@ -85,10 +102,42 @@ int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx,
gnrc_pktbuf_hold(pkt, numof - 1);
while (sendto) {
if (_snd_rcv(sendto->pid, cmd, pkt) < 1) {
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS)
int release = 0;
switch (sendto->type) {
case GNRC_NETREG_TYPE_DEFAULT:
if (_snd_rcv(sendto->target.pid, cmd, pkt) < 1) {
/* unable to dispatch packet */
release = 1;
}
break;
#ifdef MODULE_GNRC_NETAPI_MBOX
case GNRC_NETREG_TYPE_MBOX:
if (_snd_rcv_mbox(sendto->target.mbox, cmd, pkt) < 1) {
/* unable to dispatch packet */
release = 1;
}
break;
#endif
#ifdef MODULE_GNRC_NETAPI_CALLBACKS
case GNRC_NETREG_TYPE_CB:
sendto->target.cbd->cb(cmd, pkt, sendto->target.cbd->ctx);
break;
#endif
default:
/* unknown dispatch type */
release = 1;
break;
}
if (release) {
gnrc_pktbuf_release(pkt);
}
#else
if (_snd_rcv(sendto->target.pid, cmd, pkt) < 1) {
/* unable to dispatch packet */
gnrc_pktbuf_release(pkt);
}
#endif
sendto = gnrc_netreg_getnext(sendto);
}
}

View File

@ -37,8 +37,16 @@ void gnrc_netreg_init(void)
int gnrc_netreg_register(gnrc_nettype_t type, gnrc_netreg_entry_t *entry)
{
#if defined(MODULE_GNRC_NETAPI_MBOX) || defined(MODULE_GNRC_NETAPI_CALLBACKS)
#ifdef DEVELHELP
/* only threads with a message queue are allowed to register at gnrc */
assert(sched_threads[entry->pid]->msg_array);
assert((entry->type != GNRC_NETREG_TYPE_DEFAULT) ||
sched_threads[entry->target.pid]->msg_array);
#endif
#else
/* only threads with a message queue are allowed to register at gnrc */
assert(sched_threads[entry->target.pid]->msg_array);
#endif
if (_INVALID_TYPE(type)) {
return -EINVAL;

View File

@ -68,7 +68,7 @@ kernel_pid_t gnrc_rpl_init(kernel_pid_t if_pid)
}
_me_reg.demux_ctx = ICMPV6_RPL_CTRL;
_me_reg.pid = gnrc_rpl_pid;
_me_reg.target.pid = gnrc_rpl_pid;
/* register interest in all ICMPv6 packets */
gnrc_netreg_register(GNRC_NETTYPE_ICMPV6, &_me_reg);

View File

@ -36,7 +36,7 @@ int main(void)
puts("SLIP test");
/* register pktdump */
if (dump.pid <= KERNEL_PID_UNDEF) {
if (dump.target.pid <= KERNEL_PID_UNDEF) {
puts("Error starting pktdump thread");
return -1;
}

View File

@ -45,7 +45,7 @@ static void test_netreg_register__success(void)
TEST_ASSERT_EQUAL_INT(0, gnrc_netreg_register(GNRC_NETTYPE_TEST, &entries[0]));
TEST_ASSERT_NOT_NULL((res = gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16)));
TEST_ASSERT_EQUAL_INT(TEST_UINT16, res->demux_ctx);
TEST_ASSERT_EQUAL_INT(TEST_UINT8, res->pid);
TEST_ASSERT_EQUAL_INT(TEST_UINT8, res->target.pid);
TEST_ASSERT_NULL((gnrc_netreg_getnext(res)));
}
@ -66,7 +66,7 @@ void test_netreg_unregister__success2(void)
gnrc_netreg_unregister(GNRC_NETTYPE_TEST, &entries[0]);
TEST_ASSERT_NOT_NULL((res = gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16)));
TEST_ASSERT_EQUAL_INT(TEST_UINT16, res->demux_ctx);
TEST_ASSERT_EQUAL_INT(TEST_UINT8 + 1, res->pid);
TEST_ASSERT_EQUAL_INT(TEST_UINT8 + 1, res->target.pid);
gnrc_netreg_unregister(GNRC_NETTYPE_TEST, &entries[1]);
TEST_ASSERT_NULL(gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16));
}
@ -80,7 +80,7 @@ void test_netreg_unregister__success3(void)
gnrc_netreg_unregister(GNRC_NETTYPE_TEST, &entries[1]);
TEST_ASSERT_NOT_NULL((res = gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16)));
TEST_ASSERT_EQUAL_INT(TEST_UINT16, res->demux_ctx);
TEST_ASSERT_EQUAL_INT(TEST_UINT8, res->pid);
TEST_ASSERT_EQUAL_INT(TEST_UINT8, res->target.pid);
gnrc_netreg_unregister(GNRC_NETTYPE_TEST, &entries[0]);
TEST_ASSERT_NULL(gnrc_netreg_lookup(GNRC_NETTYPE_TEST, TEST_UINT16));
}