/ libs / native / queue.c
queue.c
  1  /* -*- mode: c; tab-width: 8 -*-
  2   */
  3  
  4  #include "queue.h"
  5  
  6  bgrt_st_t bgrt_queue_init_cs(bgrt_queue_t *q, uint16_t size, uint16_t flags)
  7  {
  8  	BGRT_ASSERT(q, "#queue must not be NULL");
  9  	BGRT_ASSERT(q->deq, "#queue->deq must not be NULL");
 10  	BGRT_ASSERT(((flags & Q_CS) || q->enq.sem), "#queue->enq.sem must not be NULL");
 11  
 12  	q->size = size -= 1;
 13  	q->flags = flags;
 14  	q->head = q->tail = 0;
 15  	bgrt_sem_init_cs(q->deq, (flags & Q_REV) ? size : 0);
 16  	if ((flags & Q_CS))
 17  		q->enq.counter = size;
 18  	else
 19  		bgrt_sem_init_cs(q->enq.sem, (flags & Q_REV) ? 0 : size);
 20  
 21  	return BGRT_ST_OK;
 22  }
 23  
 24  bgrt_st_t bgrt_queue_init(bgrt_queue_t *q, uint16_t size, uint16_t flags)
 25  {
 26  	bgrt_st_t st;
 27  	BGRT_INT_LOCK();
 28  	st = bgrt_queue_init_cs(q, size, flags);
 29  	BGRT_INT_FREE();
 30  	return st;
 31  }
 32  
 33  /*
 34   *
 35   */
 36  static void * _queue_idx_inc(bgrt_queue_t *q, bool enqueue)
 37  {
 38  	_Atomic(uint16_t) *obj;
 39  	uint16_t idx, next;
 40  
 41  	enqueue ^= !!(q->flags & Q_REV);
 42  	obj = enqueue ? &q->head : &q->tail;
 43  	idx = *obj;
 44  
 45  	do {
 46  		next = (idx + 1) & q->size;
 47  	} while(!atomic_compare_exchange_strong(obj, &idx, next));
 48  
 49  	return &q->queue[idx];
 50  }
 51  
 52  /*
 53   *
 54   */
 55  bgrt_st_t bgrt_queue_post_fn(bgrt_queue_t *q, void *msg,
 56  			     _queue_sem_t sem_lock_fn,
 57  			     _queue_post_cb_t post_cb)
 58  {
 59  	bgrt_st_t st;
 60  	void **p;
 61  
 62  	if ((st = sem_lock_fn(q->enq.sem)) != BGRT_ST_OK)
 63  		return st;
 64  
 65  	p = _queue_idx_inc(q, true);
 66  	if (post_cb)
 67  		post_cb(p, msg);
 68  	else
 69  		*p = msg;
 70  
 71  	return bgrt_sem_free(q->deq);
 72  }
 73  
 74  bgrt_st_t bgrt_queue_post_cs_fn(bgrt_queue_t *q, void *msg,
 75  				_queue_post_cb_t post_cb)
 76  {
 77  	void **p;
 78  
 79  	if (q->enq.counter == 0)
 80  		return BGRT_ST_ROLL;
 81  
 82  	atomic_fetch_sub(&q->enq.counter, 1);
 83  
 84  	p = _queue_idx_inc(q, true);
 85  	if (post_cb)
 86  		post_cb(p, msg);
 87  	else
 88  		*p = msg;
 89  
 90  	return bgrt_sem_free_cs(q->deq);
 91  }
 92  
 93  bgrt_st_t bgrt_queue_fetch_fn(bgrt_queue_t *q, void **msg,
 94  			      _queue_sem_t sem_lock_fn)
 95  {
 96  	bool q_sw = !!(q->flags & Q_SW);
 97  	bool q_cs = !!(q->flags & Q_CS);
 98  	bgrt_st_t st;
 99  	void **p;
100  	void *t;
101  
102  	if ((st = sem_lock_fn(q->deq)) != BGRT_ST_OK)
103  		return st;
104  
105  	p = _queue_idx_inc(q, false);
106  	t = *p;
107  
108  	if (q_sw) *p = *msg;
109  	*msg = t;
110  
111  	return q_cs ?
112  		atomic_fetch_add(&q->enq.counter, 1), BGRT_ST_OK :
113  		bgrt_sem_free(q->enq.sem);
114  }