Listing 4
#if 0 /* REQUIRED DEFINITIONS */ #define MPOOLQ_CELL_T int /* some signed type */ #endif #include "circ_arr.h" typedef struct { MPOOLQ_CELL_T *base, *end; union { volatile MPOOLQ_CELL_T * volatile w; volatile MPOOLQ_CELL_T * volatile const r; volatile MPOOLQ_CELL_T * const l; } head, tail; int size; } MPOOLQ_T; #ifndef MPOOLQ_USER_T #define MPOOLQ_USER_T char #endif #define MPOOLQ_UUS_PER_CELL \ (sizeof (MPOOLQ_CELL_T) / sizeof (MPOOLQ_USER_T)) #define MPOOLQ_UU_TO_CELLS( n ) (((n)+1) / MPOOLQ_UUS_PER_CELL) #define MPOOLQ_CELLS_TO_UU( n ) ((n) * MPOOLQ_UUS_PER_CELL) #define MPOOLQ_BLK_SIZE( blk ) \ (((volatile MPOOLQ_CELL_T *) (blk)) [-1]) /* Producers (allocator and related functions) */ #define MPOOLQ_CREATE_HOLE( p, ctail ) ( \ (ctail) [0] = -((p)->end - (ctail)), \ (p)->tail.w = (p)->base \ ) static inline void *mpoolq_alloc (MPOOLQ_T *p, MPOOLQ_CELL_T UUs) { MPOOLQ_CELL_T cells = MPOOLQ_UU_TO_CELLS (UUs); volatile MPOOLQ_CELL_T *head = p->head.r, *old_tail = p->tail.l; volatile MPOOLQ_CELL_T *end = old_tail + cells + 1; if (end >= head) { if (head > old_tail) return NULL; else { if (! (end < p->end || (end == p->end && head != p->base))) { /* actually wrap around */ if ((end = p->base + cells + 1) >= head) return NULL; old_tail = MPOOLQ_CREATE_HOLE (p, old_tail); end = old_tail + cells + 1; } } } *old_tail = UUs; p->tail.w = CIRC_ARR_WRAP_END (end, p->base, p->end); return (void *) (1 + old_tail); } static inline MPOOLQ_CELL_T mpoolq_lavail_cells (MPOOLQ_T *p) { volatile MPOOLQ_CELL_T *head = p->head.r, *tail = p->tail.l; if (tail + 1 == p->end) { if (head == p->base) return 0; tail = MPOOLQ_CREATE_HOLE (p, tail); } return CIRC_ARR_DS_LAVAIL (p->base, p->end, head, tail, p->size); } /* Consumers */ /* changes *blk to the address of the next allocated block, if any, or the tail ptr; returns TRUE if a block was found */ static inline BOOL mpoolq_next_blk (const MPOOLQ_T *p, MPOOLQ_CELL_T **blk) { MPOOLQ_CELL_T n; for (;; *blk = CIRC_ARR_WRAP_END (*blk+n, p->base, p->end)) { if (*blk == p->tail.r) return FALSE; if ((n = - (*blk) [0]) <= 0) return TRUE; } } static inline BOOL mpoolq_empty (MPOOLQ_T *p) { MPOOLQ_CELL_T *blk = (MPOOLQ_CELL_T *) p->head.l; BOOL empty = mpoolq_next_blk (p, &blk); p->head.w = blk; return empty; } #define MPOOLQ_OLDEST( p ) \ (mpoolq_empty (p) ? NULL : (void *) (p)->head.l + 1) static inline void mpoolq_free (MPOOLQ_T *p, void *blk) { MPOOLQ_BLK_SIZE (blk) = - MPOOLQ_BLK_CELLS (blk) - 1; mpoolq_empty (p); /* calls mpoolq_next_blk() */ }