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

Merge pull request #3362 from authmillenon/ng_neterr/feat/initial

[RFC] gnrc: initial import of an asynchronous error reporting API
This commit is contained in:
Martine Lenders 2016-01-26 21:35:30 +01:00
commit 131cae626c
5 changed files with 143 additions and 16 deletions

View File

@ -6,6 +6,7 @@ PSEUDOMODULES += gnrc_netif_default
PSEUDOMODULES += gnrc_ipv6_default
PSEUDOMODULES += gnrc_ipv6_router
PSEUDOMODULES += gnrc_ipv6_router_default
PSEUDOMODULES += gnrc_neterr
PSEUDOMODULES += gnrc_sixlowpan_default
PSEUDOMODULES += gnrc_sixlowpan_border_router_default
PSEUDOMODULES += gnrc_sixlowpan_nd_border_router

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup net_gnrc_neterr Error reporting
* @ingroup net
* @brief Allows for asynchronous error reporting in the network stack.
* @{
*
* @file
* @brief Error reporting definitions.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef GNRC_NETERR_H_
#define GNRC_NETERR_H_
#include <errno.h>
#include <stdint.h>
#include "kernel_types.h"
#include "msg.h"
#include "net/gnrc/pkt.h"
#include "thread.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief @ref core_msg type for reporting an error.
*/
#define GNRC_NETERR_MSG_TYPE (0x0206)
/**
* @brief Error code to signalise success (no error occured) to an gnrc_neterr subscriber.
*/
#define GNRC_NETERR_SUCCESS (0)
/**
* @brief Reports an error to all subscribers of errors to @p pkt.
*
* @param[in] pkt Packet snip to report on.
* @param[in] err The error code for the packet.
*/
#ifdef MODULE_GNRC_NETERR
static inline void gnrc_neterr_report(gnrc_pktsnip_t *pkt, uint32_t err)
{
if (pkt->err_sub != KERNEL_PID_UNDEF) {
msg_t msg;
msg.type = GNRC_NETERR_MSG_TYPE;
msg.content.value = err;
msg_send(&msg, pkt->err_sub);
}
}
#else
#define gnrc_neterr_report(pkt, err) (void)pkt; (void)err
#endif
/**
* @brief Registers the current thread for errors on a @ref gnrc_pktsnip_t.
*
* @param[in] pkt Packet snip to register for errors.
*
* @return 0, on success.
* @return EALREADY, if there already someone registered to errors on @p pkt.
*/
#ifdef MODULE_GNRC_NETERR
static inline int gnrc_neterr_reg(gnrc_pktsnip_t *pkt)
{
if (pkt->err_sub != KERNEL_PID_UNDEF) {
return EALREADY;
}
pkt->err_sub = sched_active_pid;
return 0;
}
#else
#define gnrc_neterr_reg(pkt) (0)
#endif
#ifdef __cplusplus
}
#endif
#endif /* GNRC_NETERR_H_ */
/** @} */

View File

@ -25,6 +25,7 @@
#include <inttypes.h>
#include <stdlib.h>
#include "kernel_types.h"
#include "net/gnrc/nettype.h"
#ifdef __cplusplus
@ -110,6 +111,10 @@ typedef struct gnrc_pktsnip {
void *data; /**< pointer to the data of the snip */
size_t size; /**< the length of the snip in byte */
gnrc_nettype_t type; /**< protocol of the packet snip */
#ifdef MODULE_GNRC_NETERR
kernel_pid_t err_sub; /**< subscriber to errors related to this
* packet snip */
#endif
} gnrc_pktsnip_t;
/**

View File

@ -37,6 +37,7 @@
#include "atomic.h"
#include "cpu_conf.h"
#include "net/gnrc/pkt.h"
#include "net/gnrc/neterr.h"
#include "net/gnrc/nettype.h"
#include "utlist.h"
@ -141,13 +142,26 @@ void gnrc_pktbuf_hold(gnrc_pktsnip_t *pkt, unsigned int num);
/**
* @brief Decreases gnrc_pktsnip_t::users of @p pkt atomically and removes it if it
* reaches 0.
* reaches 0 and reports a possible error through an error code, if
* @ref net_gnrc_neterr is included.
*
* @pre All snips of @p pkt must be in the packet buffer.
*
* @param[in] pkt A packet.
* @param[in] err An error code.
*/
void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt);
void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err);
/**
* @brief Decreases gnrc_pktsnip_t::users of @p pkt atomically and removes it if it
* reaches 0 and reports @ref GNRC_NETERR_SUCCESS.
*
* @param[in] pkt A packet.
*/
static inline void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt)
{
gnrc_pktbuf_release_error(pkt, GNRC_NETERR_SUCCESS);
}
/**
* @brief Must be called once before there is a write operation in a thread.
@ -189,7 +203,7 @@ gnrc_pktsnip_t *gnrc_pktbuf_get_iovec(gnrc_pktsnip_t *pkt, size_t *len);
* @return The new reference to @p pkt.
*/
static inline gnrc_pktsnip_t *gnrc_pktbuf_remove_snip(gnrc_pktsnip_t *pkt,
gnrc_pktsnip_t *snip)
gnrc_pktsnip_t *snip)
{
LL_DELETE(pkt, snip);
snip->next = NULL;

View File

@ -64,9 +64,21 @@ static inline bool _pktbuf_contains(void *ptr)
/* fits size to byte alignment */
static inline size_t _align(size_t size)
{
return ((size + _ALIGNMENT_MASK) & ~(_ALIGNMENT_MASK));
return (size + _ALIGNMENT_MASK) & ~(_ALIGNMENT_MASK);
}
static inline void _set_pktsnip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *next,
void *data, size_t size, gnrc_nettype_t type)
{
pkt->next = next;
pkt->data = data;
pkt->size = size;
pkt->type = type;
pkt->users = 1;
#ifdef MODULE_GNRC_NETERR
pkt->err_sub = KERNEL_PID_UNDEF;
#endif
}
void gnrc_pktbuf_init(void)
{
@ -81,6 +93,7 @@ gnrc_pktsnip_t *gnrc_pktbuf_add(gnrc_pktsnip_t *next, void *data, size_t size,
gnrc_nettype_t type)
{
gnrc_pktsnip_t *pkt;
if ((size == 0) || (size > GNRC_PKTBUF_SIZE)) {
DEBUG("pktbuf: size (%u) == 0 || size == GNRC_PKTBUF_SIZE (%u)\n",
(unsigned)size, GNRC_PKTBUF_SIZE);
@ -98,6 +111,8 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_
/* size required for chunk */
size_t required_new_size = (size < sizeof(_unused_t)) ?
_align(sizeof(_unused_t)) : _align(size);
void *new_data_marked;
mutex_lock(&_mutex);
if ((size == 0) || (pkt == NULL) || (size > pkt->size) || (pkt->data == NULL)) {
DEBUG("pktbuf: size == 0 (was %u) or pkt == NULL (was %p) or "
@ -120,7 +135,7 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_
}
/* would not fit unused marker => move data around */
if ((size < required_new_size) || ((pkt->size - size) < sizeof(_unused_t))) {
void *new_data_marked, *new_data_rest;
void *new_data_rest;
new_data_marked = _pktbuf_alloc(size);
if (new_data_marked == NULL) {
DEBUG("pktbuf: could not reallocate marked section.\n");
@ -143,14 +158,11 @@ gnrc_pktsnip_t *gnrc_pktbuf_mark(gnrc_pktsnip_t *pkt, size_t size, gnrc_nettype_
pkt->data = new_data_rest;
}
else {
marked_snip->data = pkt->data;
new_data_marked = pkt->data;
pkt->data = ((uint8_t *)pkt->data) + size;
}
pkt->size -= size;
marked_snip->next = pkt->next;
marked_snip->size = size;
marked_snip->type = type;
marked_snip->users = 1;
_set_pktsnip(marked_snip, pkt->next, new_data_marked, size, type);
pkt->next = marked_snip;
mutex_unlock(&_mutex);
return marked_snip;
@ -160,6 +172,7 @@ int gnrc_pktbuf_realloc_data(gnrc_pktsnip_t *pkt, size_t size)
{
size_t aligned_size = (size < sizeof(_unused_t)) ?
_align(sizeof(_unused_t)) : _align(size);
mutex_lock(&_mutex);
assert((pkt != NULL) && (pkt->data != NULL) && _pktbuf_contains(pkt->data));
if (size == 0) {
@ -204,7 +217,7 @@ void gnrc_pktbuf_hold(gnrc_pktsnip_t *pkt, unsigned int num)
mutex_unlock(&_mutex);
}
void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt)
void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err)
{
mutex_lock(&_mutex);
while (pkt) {
@ -219,6 +232,8 @@ void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt)
else {
pkt->users--;
}
DEBUG("pktbuf: report status code %" PRIu32 "\n", err);
gnrc_neterr_report(pkt, err);
pkt = tmp;
}
mutex_unlock(&_mutex);
@ -378,6 +393,7 @@ static gnrc_pktsnip_t *_create_snip(gnrc_pktsnip_t *next, void *data, size_t siz
{
gnrc_pktsnip_t *pkt = _pktbuf_alloc(sizeof(gnrc_pktsnip_t));
void *_data;
if (pkt == NULL) {
DEBUG("pktbuf: error allocating new packet snip\n");
return NULL;
@ -388,11 +404,7 @@ static gnrc_pktsnip_t *_create_snip(gnrc_pktsnip_t *next, void *data, size_t siz
_pktbuf_free(pkt, sizeof(gnrc_pktsnip_t));
return NULL;
}
pkt->next = next;
pkt->size = size;
pkt->data = _data;
pkt->type = type;
pkt->users = 1;
_set_pktsnip(pkt, next, _data, size, type);
if (data != NULL) {
memcpy(_data, data, size);
}
@ -402,6 +414,7 @@ static gnrc_pktsnip_t *_create_snip(gnrc_pktsnip_t *next, void *data, size_t siz
static void *_pktbuf_alloc(size_t size)
{
_unused_t *prev = NULL, *ptr = _first_unused;
size = (size < sizeof(_unused_t)) ? _align(sizeof(_unused_t)) : _align(size);
while (ptr && (size > ptr->size)) {
prev = ptr;
@ -456,6 +469,7 @@ static inline _unused_t *_merge(_unused_t *a, _unused_t *b)
static void _pktbuf_free(void *data, size_t size)
{
_unused_t *new = (_unused_t *)data, *prev = NULL, *ptr = _first_unused;
if (!_pktbuf_contains(data)) {
return;
}