librfn
An ad-hoc utility library
messageq.c
Go to the documentation of this file.
1 /*
2  * messageq.c
3  *
4  * Part of librfn (a general utility library from redfelineninja.org.uk)
5  *
6  * Copyright (C) 2013 Daniel Thompson <daniel@redfelineninja.org.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published
10  * by the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  */
13 
14 #include "librfn/messageq.h"
15 
16 #include <assert.h>
17 #include <string.h>
18 
19 #include "librfn/util.h"
20 
21 void messageq_init(messageq_t *mq, void *basep, size_t base_len, size_t msg_len)
22 {
23  memset(mq, 0, sizeof(*mq));
24 
25  mq->basep = basep;
26  mq->msg_len = msg_len;
27  mq->queue_len = base_len / msg_len;
28  atomic_store(&mq->num_free, base_len / msg_len);
29 }
30 
32 {
33  /* get permission to allocate a message */
34  int num_free = atomic_fetch_sub(&mq->num_free, 1);
35  if (num_free <= 0) {
36  atomic_fetch_add(&mq->num_free, 1);
37  return NULL;
38  }
39 
40  /* find out the address that will be allocated */
41  unsigned char sendp = atomic_load(&mq->sendp);
42  unsigned char newsendp;
43  do {
44  newsendp = (sendp >= (mq->queue_len-1) ? 0 : sendp+1);
45  } while(!atomic_compare_exchange_weak(&mq->sendp, &sendp, newsendp));
46 
47  return mq->basep + (sendp * mq->msg_len);
48 }
49 
50 void messageq_send(messageq_t *mq, void *msg)
51 {
52  unsigned int offset = (((char *) msg) - mq->basep);
53  unsigned int sendp = offset / mq->msg_len;
54  atomic_fetch_or(&mq->full_flags, (1 << sendp));
55 }
56 
58 {
59  unsigned int receivep = mq->receivep;
60  unsigned int full_flags = atomic_fetch_and(
61  &mq->full_flags, ~(1 << receivep));
62 
63  if (0 == (full_flags & (1 << receivep)))
64  return NULL;
65 
66  mq->receivep =
67  (receivep >= (unsigned int)(mq->queue_len - 1) ? 0 : receivep + 1);
68 
69  return mq->basep + (receivep * mq->msg_len);
70 
71 }
72 
73 void messageq_release(messageq_t *mq, void *msg)
74 {
75  /* msg is part of the API to allow automatic checking that messages are
76  * always released (and therefore received) in strict order. However
77  * that is not yet implemented.
78  */
79  (void)msg;
80  atomic_fetch_add(&mq->num_free, 1);
81 }
void messageq_init(messageq_t *mq, void *basep, size_t base_len, size_t msg_len)
Definition: messageq.c:21
char * basep
Definition: messageq.h:42
void messageq_release(messageq_t *mq, void *msg)
Definition: messageq.c:73
atomic_uchar num_free
Definition: messageq.h:46
void * messageq_claim(messageq_t *mq)
Definition: messageq.c:31
atomic_uint full_flags
Definition: messageq.h:48
void * messageq_receive(messageq_t *mq)
Definition: messageq.c:57
unsigned char receivep
Definition: messageq.h:50
unsigned char queue_len
Definition: messageq.h:44
void messageq_send(messageq_t *mq, void *msg)
Definition: messageq.c:50
uint16_t msg_len
Definition: messageq.h:43
atomic_uchar sendp
Definition: messageq.h:47