Add timeout queues

This commit is contained in:
Matthias Schiffer 2012-10-13 20:01:48 +02:00
parent 8e810f5fd8
commit bc9f976d7f
6 changed files with 162 additions and 33 deletions

View file

@ -5,6 +5,7 @@ add_executable(ffd
ffd.c ffd.c
neigh.c neigh.c
netif.c netif.c
queue.c
send.c send.c
tlv.c tlv.c
util.c util.c

View file

@ -28,6 +28,7 @@
#include "neigh.h" #include "neigh.h"
#include "netif.h" #include "netif.h"
#include "packet.h" #include "packet.h"
#include "queue.h"
#include "tlv.h" #include "tlv.h"
#include "tlv_types.h" #include "tlv_types.h"
@ -51,10 +52,10 @@ static char *mesh = "bat0";
int sockfd; int sockfd;
struct timespec now; struct timespec now;
static ffd_queue_head *tasks;
ffd_node_id_t self; ffd_node_id_t self;
ffd_iface_t *iface_list = NULL; ffd_iface_t *iface_list = NULL;
ffd_announce_t *announce_list = NULL; ffd_announce_t *announce_list = NULL;
@ -489,6 +490,8 @@ static void receive_packet(void) {
} }
static void send_updates(void) { static void send_updates(void) {
fprintf(stderr, "debug: sending periodic updates.\n");
ffd_iface_t *iface; ffd_iface_t *iface;
for (iface = iface_list; iface; iface = iface->next) { for (iface = iface_list; iface; iface = iface->next) {
ffd_send_update(iface, NULL, NULL, false); ffd_send_update(iface, NULL, NULL, false);
@ -558,6 +561,36 @@ static void maintenance(void) {
} }
} }
typedef struct _periodic_task_info {
void (*handle)(void);
unsigned delay;
unsigned interval;
} periodic_task_info;
static const periodic_task_info periodic_tasks [] = {
{maintenance, 0, FFD_MAINTENANCE_INTERVAL},
{ffd_send_hellos, FFD_HELLO_INTERVAL, FFD_HELLO_INTERVAL},
{send_updates, 1, FFD_UPDATE_INTERVAL},
{NULL}
};
static void handle_periodic_task(const struct timespec *timeout, void *arg) {
const periodic_task_info *info = arg;
info->handle();
ffd_queue_put_delayed(&tasks, handle_periodic_task, timeout, info->interval, arg);
}
static void register_periodic_tasks(void) {
const periodic_task_info *info;
for (info = periodic_tasks; info->handle; info++)
ffd_queue_put_delayed(&tasks, handle_periodic_task, &now, info->delay, (void*)info);
}
int main() { int main() {
if (!check_config()) if (!check_config())
return 1; return 1;
@ -569,44 +602,21 @@ int main() {
return 1; return 1;
update_time(); update_time();
register_periodic_tasks();
struct timespec next_hello = now;
struct timespec next_update = now;
struct timespec next_maintenance = now;
while (true) { while (true) {
int maintenance_timeout = timespec_diff(&next_maintenance, &now); ffd_queue_run(&tasks);
if (maintenance_timeout <= 0) {
maintenance();
add_interval(&next_maintenance, FFD_MAINTENANCE_INTERVAL);
}
int hello_timeout = timespec_diff(&next_hello, &now);
if (hello_timeout <= 0) {
ffd_send_hellos();
add_interval(&next_hello, FFD_HELLO_INTERVAL);
}
int update_timeout = timespec_diff(&next_update, &now);
if (update_timeout <= 0) {
fprintf(stderr, "Sending periodic update.\n");
send_updates();
add_interval(&next_update, FFD_UPDATE_INTERVAL);
}
int timeout = min(min(hello_timeout, update_timeout), maintenance_timeout);
if (timeout <= 0)
continue;
struct pollfd fds[1]; struct pollfd fds[1];
int timeout = 10*ffd_queue_timeout(&tasks);
if (timeout < 0)
timeout = -1;
fds[0].fd = sockfd; fds[0].fd = sockfd;
fds[0].events = POLLIN; fds[0].events = POLLIN;
poll(fds, 1, 10*timeout); poll(fds, 1, timeout);
update_time(); update_time();

View file

@ -145,7 +145,6 @@ extern ffd_iface_t *iface_list;
extern ffd_announce_t *announce_list; extern ffd_announce_t *announce_list;
extern int sockfd; extern int sockfd;
extern struct timespec now;
#define FFD_NODE_ID_UNSPEC ((ffd_node_id_t){}) #define FFD_NODE_ID_UNSPEC ((ffd_node_id_t){})

42
ffd/queue.c Normal file
View file

@ -0,0 +1,42 @@
/*
Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "queue.h"
void ffd_queue_put(ffd_queue_head **queue, ffd_queue_cb cb, const struct timespec *timeout, void *arg) {
while (*queue && timespec_after(timeout, &(*queue)->timeout))
queue = &(*queue)->next;
ffd_queue_head *entry = malloc(sizeof(ffd_queue_head));
entry->cb = cb;
entry->timeout = *timeout;
entry->arg = arg;
entry->next = *queue;
*queue = entry;
}

69
ffd/queue.h Normal file
View file

@ -0,0 +1,69 @@
/*
Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FFD_QUEUE_H_
#define _FFD_QUEUE_H_
#include "util.h"
typedef void (*ffd_queue_cb)(const struct timespec *timeout, void *arg);
typedef struct _ffd_queue_head {
struct _ffd_queue_head *next;
ffd_queue_cb cb;
struct timespec timeout;
void *arg;
} ffd_queue_head;
void ffd_queue_put(ffd_queue_head **queue, ffd_queue_cb cb, const struct timespec *timeout, void *arg);
static inline void ffd_queue_put_delayed(ffd_queue_head **queue, ffd_queue_cb cb, const struct timespec *timeout, int delay, void *arg) {
struct timespec timeout_delayed = *timeout;
add_interval(&timeout_delayed, delay);
ffd_queue_put(queue, cb, &timeout_delayed, arg);
}
static inline void ffd_queue_run(ffd_queue_head **queue) {
while (*queue && timespec_after(&now, &(*queue)->timeout)) {
ffd_queue_head *entry = *queue;
*queue = (*queue)->next;
entry->cb(&entry->timeout, entry->arg);
free(entry);
}
}
static inline int ffd_queue_timeout(ffd_queue_head *const *queue) {
if (!*queue)
return -1;
return max(timespec_diff(&(*queue)->timeout, &now), 0);
}
#endif /* _FFD_QUEUE_H_ */

View file

@ -34,6 +34,9 @@
#include <time.h> #include <time.h>
extern struct timespec now;
bool file_readv(const char *file, const char *format, va_list ap); bool file_readv(const char *file, const char *format, va_list ap);
void random_bytes(void *buffer, size_t len); void random_bytes(void *buffer, size_t len);
@ -53,6 +56,11 @@ static inline bool are_eth_addrs_equal(const eth_addr_t *address1, const eth_add
return (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3] && a[4]==b[4] && a[5]==b[5]); return (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3] && a[4]==b[4] && a[5]==b[5]);
} }
static inline bool timespec_after(const struct timespec *tp1, const struct timespec *tp2) {
return (tp1->tv_sec > tp2->tv_sec ||
(tp1->tv_sec == tp2->tv_sec && tp1->tv_nsec > tp2->tv_nsec));
}
/* returns (tp1 - tp2) in centiseconds */ /* returns (tp1 - tp2) in centiseconds */
static inline int timespec_diff(const struct timespec *tp1, const struct timespec *tp2) { static inline int timespec_diff(const struct timespec *tp1, const struct timespec *tp2) {
return ((tp1->tv_sec - tp2->tv_sec))*100 + (tp1->tv_nsec - tp2->tv_nsec)/1e7; return ((tp1->tv_sec - tp2->tv_sec))*100 + (tp1->tv_nsec - tp2->tv_nsec)/1e7;