summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/memtypes.c4
-rw-r--r--lib/mqueue.c433
-rw-r--r--lib/mqueue.h132
3 files changed, 210 insertions, 359 deletions
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 633ca9bb..9479feb2 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -33,8 +33,8 @@ struct memory_list memory_list_lib[] =
{ MTYPE_QPT_MUTEX, "qpt mutex" },
{ MTYPE_QPT_COND, "qpt condition variable" },
{ MTYPE_MQUEUE_QUEUE, "Mqueue queue structure" },
- { MTYPE_MQUEUE_BLOCKS, "Mqueue message blocks" },
- { MTYPE_MQUEUE_BLOCK_EXT, "Mqueue message block extension"},
+ { MTYPE_MQUEUE_BLOCK, "Mqueue message block" },
+ { MTYPE_MQUEUE_BLOCK_ARGV, "Mqueue message block argv" },
{ MTYPE_MQUEUE_THREAD_SIGNAL, "Mqueue thread signal" },
{ MTYPE_QPS_SELECTION, "qpselect selection" },
{ MTYPE_QPS_FILE, "qpselect file" },
diff --git a/lib/mqueue.c b/lib/mqueue.c
index fd0d2678..e1433245 100644
--- a/lib/mqueue.c
+++ b/lib/mqueue.c
@@ -31,7 +31,7 @@
* A message queue carries messages from one or more qpthreads to one or more
* other qpthreads.
*
- * If !qpthreads_enabled, then a message queue hold messages for the program
+ * If !qpthreads_enabled, then a message queue holds messages for the program
* to consume later. There are never any waiters. Timeouts are ignored.
*
* A message queue has one ordinary priority queue and one high priority
@@ -73,39 +73,51 @@
*
* Messages take the form of a small block of information which contain:
*
- * * action -- void action(mqueue_block) message dispatch
- * * arguments -- each a union of: *void/uintptr_t/intptr_t
+ * * action -- void action(mqueue_block) message dispatch
+ * * arg0 -- void* argument
+ * * struct args -- embedded argument structure
+ * * argv -- optional array of union of: *void/uintptr_t/intptr_t
*
* There are set/get functions for action/arguments -- users should not poke
* around inside the structure.
*
- * To send a message, first allocate a message block (see mqb_init_new),
- * then fill in the arguments and enqueue it.
+ * To send a message, first initialise/allocate a message block
+ * (see mqb_init_new), then fill in the arguments and enqueue it.
*
- * The number of arguments is flexible, and the mqb handling looks after
- * the array of same. Note:
- *
- * * arg0 (aka argv[0]) implicitly exists and is implicitly a pointer.
- *
- * This is expected to be used as the "context" for the message.
+ * NB: arg0 is expected to be used as the "context" for the message -- to
+ * point to some data common to both ends of the conversation.
*
* For specific revoke, arg0 is assumed to identify the messages to be
* revoked.
*
- * * arg1 (aka argv[1]) implicitly exists.
+ * NB: the struct args is expected to be a modest sized structure, carrying
+ * the key elements of the message.
+ *
+ * Some other structure must be overlaid on this, in the same way by sender
+ * and receiver of the message. So:
+ *
+ * mqueue_block mqb = mqb_init_new(NULL, arg0, action_func) ;
+ *
+ * struct my_message* args = mqb_get_args(mqb) ;
+ *
+ * allocates mqueue block, filling in arg0 and the action func. Then
+ * args can be used to fill in a "struct my_message" form of args.
*
- * The count of known arguments is, then, always at least 2.
+ * NB: the sizeof(struct my_message) MUST BE <= mqb_args_size_max !!!
*
- * May set any number of arguments, and the count is extended to include the
- * highest index set.
+ * The argv is an optional, flexible list/array of optional array of
+ * union of: *void/uintptr_t/intptr_t -- see mqb_arg_t et al.
+ *
+ * May set any number of arguments in argv.
+ *
+ * A count of arguments is maintained, and is the highest index set + 1. That
+ * count can be fetched. (So there is no need to maintain it separately.)
*
* May get any argument by its index -- but it is a fatal error to attempt to
* access a non-existent argument (one beyond the known count).
*
- * May treat arguments from some index forward as a "list". There is support
- * for pushing values onto the "list" and for iterating along the "list".
- * (But note that there is only one argv[] -- the "list" is not separate and
- * does not have separate indexes.)
+ * There is support for pushing values onto the argv "list" and for iterating
+ * along the "list". May also push and pop entire arrays of items.
*
*==============================================================================
* Local Queues
@@ -113,7 +125,7 @@
* A local queue may be used within a thread to requeue messages for later
* processing.
*
- * Local queues are very simple FIFO queues.
+ * Local queues are simple FIFO queues.
*/
/*==============================================================================
@@ -128,7 +140,7 @@
* For mqt_cond_xxx type queues, sets the default timeout interval and the
* initial timeout time to now + that interval.
*
- * NB: once any message queue has been enabled, it is TOO LATE to enable
+ * NB: once any message queue has been initialised, it is TOO LATE to enable
* qpthreads.
*/
extern mqueue_queue
@@ -197,7 +209,7 @@ mqueue_local_init_new(mqueue_local_queue lmq)
/*------------------------------------------------------------------------------
* Reset Local Message Queue, and if required free it.
*
- * Dequeues entries and dispatches them "mqb_revoke", to empty the queue.
+ * Dequeues entries and dispatches them "mqb_destroy", to empty the queue.
*
* See: mqueue_local_reset_keep(lmq)
* mqueue_local_reset_free(lmq)
@@ -248,34 +260,33 @@ mqueue_set_timeout_interval(mqueue_queue mq, qtime_t interval)
/*==============================================================================
* Message Block memory management.
*
- * Allocates message_block structures in lots of 256. Uses first message_block
- * in each lot to keep track of the lots.
+ * Allocates message block structures when required.
+ *
+ * Places those structures on the free list when they are freed.
+ *
+ * Keeps a count of free structures. (Could at some later date reduce the
+ * number of free structures if it is known that some burst of messages has
+ * now passed.)
*
* mqueue_initialise MUST be called before the first message block is allocated.
*/
static pthread_mutex_t mqb_mutex ;
-#define MQB_LOT_SIZE 256
-
-static mqueue_block mqb_lot_list = NULL ;
-static mqueue_block mqb_free_list = NULL ;
+static mqueue_block mqb_free_list = NULL ;
+static unsigned mqb_free_count = 0 ;
-static mqueue_block mqueue_block_new_lot(void) ;
-
-/*------------------------------------------------------------------------------
- * Size of argv_extension assuming the given *total* number of arguments.
- *
- * NB: expect there to always be >= mqb_argv_static_len arguments allocated.
- */
-static inline size_t
-mqb_extension_size(mqb_index_t arg_have)
+inline static size_t mqb_argv_size(mqb_index_t alloc)
{
- return sizeof(mqb_arg_t) * (arg_have - mqb_argv_static_len) ;
+ return alloc * sizeof(mqb_arg_t) ;
} ;
/*------------------------------------------------------------------------------
* Initialise message block (allocate if required) and set action & arg0.
+ *
+ * Zeroises the struct args.
+ *
+ * Returns address of message block.
*/
extern mqueue_block
mqb_init_new(mqueue_block mqb, mqueue_action action, void* arg0)
@@ -286,31 +297,32 @@ mqb_init_new(mqueue_block mqb, mqueue_action action, void* arg0)
mqb = mqb_free_list ;
if (mqb == NULL)
- mqb = mqueue_block_new_lot() ;
-
- mqb_free_list = mqb->next ;
+ mqb = XMALLOC(MTYPE_MQUEUE_BLOCK, sizeof(struct mqueue_block)) ;
+ else
+ {
+ mqb_free_list = mqb->next ;
+ --mqb_free_count ;
+ } ;
qpt_mutex_unlock(&mqb_mutex) ;
} ;
memset(mqb, 0, sizeof(struct mqueue_block)) ;
- mqb->action = action ;
- mqb->argv[0].p = arg0 ;
-
- mqb->arg_count = 2 ; /* Always arg0 and arg1 (aka argv[0] and argv[1]) */
- mqb->arg_have = mqb_argv_static_len ;
+ mqb->action = action ;
+ mqb->arg0 = arg0 ;
/* Zeroising the mqb sets:
*
* next -- NULL
*
- * argv -- everything zero or NULL
+ * args -- zeroised
*
- * arg_list_base -- no list
- * arg_list_next -- reset
+ * argv -- NULL -- empty list/array
*
- * argv_extension -- NULL -- no extension
+ * argv_count -- 0 -- empty
+ * argv_alloc -- 0 -- nothing allocated
+ * argv_next -- 0 -- iterator reset
*/
return mqb ;
@@ -319,7 +331,7 @@ mqb_init_new(mqueue_block mqb, mqueue_action action, void* arg0)
/*------------------------------------------------------------------------------
* Re-initialise message block (or allocate if required) and set action & arg0.
*
- * NB: preserves any existing extension.
+ * NB: preserves any existing argv, but empties it.
*
* NB: it is the caller's responsibility to free the value of any argument that
* requires it.
@@ -327,24 +339,24 @@ 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)
{
- mqb_index_t arg_have ;
- mqb_arg_t* argv_extension ;
+ mqb_index_t argv_alloc ;
+ mqb_arg_t* argv ;
/* Exactly mqb_init_new if mqb is NULL */
if (mqb == NULL)
return mqb_init_new(NULL, action, arg0) ;
- /* Otherwise, need to put extension to one side first */
- argv_extension = mqb->argv_extension ;
- arg_have = mqb->arg_have ;
+ /* Otherwise, need to put argv to one side first */
+ argv = mqb->argv ;
+ argv_alloc = mqb->argv_alloc ;
mqb_init_new(mqb, action, arg0) ;
- /* Now zeroize the extension, and restore it */
- memset(argv_extension, 0, mqb_extension_size(arg_have)) ;
+ /* Now zeroize the argv, and restore it */
+ memset(argv, 0, mqb_argv_size(argv_alloc)) ;
- mqb->argv_extension = argv_extension ;
- mqb->arg_have = arg_have ;
+ mqb->argv = argv ;
+ mqb->argv_alloc = argv_alloc ;
return mqb ;
} ;
@@ -352,7 +364,7 @@ mqb_re_init(mqueue_block mqb, mqueue_action action, void* arg0)
/*------------------------------------------------------------------------------
* Free message block when done with it.
*
- * Frees an extension argument vector.
+ * Frees any argv argument vector.
*
* NB: it is the caller's responsibility to free the value of any argument that
* requires it.
@@ -360,50 +372,18 @@ mqb_re_init(mqueue_block mqb, mqueue_action action, void* arg0)
extern void
mqb_free(mqueue_block mqb)
{
- if (mqb->argv_extension != NULL)
- XFREE(MTYPE_MQUEUE_BLOCK_EXT, mqb->argv_extension) ;
+ if (mqb->argv != NULL)
+ XFREE(MTYPE_MQUEUE_BLOCK_ARGV, mqb->argv) ;
qpt_mutex_lock(&mqb_mutex) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
mqb->next = mqb_free_list ;
mqb_free_list = mqb ;
+ ++mqb_free_count ;
qpt_mutex_unlock(&mqb_mutex) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
} ;
-/*------------------------------------------------------------------------------
- * Make a new lot of empty message_block structures.
- *
- * NB: caller MUST hold the mqb_mutex.
- */
-static mqueue_block
-mqueue_block_new_lot(void)
-{
- mqueue_block first, last, this ;
-
- mqueue_block new = XCALLOC(MTYPE_MQUEUE_BLOCKS,
- SIZE(struct mqueue_block, MQB_LOT_SIZE)) ;
- first = &new[1] ;
- last = &new[MQB_LOT_SIZE - 1] ;
-
- new->next = mqb_lot_list ; /* add to list of lots */
- mqb_lot_list = new ;
-
- /* String all the new message_blocks together. */
- this = last ;
- while (this > first)
- {
- mqueue_block prev = this-- ;
- this->next = prev ;
- } ;
- assert(this == first) ;
-
- last->next = mqb_free_list ; /* point last at old free list */
- mqb_free_list = first ; /* new blocks at head of free list */
-
- return mqb_free_list ;
-} ;
-
/*==============================================================================
* Enqueue and dequeue messages.
*/
@@ -791,17 +771,14 @@ static void mqb_argv_extend(mqueue_block mqb, mqb_index_t iv) ;
inline static mqb_arg_t*
mqb_p_arg_set(mqueue_block mqb, mqb_index_t iv)
{
- if (iv >= mqb->arg_count)
+ if (iv >= mqb->argv_count)
{
- if (iv >= mqb->arg_have)
+ if (iv >= mqb->argv_alloc)
mqb_argv_extend(mqb, iv) ;
- mqb->arg_count = iv + 1 ;
+ mqb->argv_count = iv + 1 ;
} ;
- if (iv < mqb_argv_static_len)
- return &mqb->argv[iv] ;
- else
- return &mqb->argv_extension[iv - mqb_argv_static_len] ;
+ return &mqb->argv[iv] ;
} ;
/*------------------------------------------------------------------------------
@@ -835,102 +812,74 @@ mqb_set_argv_u(mqueue_block mqb, mqb_index_t iv, mqb_uint_t u)
} ;
/*------------------------------------------------------------------------------
- * Set start of "list" part of argv[] to be the given iv (must be > 0 !).
+ * Set size of argv[].
+ *
+ * This is entirely optional, and may be used to ensure that at least the given
+ * number of elements have been allocated.
+ *
+ * Does not change the "count". Will not reduce the allocated size.
+ *
+ * Just avoids repeated extensions of argv if it is known that it will become
+ * large.
*/
extern void
-mqb_set_argv_list(mqueue_block mqb, mqb_index_t iv)
+mqb_set_argv_size(mqueue_block mqb, unsigned n)
{
- assert(iv > 0) ;
-
- mqb->arg_list_base = iv ;
-
- /* If there is a gap between the existing items and the start of the */
- /* "list", then fill in upto the start of the "list" */
- if (iv > mqb->arg_count)
- mqb_set_argv_p(mqb, iv - 1, NULL) ;
+ if (n > mqb->argv_alloc)
+ mqb_argv_extend(mqb, n - 1) ;
} ;
/*------------------------------------------------------------------------------
- * Push a pointer onto the "list"
- *
- * Implicitly starts list if not set by mqb_set_argv_list(), setting to
- * just past the last argument set -- noting that arg0 and arg1 are implicitly
- * set.
+ * Push a pointer onto the argv "list"
*/
extern void
mqb_push_argv_p(mqueue_block mqb, mqb_ptr_t p)
{
mqb_arg_t* p_arg ;
- if (mqb->arg_list_base == 0)
- mqb->arg_list_base = mqb->arg_count ;
-
- p_arg = mqb_p_arg_set(mqb, mqb->arg_count) ;
+ p_arg = mqb_p_arg_set(mqb, mqb->argv_count) ;
p_arg->p = p ;
} ;
/*------------------------------------------------------------------------------
- * Push an integer onto the "list"
- *
- * Implicitly starts list if not set by mqb_set_argv_list(), setting to
- * just past the last argument set -- noting that arg0 and arg1 are implicitly
- * set.
+ * Push an integer onto the argv "list"
*/
extern void
mqb_push_argv_i(mqueue_block mqb, mqb_int_t i)
{
mqb_arg_t* p_arg ;
- if (mqb->arg_list_base == 0)
- mqb->arg_list_base = mqb->arg_count ;
-
- p_arg = mqb_p_arg_set(mqb, mqb->arg_count) ;
+ p_arg = mqb_p_arg_set(mqb, mqb->argv_count) ;
p_arg->i = i ;
} ;
/*------------------------------------------------------------------------------
- * Push an unsigned integer onto the "list"
- *
- * Implicitly starts list if not set by mqb_set_argv_list(), setting to
- * just past the last argument set -- noting that arg0 and arg1 are implicitly
- * set.
+ * Push an unsigned integer onto the argv "list"
*/
extern void
mqb_push_argv_u(mqueue_block mqb, mqb_uint_t u)
{
mqb_arg_t* p_arg ;
- if (mqb->arg_list_base == 0)
- mqb->arg_list_base = mqb->arg_count ;
-
- p_arg = mqb_p_arg_set(mqb, mqb->arg_count) ;
+ p_arg = mqb_p_arg_set(mqb, mqb->argv_count) ;
p_arg->u = u ;
} ;
/*------------------------------------------------------------------------------
- * Push an array of 'n' void* pointers
- *
- * Implicitly starts list if not set by mqb_set_argv_list(), setting to
- * just past the last argument set -- noting that arg0 and arg1 are implicitly
- * set.
+ * Push an array of 'n' void* pointers onto the argv "list"
*/
extern void
mqb_push_argv_array(mqueue_block mqb, unsigned n, void** array)
{
- mqb_arg_t* p_arg ;
- unsigned m ;
-
- mqb_index_t iv = mqb->arg_count ;
-
- if (mqb->arg_list_base == 0)
- mqb->arg_list_base = iv ;
+ mqb_index_t iv ;
- /* need do nothing more if n == 0, get out now to avoid edge cases */
+ /* need do nothing if n == 0, get out now to avoid edge cases */
if (n == 0)
return ;
/* make sure we are allocated upto and including the last array item */
- p_arg = mqb_p_arg_set(mqb, iv + n - 1) ;
+ iv = mqb->argv_count ;
+ mqb_set_argv_size(mqb, iv + n - 1) ;
/* require that mqb_ptr_t values exactly fill mqb_arg_t entries */
/* and that mqb_ptr_t values are exactly same as void* values */
@@ -938,25 +887,7 @@ mqb_push_argv_array(mqueue_block mqb, unsigned n, void** array)
CONFIRM(sizeof(mqb_ptr_t) == sizeof(void*)) ;
/* copy the pointers */
- p_arg = mqb_p_arg_set(mqb, iv) ; /* get address for first item */
-
- if (iv < mqb_argv_static_len)
- {
- m = mqb_argv_static_len - iv ; /* deal with static part */
- if (n < m)
- m = n ;
-
- memcpy(p_arg, array, sizeof(void*) * m) ;
-
- n -= m ;
- if (n == 0)
- return ; /* quit now if done everything */
-
- array += m ; /* advance past stuff copied */
- p_arg = mqb->argv_extension ; /* rest goes in the extension */
- } ;
-
- memcpy(p_arg, array, sizeof(void*) * n) ;
+ memcpy(&mqb->argv[iv], array, sizeof(void*) * n) ;
} ;
/*------------------------------------------------------------------------------
@@ -967,13 +898,10 @@ mqb_push_argv_array(mqueue_block mqb, unsigned n, void** array)
inline static mqb_arg_t*
mqb_p_arg_get(mqueue_block mqb, mqb_index_t iv)
{
- if (iv >= mqb->arg_count)
+ if (iv >= mqb->argv_count)
zabort("invalid message block argument index") ;
- if (iv < mqb_argv_static_len)
- return &mqb->argv[iv] ;
- else
- return &mqb->argv_extension[iv - mqb_argv_static_len] ;
+ return &mqb->argv[iv] ;
} ;
/*------------------------------------------------------------------------------
@@ -981,10 +909,7 @@ mqb_p_arg_get(mqueue_block mqb, mqb_index_t iv)
*
* NB: it is a FATAL error to reference an argument beyond the last one set.
*
- * arg0 and arg1 are implicitly set.
- *
- * mqb_get_arg_count() returns the number of arguments set, including any
- * "list" part.
+ * mqb_get_argv_count() returns the number of arguments set in argv.
*/
extern mqb_ptr_t
mqb_get_argv_p(mqueue_block mqb, mqb_index_t iv)
@@ -998,10 +923,7 @@ mqb_get_argv_p(mqueue_block mqb, mqb_index_t iv)
*
* NB: it is a FATAL error to reference an argument beyond the last one set.
*
- * arg0 and arg1 are implicitly set.
- *
- * mqb_get_arg_count() returns the number of arguments set, including any
- * "list" part.
+ * mqb_get_argv_count() returns the number of arguments set in argv.
*/
extern mqb_int_t
mqb_get_argv_i(mqueue_block mqb, mqb_index_t iv)
@@ -1015,10 +937,7 @@ mqb_get_argv_i(mqueue_block mqb, mqb_index_t iv)
*
* NB: it is a FATAL error to reference an argument beyond the last one set.
*
- * arg0 and arg1 are implicitly set.
- *
- * mqb_get_arg_count() returns the number of arguments set, including any
- * "list" part.
+ * mqb_get_argv_count() returns the number of arguments set in argv.
*/
extern mqb_uint_t
mqb_get_argv_u(mqueue_block mqb, mqb_index_t iv)
@@ -1028,101 +947,61 @@ mqb_get_argv_u(mqueue_block mqb, mqb_index_t iv)
} ;
/*------------------------------------------------------------------------------
- * Get iv for the first argument in the "list" portion (if any).
- *
- * Returns: 0 => no list portion
- * iv 1..n: can be used to access the "list" portion using
- * mqb_get_argv_x(). BUT, watch out for empty lists !
- */
-extern mqb_index_t
-mqb_get_argv_list_base(mqueue_block mqb)
-{
- return mqb->arg_list_base ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Get the number of arguments in the "list" portion (if any).
- *
- * Returns: 0 => no or empty list portion
- *
- * Resets the "next" counter -- see mqb_next_argv_x() below.
- */
-extern mqb_index_t
-mqb_get_argv_list_count(mqueue_block mqb)
-{
- mqb->arg_list_next = 0 ;
- return (mqb->arg_list_base == 0) ? 0 : mqb->arg_count - mqb->arg_list_base ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Get pointer value of next "list" argument -- if any.
+ * Get pointer value of next argv "list" argument -- if any.
*
* There is a "next" counter in the message queue block, which is reset when
- * the mqb is initialised or re-initialised, and when mqb_get_list_count() is
- * called.
+ * the mqb is initialised or re-initialised, and by mqb_reset_argv_next().
*
* NB: returns NULL if there is no "list" or if already at the end of same.
*/
extern mqb_ptr_t
mqb_next_argv_p(mqueue_block mqb)
{
- if (mqb->arg_list_next == 0)
- mqb->arg_list_next = mqb->arg_list_base ;
-
- if ((mqb->arg_list_base == 0) || (mqb->arg_list_next >= mqb->arg_count))
+ if (mqb->argv_next >= mqb->argv_count)
return NULL ;
- return mqb_get_argv_p(mqb, mqb->arg_list_next++) ;
+ return mqb_get_argv_p(mqb, mqb->argv_next++) ;
} ;
/*------------------------------------------------------------------------------
- * Get integer value of next "list" argument -- if any.
+ * Get integer value of next argv "list" argument -- if any.
*
* There is a "next" counter in the message queue block, which is reset when
- * the mqb is initialised or re-initialised, and when mqb_get_list_count() is
- * called.
+ * the mqb is initialised or re-initialised, and by mqb_reset_argv_next().
*
* NB: returns 0 if there is no "list" or if already at the end of same.
*/
extern mqb_int_t
mqb_next_argv_i(mqueue_block mqb)
{
- if (mqb->arg_list_next == 0)
- mqb->arg_list_next = mqb->arg_list_base ;
-
- if ((mqb->arg_list_base == 0) || (mqb->arg_list_next >= mqb->arg_count))
+ if (mqb->argv_next >= mqb->argv_count)
return 0 ;
- return mqb_get_argv_i(mqb, mqb->arg_list_next++) ;
+ return mqb_get_argv_i(mqb, mqb->argv_next++) ;
} ;
/*------------------------------------------------------------------------------
- * Get unsigned integer value of next "list" argument -- if any.
+ * Get unsigned integer value of next argv "list" argument -- if any.
*
* There is a "next" counter in the message queue block, which is reset when
- * the mqb is initialised or re-initialised, and when mqb_get_list_count() is
- * called.
+ * the mqb is initialised or re-initialised, and by mqb_reset_argv_next().
*
* NB: returns 0 if there is no "list" or if already at the end of same.
*/
extern mqb_uint_t
mqb_next_argv_u(mqueue_block mqb)
{
- if (mqb->arg_list_next == 0)
- mqb->arg_list_next = mqb->arg_list_base ;
-
- if ((mqb->arg_list_base == 0) || (mqb->arg_list_next >= mqb->arg_count))
+ if (mqb->argv_next >= mqb->argv_count)
return 0 ;
- return mqb_get_argv_u(mqb, mqb->arg_list_next++) ;
+ return mqb_get_argv_u(mqb, mqb->argv_next++) ;
} ;
/*------------------------------------------------------------------------------
- * Pop an array of 'n' void* pointers
+ * Pop an array of 'n' void* pointers from the argv "list"
*
* There is a "next" counter in the message queue block, which is reset when
- * the mqb is initialised or re-initialised, and when mqb_get_list_count() is
- * called.
+ * the mqb is initialised or re-initialised, and by mqb_reset_argv_next().
*
* Treats from "next" to the end of the "list" as an array of void* pointers.
*
@@ -1134,23 +1013,18 @@ extern void**
mqb_pop_argv_array(mqueue_block mqb)
{
void** array ;
- void** p_item ;
- unsigned n, m ;
- mqb_index_t iv ;
- mqb_arg_t* p_arg ;
+ unsigned n ;
- /* worry about state of "next" and get out if nothing to do. */
- if (mqb->arg_list_next == 0)
- mqb->arg_list_next = mqb->arg_list_base ;
+ mqb_index_t iv = mqb->argv_next ;
- if ((mqb->arg_list_base == 0) || (mqb->arg_list_next >= mqb->arg_count))
+ /* worry about state of "next" and get out if nothing to do. */
+ if (iv >= mqb->argv_count)
return NULL ;
- /* work out what we are popping and update "next" */
- iv = mqb->arg_list_next ;
- n = mqb->arg_count - iv ;
+ /* work out how much to pop and update "next" */
+ n = mqb->argv_count - iv ;
- mqb->arg_list_next = mqb->arg_count ;
+ mqb->argv_next = mqb->argv_count ;
/* construct target array */
array = XMALLOC(MTYPE_TMP, sizeof(void*) * n) ;
@@ -1161,25 +1035,7 @@ mqb_pop_argv_array(mqueue_block mqb)
CONFIRM(sizeof(mqb_ptr_t) == sizeof(void*)) ;
/* now transfer pointers to the array */
- p_item = array ; /* address for first item */
- p_arg = mqb_p_arg_get(mqb, iv) ; /* get address of first item */
-
- if (iv < mqb_argv_static_len)
- {
- m = mqb_argv_static_len - iv ;
- if (n < m)
- m = n ;
- memcpy(p_item, p_arg, sizeof(void*) * m) ;
-
- n -= m ; /* count down */
- if (n == 0)
- return array ; /* all done */
-
- p_item += m ; /* step past copied stuff */
- p_arg = mqb->argv_extension ; /* rest from the extension */
- } ;
-
- memcpy(p_item, p_arg, sizeof(void*) * n) ;
+ memcpy(array, mqb->argv + iv, sizeof(void*) * n) ;
return array ;
} ;
@@ -1187,8 +1043,8 @@ mqb_pop_argv_array(mqueue_block mqb)
/*------------------------------------------------------------------------------
* Extend the argv to include at least given iv.
*
- * The number of argv slots available is arranged to be a multiple of
- * mqb_argv_static_len.
+ * The number of argv slots allocated is arranged to be a multiple of
+ * mqb_argv_size_unit.
*
* Ensures that newly created slots are zeroised.
*/
@@ -1196,26 +1052,23 @@ static void
mqb_argv_extend(mqueue_block mqb, mqb_index_t iv)
{
mqb_index_t need ; /* total slots required */
- size_t new_size, old_size ; /* sizes of the extension part */
+ mqb_index_t have ;
- assert(mqb->arg_have >= mqb_argv_static_len) ;
- assert(mqb->arg_have <= iv) ;
+ have = mqb->argv_alloc ;
+ assert(have <= iv) ;
- need = ((iv / mqb_argv_static_len) + 1) * mqb_argv_static_len ;
- new_size = mqb_extension_size(need) ;
+ need = ((iv / mqb_argv_size_unit) + 1) * mqb_argv_size_unit ;
- if (mqb->argv_extension == NULL)
- mqb->argv_extension = XCALLOC(MTYPE_MQUEUE_BLOCK_EXT, new_size) ;
+ if (mqb->argv == NULL)
+ mqb->argv = XCALLOC(MTYPE_MQUEUE_BLOCK_ARGV, mqb_argv_size(need)) ;
else
{
- mqb->argv_extension = XREALLOC(MTYPE_MQUEUE_BLOCK_EXT,
- mqb->argv_extension, new_size) ;
-
- old_size = mqb_extension_size(mqb->arg_have) ;
- memset(mqb->argv_extension + old_size, 0, new_size - old_size) ;
+ mqb->argv = XREALLOC(MTYPE_MQUEUE_BLOCK_ARGV, mqb->argv,
+ mqb_argv_size(need)) ;
+ memset(&mqb->argv[have], 0, mqb_argv_size(need - have)) ;
} ;
- mqb->arg_have = need ;
+ mqb->argv_alloc = need ;
} ;
/*==============================================================================
diff --git a/lib/mqueue.h b/lib/mqueue.h
index 5d00b726..32ac599e 100644
--- a/lib/mqueue.h
+++ b/lib/mqueue.h
@@ -36,15 +36,25 @@
*
* * action -- function to call when message is dispatched
*
- * * argv -- arguments: each may be pointer or signed/unsigned integer
+ * * arg0 -- always a pointer -- used in specific revoke
*
- * argv[0] (aka arg0) always exists, and is always a pointer
- * argv[1] (aka arg1) always exists
+ * * args -- embedded structure -- to be overlaid by user structure
*
- * May have any number of arguments.
+ * * argv -- pointer to: list/array of pointer/integer/unsigned
*
- * May treat all arguments from some specified point onwards
- * as a "list" which may be pushed onto and iterated along.
+ * 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 ;
@@ -62,6 +72,12 @@ typedef union
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,
@@ -72,29 +88,37 @@ typedef enum mqb_flag mqb_flag_t ;
typedef void mqueue_action(mqueue_block mqb, mqb_flag_t flag) ;
-enum {
- mqb_argv_static_len = 6 /* max args without extension */
+enum { mqb_args_size_max = 64 } ; /* maximum size of struct args */
+enum { mqb_argv_size_unit = 16 } ; /* allocate argv in these units */
+
+struct args
+{
+ char data[mqb_args_size_max] ; /* empty space */
} ;
struct mqueue_block
{
+ struct args args ; /* user structure */
+
mqueue_block next ; /* single linked list */
mqueue_action* action ; /* for message dispatch */
- mqb_arg_t argv[mqb_argv_static_len] ;
-
- mqb_index_t arg_count ; /* >= 2 (includes any "list") */
- mqb_index_t arg_list_base ; /* start of "list" 0 => none */
- mqb_index_t arg_list_next ; /* iterator */
+ void* arg0 ;
+ mqb_arg_t* argv ; /* argv, if any */
- mqb_index_t arg_have ; /* *total* arguments allocated */
- /* >= mqb_argv_static_len */
-
- mqb_arg_t* argv_extension ; /* extension 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 ! */
+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 ;
@@ -170,9 +194,6 @@ mqueue_init_new(mqueue_queue mq, enum mqueue_queue_type type) ;
extern mqueue_local_queue
mqueue_local_init_new(mqueue_local_queue lmq) ;
-extern mqueue_block
-mqb_re_init(mqueue_block mqb, mqueue_action action, void* arg0) ;
-
extern mqueue_local_queue
mqueue_local_reset(mqueue_local_queue lmq, int free_structure) ;
@@ -188,6 +209,9 @@ mqueue_thread_signal_init(mqueue_thread_signal mqt, qpt_thread_t thread,
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) ;
@@ -215,39 +239,31 @@ mqueue_local_dequeue(mqueue_local_queue lmq) ;
Inline void mqb_set_action(mqueue_block mqb, mqueue_action action) ;
Inline void mqb_set_arg0(mqueue_block mqb, void* p) ;
-Inline void mqb_set_arg1_p(mqueue_block mqb, mqb_ptr_t p) ;
-Inline void mqb_set_arg1_i(mqueue_block mqb, mqb_int_t i) ;
-Inline void mqb_set_arg1_u(mqueue_block mqb, mqb_uint_t u) ;
+
+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_set_argv_list(mqueue_block mqb, mqb_index_t iv) ;
-
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 mqb_index_t mqb_get_arg_count(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 void* mqb_get_arg0(mqueue_block mqb) ;
-Inline mqb_ptr_t mqb_get_arg1_p(mqueue_block mqb) ;
-Inline mqb_int_t mqb_get_arg1_i(mqueue_block mqb) ;
-Inline mqb_uint_t mqb_get_arg1_u(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_index_t mqb_get_argv_list_base(mqueue_block mqb) ;
-extern mqb_index_t mqb_get_argv_list_count(mqueue_block mqb) ;
-
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) ;
@@ -269,25 +285,7 @@ mqb_set_action(mqueue_block mqb, mqueue_action action)
Inline void
mqb_set_arg0(mqueue_block mqb, void* arg0)
{
- mqb->argv[0].p = arg0 ;
-} ;
-
-Inline void
-mqb_set_arg1_p(mqueue_block mqb, mqb_ptr_t p)
-{
- mqb->argv[1].p = p ;
-} ;
-
-Inline void
-mqb_set_arg1_i(mqueue_block mqb, mqb_int_t i)
-{
- mqb->argv[1].i = i ;
-} ;
-
-Inline void
-mqb_set_arg1_u(mqueue_block mqb, mqb_uint_t u)
-{
- mqb->argv[1].u = u ;
+ mqb->arg0 = arg0 ;
} ;
/* Get operations */
@@ -310,34 +308,34 @@ mqb_dispatch_destroy(mqueue_block mqb)
mqb->action(mqb, mqb_destroy) ;
} ;
-Inline mqb_index_t
-mqb_get_arg_count(mqueue_block mqb)
+Inline void*
+mqb_get_arg0(mqueue_block mqb)
{
- return mqb->arg_count ; /* count includes any "list" portion */
+ return mqb->arg0 ;
} ;
Inline void*
-mqb_get_arg0(mqueue_block mqb)
+mqb_get_args(mqueue_block mqb)
{
- return mqb->argv[0].p ;
+ return &mqb->args ;
} ;
-Inline mqb_ptr_t
-mqb_get_arg1_p(mqueue_block mqb)
+Inline void*
+mqb_get_argv(mqueue_block mqb)
{
- return mqb->argv[1].p ;
+ return mqb->argv ;
} ;
-Inline mqb_int_t
-mqb_get_arg1_i(mqueue_block mqb)
+Inline mqb_index_t
+mqb_get_argv_count(mqueue_block mqb)
{
- return mqb->argv[1].i ;
+ return mqb->argv_count ;
} ;
-Inline mqb_uint_t
-mqb_get_arg1_u(mqueue_block mqb)
+Inline void
+mqb_reset_argv_next(mqueue_block mqb)
{
- return mqb->argv[1].u ;
+ mqb->argv_next = 0 ;
} ;
#endif /* _ZEBRA_MQUEUE_H */