diff options
Diffstat (limited to 'lib/mqueue.h')
-rw-r--r-- | lib/mqueue.h | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/lib/mqueue.h b/lib/mqueue.h new file mode 100644 index 00000000..a28b6606 --- /dev/null +++ b/lib/mqueue.h @@ -0,0 +1,393 @@ +/* Message Queue data structure -- header + * Copyright (C) 2009 Chris Hall (GMCH), Highwayman + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_MQUEUE_H +#define _ZEBRA_MQUEUE_H + +#include <stddef.h> +#include <stdbool.h> + +#include "qpthreads.h" +#include "qtime.h" + +#ifndef Inline +#define Inline static inline +#endif + +/*============================================================================== + * Message Queue Blocks -- mqb + * + * Messages in a message queue are held as Message Queue Blocks: + * + * * action -- function to call when message is dispatched + * + * * arg0 -- always a pointer -- used in specific revoke + * + * * args -- embedded structure -- to be overlaid by user structure + * + * * argv -- pointer to: list/array of pointer/integer/unsigned + * + * NB: the elements of argv are all exactly the same size and alignment. + * + * So, as well as using the access functions, it is possible to use the + * argv array directly, as any of: + * + * mqb_arg_t* argv = mqb_get_argv(mqb) ; + * + * void** argv = mqb_get_argv(mqb) ; + * char** argv = mqb_get_argv(mqb) ; + * + * mqb_ptr_t* argv = mqb_get_argv(mqb) ; + * mqb_int_t* argv = mqb_get_argv(mqb) ; + * mqb_uint_t* argv = mqb_get_argv(mqb) ; + */ + +typedef struct mqueue_block* mqueue_block ; + +typedef void* mqb_ptr_t ; +typedef intptr_t mqb_int_t ; +typedef uintptr_t mqb_uint_t ; + +typedef unsigned short mqb_index_t ; + +typedef union +{ + mqb_ptr_t p ; + mqb_int_t i ; + mqb_uint_t u ; +} mqb_arg_t ; + +/* argv is an array of mqb_arg_t, which is the same as an array of.... */ +CONFIRM(sizeof(mqb_arg_t) == sizeof(void*)) ; /* ... pointers */ +CONFIRM(sizeof(mqb_arg_t) == sizeof(mqb_ptr_t)) ; /* ... mqb_ptr_t */ +CONFIRM(sizeof(mqb_arg_t) == sizeof(mqb_int_t)) ; /* ... mqb_int_t */ +CONFIRM(sizeof(mqb_arg_t) == sizeof(mqb_uint_t)) ; /* ... mqb_uint_t */ + /* ... or any combination */ +enum mqb_flag +{ + mqb_destroy = 0, + mqb_action = 1 +} ; + +typedef enum mqb_flag mqb_flag_t ; + +typedef void mqueue_action(mqueue_block mqb, mqb_flag_t flag) ; + +enum { mqb_args_size_max = 64 } ; /* maximum size of struct args */ +enum { mqb_argv_size_unit = 16 } ; /* allocate argv in these units */ + +struct mqb_args +{ + char bytes[mqb_args_size_max] ; /* empty space */ +} ; + +#define MQB_ARGS_SIZE_OK(s) CONFIRM(sizeof(struct s) <= mqb_args_size_max) + +struct mqueue_block +{ + struct mqb_args args ; /* user structure */ + + mqueue_block next ; /* single linked list */ + + mqueue_action* action ; /* for message dispatch */ + + void* arg0 ; + mqb_arg_t* argv ; /* argv, if any */ + + mqb_index_t argv_count ; /* count of elements in argv */ + mqb_index_t argv_alloc ; /* count of elements allocated */ + mqb_index_t argv_next ; /* iterator */ +} ; + +/* mqueue_block structures are malloced. That guarantees maximum alignment. + * To guarantee maximum alignment for "struct args", it must be first item ! + * + * (The typedef is required to stop Eclipse (3.4.2 with CDT 5.0) whining + * about first argument of offsetof().) + */ +typedef struct mqueue_block mqueue_block_t ; +CONFIRM(offsetof(mqueue_block_t, args) == 0) ; + +/*============================================================================== + * The Message Queue itself + */ + +typedef struct mqueue_thread_signal* mqueue_thread_signal ; + +struct mqueue_thread_signal { + mqueue_thread_signal next ; /* NULL => last on list */ + mqueue_thread_signal prev ; /* NULL => NOT on list -- vital ! */ + + qpt_thread_t qpthread ; /* qpthread to kick */ + int signum ; /* signal to kick with */ +} ; + +enum mqueue_queue_type { + mqt_cond_unicast, /* use qpt_cond_signal to kick the queue */ + mqt_cond_broadcast, /* use qpt_cond_broadcast to kick the queue */ + mqt_signal_unicast, /* use single qpt_signal to kick the queue */ + mqt_signal_broadcast, /* use multiple qpt_signal to kick the queue */ +}; + +#ifndef MQUEUE_DEFAULT_INTERVAL +# define MQUEUE_DEFAULT_INTERVAL QTIME(5) +#endif + +struct mqueue_queue_cond { + qpt_cond_t wait_here ; + qtime_mono_t timeout ; + qtime_t interval ; +} ; + +struct mqueue_queue_signal { + mqueue_thread_signal head ; /* NULL => list is empty */ + mqueue_thread_signal tail ; +}; + +typedef struct mqueue_queue* mqueue_queue ; + +struct mqueue_queue +{ + qpt_mutex_t mutex ; + + mqueue_block head ; /* NULL => list is empty */ + mqueue_block tail_priority ; /* last priority message (if any & not empty) */ + mqueue_block tail ; /* last message (if not empty) */ + + unsigned count ; /* of items on the queue */ + + enum mqueue_queue_type type ; + + unsigned waiters ; + + union { + struct mqueue_queue_cond cond ; + struct mqueue_queue_signal signal ; + } kick ; +} ; + +typedef struct mqueue_local_queue* mqueue_local_queue ; + +struct mqueue_local_queue +{ + mqueue_block head ; /* NULL => list is empty */ + mqueue_block tail ; /* last message (if not empty) */ +} ; + +/*============================================================================== + * Functions + */ + +extern void +mqueue_initialise(void) ; + +extern void +mqueue_finish(void) ; + +extern mqueue_queue +mqueue_init_new(mqueue_queue mq, enum mqueue_queue_type type) ; + +extern void +mqueue_empty(mqueue_queue mq) ; + +extern mqueue_queue +mqueue_reset(mqueue_queue mq, int free_structure) ; + +#define mqueue_reset_keep(mq) mqueue_reset(mq, 0) +#define mqueue_reset_free(mq) mqueue_reset(mq, 1) + +extern mqueue_local_queue +mqueue_local_init_new(mqueue_local_queue lmq) ; + +extern mqueue_local_queue +mqueue_local_reset(mqueue_local_queue lmq, int free_structure) ; + +#define mqueue_local_reset_keep(lmq) mqueue_local_reset(lmq, 0) +#define mqueue_local_reset_free(lmq) mqueue_local_reset(lmq, 1) + +extern void +mqueue_set_timeout_interval(mqueue_queue mq, qtime_t interval) ; + +extern mqueue_thread_signal +mqueue_thread_signal_init(mqueue_thread_signal mqt, qpt_thread_t thread, + int signum) ; +mqueue_thread_signal +mqueue_thread_signal_reset(mqueue_thread_signal mqt, int free_structure) ; + +#define mqueue_thread_signal_reset_keep(mqt) mqueue_thread_signal_reset(mqt, 0) +#define mqueue_thread_signal_reset_free(mqt) mqueue_thread_signal_reset(mqt, 1) + +extern mqueue_block +mqb_init_new(mqueue_block mqb, mqueue_action action, void* arg0) ; + +extern mqueue_block +mqb_re_init(mqueue_block mqb, mqueue_action action, void* arg0) ; + +extern void +mqb_free(mqueue_block mqb) ; + +enum mqb_rank +{ + mqb_priority = true, + mqb_ordinary = false +} ; + +extern void +mqueue_enqueue(mqueue_queue mq, mqueue_block mqb, enum mqb_rank priority) ; + +extern mqueue_block +mqueue_dequeue(mqueue_queue mq, int wait, void* arg) ; + +extern void +mqueue_revoke(mqueue_queue mq, void* arg0) ; + +extern int +mqueue_done_waiting(mqueue_queue mq, mqueue_thread_signal mtsig) ; + +extern void +mqueue_local_enqueue(mqueue_local_queue lmq, mqueue_block mqb) ; + +extern void +mqueue_local_enqueue_head(mqueue_local_queue lmq, mqueue_block mqb) ; + +Inline mqueue_block +mqueue_local_head(mqueue_local_queue lmq) ; + +extern mqueue_block +mqueue_local_dequeue(mqueue_local_queue lmq) ; + +/*============================================================================== + * Access functions for mqueue_block fields -- mqb_set_xxx/mqb_get_xxx + * + * Users should not poke around inside the mqueue_block structure. + */ + +Inline void mqb_set_action(mqueue_block mqb, mqueue_action action) ; + +Inline void mqb_set_arg0(mqueue_block mqb, void* p) ; + +extern void mqb_set_argv_size(mqueue_block mqb, unsigned n) ; + +extern void mqb_set_argv_p(mqueue_block mqb, mqb_index_t iv, mqb_ptr_t p) ; +extern void mqb_set_argv_i(mqueue_block mqb, mqb_index_t iv, mqb_int_t i) ; +extern void mqb_set_argv_u(mqueue_block mqb, mqb_index_t iv, mqb_uint_t u) ; + +extern void mqb_push_argv_p(mqueue_block mqb, mqb_ptr_t p) ; +extern void mqb_push_argv_i(mqueue_block mqb, mqb_int_t i) ; +extern void mqb_push_argv_u(mqueue_block mqb, mqb_uint_t u) ; + +extern void mqb_push_argv_array(mqueue_block mqb, unsigned n, void** array) ; + +Inline void mqb_dispatch(mqueue_block mqb, mqb_flag_t flag) ; +Inline void mqb_dispatch_action(mqueue_block mqb) ; +Inline void mqb_dispatch_destroy(mqueue_block mqb) ; + +Inline void* mqb_get_arg0(mqueue_block mqb) ; +Inline void* mqb_get_args(mqueue_block mqb) ; +Inline void* mqb_get_argv(mqueue_block mqb) ; + +Inline mqb_index_t mqb_get_argv_count(mqueue_block mqb) ; + +extern mqb_ptr_t mqb_get_argv_p(mqueue_block mqb, mqb_index_t iv) ; +extern mqb_int_t mqb_get_argv_i(mqueue_block mqb, mqb_index_t iv) ; +extern mqb_uint_t mqb_get_argv_u(mqueue_block mqb, mqb_index_t iv) ; + +extern mqb_ptr_t mqb_next_argv_p(mqueue_block mqb) ; +extern mqb_int_t mqb_next_argv_i(mqueue_block mqb) ; +extern mqb_uint_t mqb_next_argv_u(mqueue_block mqb) ; + +extern void** mqb_pop_argv_array(mqueue_block mqb) ; + +/*============================================================================== + * The Inline functions. + */ + +Inline mqueue_block +mqueue_local_head(mqueue_local_queue lmq) +{ + return lmq->head ; +} ; + +/* Set operations. */ + +Inline void +mqb_set_action(mqueue_block mqb, mqueue_action action) +{ + mqb->action = action ; +} ; + +Inline void +mqb_set_arg0(mqueue_block mqb, void* arg0) +{ + mqb->arg0 = arg0 ; +} ; + +/* Get operations */ + +Inline void +mqb_dispatch(mqueue_block mqb, mqb_flag_t flag) +{ + mqb->action(mqb, flag) ; +} ; + +Inline void +mqb_dispatch_action(mqueue_block mqb) +{ + mqb->action(mqb, mqb_action) ; +} ; + +Inline void +mqb_dispatch_destroy(mqueue_block mqb) +{ + mqb->action(mqb, mqb_destroy) ; +} ; + +Inline void* +mqb_get_arg0(mqueue_block mqb) +{ + return mqb->arg0 ; +} ; + +Inline void* +mqb_get_args(mqueue_block mqb) +{ + return &mqb->args ; +} ; + +Inline void* +mqb_get_argv(mqueue_block mqb) +{ + return mqb->argv ; +} ; + +Inline mqb_index_t +mqb_get_argv_count(mqueue_block mqb) +{ + return mqb->argv_count ; +} ; + +Inline void +mqb_reset_argv_next(mqueue_block mqb) +{ + mqb->argv_next = 0 ; +} ; + +#endif /* _ZEBRA_MQUEUE_H */ |