From baff748e8cffd6f6eadc2e3524b63e0e0315ef41 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 5 Nov 2013 02:00:44 +0100 Subject: [PATCH 1/2] add simple list implementation --- sys/Makefile | 3 + sys/include/list.h | 47 +++++++++++++++ sys/list/Makefile | 5 ++ sys/list/list.c | 141 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 sys/include/list.h create mode 100644 sys/list/Makefile create mode 100644 sys/list/list.c diff --git a/sys/Makefile b/sys/Makefile index d350ade17447..dd578f35b6ec 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -94,6 +94,9 @@ endif ifneq (,$(findstring ccn_lite_client,$(USEMODULE))) DIRS += net/ccn_lite/util endif +ifneq (,$(findstring list,$(USEMODULE))) + DIRS += list +endif all: $(BINDIR)$(MODULE).a @for i in $(DIRS) ; do "$(MAKE)" -C $$i ; done ; diff --git a/sys/include/list.h b/sys/include/list.h new file mode 100644 index 000000000000..6737295c5c66 --- /dev/null +++ b/sys/include/list.h @@ -0,0 +1,47 @@ +#ifndef SIMPLE_LIST_H_ +#define SIMPLE_LIST_H_ +#include +#include + +struct simple_list_elem; + +#define simple_list_add_head(head) _simple_list_add_head((struct simple_list_elem**) head, calloc(1, sizeof **head)) +#define simple_list_set_head(head, node) _simple_list_add_head((struct simple_list_elem**) head, node) +#define simple_list_add_tail(head) _simple_list_add_tail((struct simple_list_elem**) head, calloc(1, sizeof **head)) +#define simple_list_set_tail(head, node) _simple_list_add_tail((struct simple_list_elem**) head, node) +#define simple_list_add_before(head, value) *head == 0 ? simple_list_add_head(head) : \ + _simple_list_add_before((struct simple_list_elem**) head, calloc(1, sizeof **head), value, (void*) &(*(head))->value - (void*) *head) +#define simple_list_set_before(head, node, value) *head == 0 ? simple_list_set_head(head, node) : \ + _simple_list_add_before((struct simple_list_elem**) head, node, value, (void*) &(*(head))->value - (void*) *head) +#define simple_list_find(head, value) head == 0 ? NULL : \ + _simple_list_find((struct simple_list_elem*) head, value, (void*) &((head)->value) - (void*) head, 0) +#define simple_list_find_memcmp(head, value) head == 0 ? NULL : \ + _simple_list_find((struct simple_list_elem*) head, value, (void*) &((head)->value) - (void*) head, sizeof(*value)) +#define simple_list_find_cmp(head, value, comperator) head == 0 ? NULL : \ + _simple_list_find_cmp((struct simple_list_elem*) head, value, (void*) &((head)->value) - (void*) head, comperator) +#define simple_list_remove(head, node) _simple_list_remove((struct simple_list_elem**) head, (struct simple_list_elem*) node, 0) +#define simple_list_extract(head, node) _simple_list_remove((struct simple_list_elem**) head, (struct simple_list_elem*) node, 1) +#define simple_list_clear(head) _simple_list_clear((struct simple_list_elem**) head) + +#define simple_list_for_each(head, node) for (node = head; node; node = node->next) +#define simple_list_for_each_safe(head, node, prev, skipped) \ + for (skipped = 0, prev = 0, node = head; node; prev = (skipped ? prev : node), node = (skipped ? node : node->next), skipped = 0) +#define simple_list_for_each_remove(head, node, prev) { \ + if (!prev) { \ + skipped = 1; \ + *head = (*head)->next; \ + } else \ + prev->next = node->next; \ + free(node); \ + node = prev ? prev : *head; \ + } + +void* _simple_list_add_head(struct simple_list_elem** head, void* mem); +void* _simple_list_add_tail(struct simple_list_elem** head, void* mem); +void* _simple_list_add_before(struct simple_list_elem** head, void* mem, int needle, int offset); +void* _simple_list_find(struct simple_list_elem* head, void* needle, int offset, size_t size); +void* _simple_list_find_cmp(struct simple_list_elem* head, void* needle, int offset, int compare(void*, void*)); +void* _simple_list_remove(struct simple_list_elem** head, struct simple_list_elem* node, int keep); +void _simple_list_clear(struct simple_list_elem** head); + +#endif /* SIMPLE_LIST_H_ */ diff --git a/sys/list/Makefile b/sys/list/Makefile new file mode 100644 index 000000000000..80ba39ec3b58 --- /dev/null +++ b/sys/list/Makefile @@ -0,0 +1,5 @@ +INCLUDES = -I../include -I$(RIOTBASE)/core/include +MODULE = list + +include $(RIOTBASE)/Makefile.base + diff --git a/sys/list/list.c b/sys/list/list.c new file mode 100644 index 000000000000..78443aa7ee0e --- /dev/null +++ b/sys/list/list.c @@ -0,0 +1,141 @@ +#include +#include + +#include "list.h" + +struct simple_list_elem { + struct simple_list_elem* next; +}; + +void* _simple_list_add_tail(struct simple_list_elem** head, void* mem) { + struct simple_list_elem* _head = *head; + + /* check out-of-memory condition */ + if (mem == NULL) + return NULL; + + if (!_head) { + *head = mem; + return *head; + } + + while (_head->next) { + _head = _head->next; + } + + _head = _head->next = mem; + return _head; +} + +void* _simple_list_add_head(struct simple_list_elem** head, void* mem) { + struct simple_list_elem* _head = *head; + + /* check out-of-memory condition */ + if (mem == NULL) + return NULL; + + *head = mem; + (*head)->next = _head; + + return *head; +} + +void* _simple_list_add_before(struct simple_list_elem** head, void* mem, int needle, int offset) { + struct simple_list_elem* _head = *head; + struct simple_list_elem* prev = 0; + + /* check out-of-memory condition */ + if (mem == NULL) + return NULL; + + if (!_head) { + *head = mem; + return *head; + } + + while(_head) { + int* buff = (void*) _head + offset; + if (*buff > needle) { + if (prev) { + prev->next = mem; + prev->next->next = _head; + return prev->next; + } + + prev = mem; + prev->next = _head; + *head = prev; + return prev; + } + prev = _head; + _head = _head->next; + } + + _head = prev->next = mem; + return _head; +} + +void* _simple_list_find(struct simple_list_elem* head, void* needle, int offset, size_t size) { + while (head) { + void** buff = (void*) head + offset; + + if (size == 0 && *buff == needle) + return head; + if (size > 0 && memcmp(*buff, needle, size) == 0) + return head; + head = head->next; + } + + return 0; +} + +void* _simple_list_find_cmp(struct simple_list_elem* head, void* needle, int offset, int compare(void*, void*)) { + while (head) { + void** buff = (void*) head + offset; + + if (compare(*buff, needle) == 0) + return head; + + head = head->next; + } + + return 0; +} + +void* _simple_list_remove(struct simple_list_elem** head, struct simple_list_elem* node, int keep) { + struct simple_list_elem* _head = *head; + struct simple_list_elem* prev = 0; + + while (_head && _head != node) { + prev = _head; + _head = _head->next; + } + + /* not found */ + if (_head != node) + return NULL; + + /* remove head */ + if (!prev) + *head = _head->next; + else + prev->next = node->next; + + if (keep) + return node; + + free(node); + return (void*) 1; +} + +void _simple_list_clear(struct simple_list_elem** head) { + struct simple_list_elem *tmp, *_head = *head; + + while (_head != NULL) { + tmp = _head; + _head = _head->next; + free(tmp); + } + + *head = NULL; +} \ No newline at end of file From f707ed87544b2faeb2b80c893742d1a0610adddf Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 5 Nov 2013 03:42:44 +0100 Subject: [PATCH 2/2] use list.h in lowpan.c Use a generic list instead of the buggy custom one --- Makefile.dep | 3 + sys/net/sixlowpan/lowpan.c | 209 ++++++++----------------------------- 2 files changed, 46 insertions(+), 166 deletions(-) diff --git a/Makefile.dep b/Makefile.dep index b3b66a8b135c..b86b1f2cdf94 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -64,4 +64,7 @@ ifneq (,$(findstring sixlowpan,$(USEMODULE))) ifeq (,$(findstring transceiver, $(USEMODULE))) USEMODULE += transceiver endif + ifeq (,$(findstring list, $(USEMODULE))) + USEMODULE += list + endif endif diff --git a/sys/net/sixlowpan/lowpan.c b/sys/net/sixlowpan/lowpan.c index 13aa962daeae..ef3250c0698f 100644 --- a/sys/net/sixlowpan/lowpan.c +++ b/sys/net/sixlowpan/lowpan.c @@ -30,6 +30,7 @@ #include "mutex.h" #include "hwtimer.h" #include "msg.h" +#include "list.h" #include "transceiver.h" #include "sixlowpan/mac.h" #include "sixlowpan/ndp.h" @@ -64,12 +65,14 @@ char addr_str[IPV6_MAX_ADDR_STR_LEN]; #define SIXLOWPAN_FRAG_HDR_MASK (0xf8) typedef struct lowpan_interval_list_t { + struct lowpan_interval_list_t *next; uint8_t start; uint8_t end; - struct lowpan_interval_list_t *next; } lowpan_interval_list_t; typedef struct lowpan_reas_buf_t { + /* Pointer to next reassembly buffer (if any) */ + struct lowpan_reas_buf_t *next; /* Source Address */ ieee_802154_long_t s_laddr; /* Destination Address */ @@ -86,8 +89,6 @@ typedef struct lowpan_reas_buf_t { uint8_t *packet; /* Pointer to list of intervals of received packet fragments (if any) */ lowpan_interval_list_t *interval_list_head; - /* Pointer to next reassembly buffer (if any) */ - struct lowpan_reas_buf_t *next; } lowpan_reas_buf_t; extern mutex_t lowpan_context_mutex; @@ -143,8 +144,7 @@ void lowpan_iphc_decoding(uint8_t *data, uint8_t length, ieee_802154_long_t *s_laddr, ieee_802154_long_t *d_laddr); void add_fifo_packet(lowpan_reas_buf_t *current_packet); -lowpan_reas_buf_t *collect_garbage_fifo(lowpan_reas_buf_t *current_buf); -lowpan_reas_buf_t *collect_garbage(lowpan_reas_buf_t *current_buf); +void collect_garbage_fifo(lowpan_reas_buf_t *current_buf); void init_reas_bufs(lowpan_reas_buf_t *buf); void check_timeout(void); @@ -265,23 +265,18 @@ void sixlowpan_lowpan_print_reassembly_buffers(void) { lowpan_reas_buf_t *temp_buffer; lowpan_interval_list_t *temp_interval; - temp_buffer = head; printf("\n\n--- Reassembly Buffers ---\n"); - while (temp_buffer != NULL) { + simple_list_for_each(head, temp_buffer) { print_long_local_addr(&temp_buffer->s_laddr); printf("Ident.: %i, Packet Size: %i/%i, Timestamp: %li\n", temp_buffer->ident_no, temp_buffer->current_packet_size, temp_buffer->packet_size, temp_buffer->timestamp); - temp_interval = temp_buffer->interval_list_head; - while (temp_interval != NULL) { + simple_list_for_each(temp_buffer->interval_list_head, temp_interval) { printf("\t%i - %i\n", temp_interval->start, temp_interval->end); - temp_interval = temp_interval->next; } - - temp_buffer = temp_buffer->next; } } @@ -289,23 +284,18 @@ void sixlowpan_lowpan_print_fifo_buffers(void) { lowpan_reas_buf_t *temp_buffer; lowpan_interval_list_t *temp_interval; - temp_buffer = packet_fifo; printf("\n\n--- Reassembly Buffers ---\n"); - while (temp_buffer != NULL) { + simple_list_for_each(packet_fifo, temp_buffer) { print_long_local_addr(&temp_buffer->s_laddr); printf("Ident.: %i, Packet Size: %i/%i, Timestamp: %li\n", temp_buffer->ident_no, temp_buffer->current_packet_size, temp_buffer->packet_size, temp_buffer->timestamp); - temp_interval = temp_buffer->interval_list_head; - while (temp_interval != NULL) { + simple_list_for_each(temp_buffer->interval_list_head, temp_interval) { printf("\t%i - %i\n", temp_interval->start, temp_interval->end); - temp_interval = temp_interval->next; } - - temp_buffer = temp_buffer->next; } } #endif @@ -344,7 +334,7 @@ void lowpan_transfer(void) msg_send_receive(&m_send, &m_recv, ip_process_pid); } else { - // printf("ERROR: packet with unknown dispatch received\n"); + printf("ERROR: packet with unknown dispatch received\n"); } collect_garbage_fifo(current_buf); @@ -390,14 +380,12 @@ uint8_t ll_get_addr_match(ieee_802154_long_t *src, ieee_802154_long_t *dst) lowpan_reas_buf_t *new_packet_buffer(uint16_t datagram_size, uint16_t datagram_tag, ieee_802154_long_t *s_laddr, - ieee_802154_long_t *d_laddr, - lowpan_reas_buf_t *current_buf, - lowpan_reas_buf_t *temp_buf) + ieee_802154_long_t *d_laddr) { - lowpan_reas_buf_t *new_buf = NULL; + lowpan_reas_buf_t *new_buf; /* Allocate new memory for a new packet to be reassembled */ - new_buf = malloc(sizeof(lowpan_reas_buf_t)); + new_buf = simple_list_add_head(&head); if (new_buf != NULL) { init_reas_bufs(new_buf); @@ -415,20 +403,16 @@ lowpan_reas_buf_t *new_packet_buffer(uint16_t datagram_size, vtimer_now(&now); new_buf->timestamp = now.microseconds; - if ((current_buf == NULL) && (temp_buf == NULL)) { - head = new_buf; - } - else { - temp_buf->next = new_buf; - } - return new_buf; } else { + /* not enough memory for packet */ + simple_list_remove(&head, new_buf); return NULL; } } else { + /* not enough memory for new_buf */ return NULL; } } @@ -438,10 +422,8 @@ lowpan_reas_buf_t *get_packet_frag_buf(uint16_t datagram_size, ieee_802154_long_t *s_laddr, ieee_802154_long_t *d_laddr) { - lowpan_reas_buf_t *current_buf = NULL, *temp_buf = NULL; - current_buf = head; - - while (current_buf != NULL) { + lowpan_reas_buf_t *current_buf; + simple_list_for_each(head, current_buf) { if (((ll_get_addr_match(¤t_buf->s_laddr, s_laddr)) == 64) && ((ll_get_addr_match(¤t_buf->d_laddr, d_laddr)) == 64) && (current_buf->packet_size == datagram_size) && @@ -453,13 +435,9 @@ lowpan_reas_buf_t *get_packet_frag_buf(uint16_t datagram_size, current_buf->timestamp = now.microseconds; return current_buf; } - - temp_buf = current_buf; - current_buf = current_buf->next; } - return new_packet_buffer(datagram_size, datagram_tag, s_laddr, d_laddr, - current_buf, temp_buf); + return new_packet_buffer(datagram_size, datagram_tag, s_laddr, d_laddr); } uint8_t is_in_interval(uint8_t start1, uint8_t end1, uint8_t start2, uint8_t end2) @@ -482,32 +460,21 @@ uint8_t handle_packet_frag_interval(lowpan_reas_buf_t *current_buf, { /* 0: Error, discard fragment */ /* 1: Finished correctly */ - lowpan_interval_list_t *temp_interval = NULL, *current_interval = NULL, *new_interval = NULL; - current_interval = current_buf->interval_list_head; + lowpan_interval_list_t *current_interval; - while (current_interval != NULL) { + simple_list_for_each(current_buf->interval_list_head, current_interval) { if (is_in_interval(current_interval->start, current_interval->end, datagram_offset, datagram_offset + frag_size) == 1) { /* Interval is overlapping or the same as one of a previous fragment, discard fragment */ return 0; } - - temp_interval = current_interval; - current_interval = current_interval->next; } - new_interval = malloc(sizeof(lowpan_interval_list_t)); + current_interval = simple_list_add_tail(¤t_buf->interval_list_head); - if (new_interval != NULL) { - new_interval->start = datagram_offset; - new_interval->end = datagram_offset + frag_size - 1; - new_interval->next = NULL; - - if ((current_interval == NULL) && (temp_interval == NULL)) { - current_buf->interval_list_head = new_interval; - } - else { - temp_interval->next = new_interval; - } + if (current_interval != NULL) { + current_interval->start = datagram_offset; + current_interval->end = datagram_offset + frag_size - 1; + current_interval->next = NULL; return 1; } @@ -515,84 +482,14 @@ uint8_t handle_packet_frag_interval(lowpan_reas_buf_t *current_buf, return 0; } -lowpan_reas_buf_t *collect_garbage_fifo(lowpan_reas_buf_t *current_buf) +void collect_garbage_fifo(lowpan_reas_buf_t *current_buf) { - lowpan_interval_list_t *temp_list, *current_list; - lowpan_reas_buf_t *temp_buf, *my_buf, *return_buf; + free(current_buf->packet); + simple_list_clear(¤t_buf->interval_list_head); mutex_lock(&fifo_mutex); - - temp_buf = packet_fifo; - my_buf = temp_buf; - - if (packet_fifo == current_buf) { - packet_fifo = current_buf->next; - return_buf = packet_fifo; - } - else { - while (temp_buf != current_buf) { - my_buf = temp_buf; - temp_buf = temp_buf->next; - } - - my_buf->next = current_buf->next; - - return_buf = my_buf->next; - } - + simple_list_remove(&packet_fifo, current_buf); mutex_unlock(&fifo_mutex); - - current_list = current_buf->interval_list_head; - temp_list = current_list; - - while (current_list != NULL) { - temp_list = current_list->next; - free(current_list); - current_list = temp_list; - } - - free(current_buf->packet); - free(current_buf); - - return return_buf; -} - -lowpan_reas_buf_t *collect_garbage(lowpan_reas_buf_t *current_buf) -{ - lowpan_interval_list_t *temp_list, *current_list; - lowpan_reas_buf_t *temp_buf, *my_buf, *return_buf; - - temp_buf = head; - my_buf = temp_buf; - - if (head == current_buf) { - head = current_buf->next; - return_buf = head; - } - else { - while (temp_buf != current_buf) { - my_buf = temp_buf; - temp_buf = temp_buf->next; - } - - my_buf->next = current_buf->next; - - return_buf = my_buf->next; - } - - current_list = current_buf->interval_list_head; - temp_list = current_list; - - while (current_list != NULL) { - temp_list = current_list->next; - free(current_list); - current_list = temp_list; - } - - free(current_buf->packet); - free(current_buf); - - return return_buf; } void handle_packet_fragment(uint8_t *data, uint8_t datagram_offset, @@ -642,11 +539,16 @@ void check_timeout(void) cur_time = now.microseconds; temp_buf = head; - while (temp_buf != NULL) { + int skipped = 0; + lowpan_reas_buf_t *prev; + simple_list_for_each_safe(head, temp_buf, prev, skipped) { if ((cur_time - temp_buf->timestamp) >= LOWPAN_REAS_BUF_TIMEOUT) { printf("TIMEOUT!cur_time: %li, temp_buf: %li\n", cur_time, temp_buf->timestamp); - temp_buf = collect_garbage(temp_buf); + + free(temp_buf->packet); + simple_list_clear(&temp_buf->interval_list_head); + simple_list_for_each_remove(&head, temp_buf, prev); } else { if (smallest_time == NULL) { @@ -656,52 +558,27 @@ void check_timeout(void) smallest_time = temp_buf; } - temp_buf = temp_buf->next; count++; } } if ((count > 10) && (smallest_time != NULL)) { - collect_garbage(smallest_time); + free(smallest_time->packet); + simple_list_clear(&smallest_time->interval_list_head); + simple_list_remove(&head, smallest_time); } } void add_fifo_packet(lowpan_reas_buf_t *current_packet) { - lowpan_reas_buf_t *temp_buf, *my_buf; - - if (head == current_packet) { - head = current_packet->next; - } - else { - temp_buf = head; - - while (temp_buf != current_packet) { - my_buf = temp_buf; - temp_buf = temp_buf->next; - } - - my_buf->next = current_packet->next; - } + simple_list_extract(&head, current_packet); + current_packet->next = NULL; mutex_lock(&fifo_mutex); - if (packet_fifo == NULL) { - packet_fifo = current_packet; - } - else { - temp_buf = packet_fifo; - - while (temp_buf != NULL) { - my_buf = temp_buf; - temp_buf = temp_buf->next; - } - - my_buf->next = current_packet; - } + simple_list_set_tail(&packet_fifo, current_packet); mutex_unlock(&fifo_mutex); - current_packet->next = NULL; } /* Register an upper layer thread */