All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cbuff.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * @file cbuff.c
19  * @brief Implementation of a ring buffer
20  *
21  * @copyright 2013 The FreeRADIUS server project
22  * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23  */
24 RCSID("$Id: 45d42f5414f349f60dcc5e9f577d4215c3593415 $")
25 
26 #include <freeradius-devel/libradius.h>
27 
28 #ifdef HAVE_PTHREAD_H
29 # define PTHREAD_MUTEX_LOCK(_x) if (_x->lock) pthread_mutex_lock(&((_x)->mutex))
30 # define PTHREAD_MUTEX_UNLOCK(_x) if (_x->lock) pthread_mutex_unlock(&((_x)->mutex))
31 #else
32 # define PTHREAD_MUTEX_LOCK(_x)
33 # define PTHREAD_MUTEX_UNLOCK(_x)
34 #endif
35 
36 /** Standard thread safe circular buffer
37  *
38  */
39 struct fr_cbuff {
40  void const *end; //!< End of allocated memory
41 
42  uint32_t size;
43  uint32_t in; //!< Write index
44  uint32_t out; //!< Read index
45 
46  void **elem; //!< Ring buffer data
47 
48  bool lock; //!< Perform thread synchronisation
49 #ifdef HAVE_PTHREAD_H
50  pthread_mutex_t mutex; //!< Thread synchronisation mutex
51 #endif
52 };
53 
54 /** Initialise a new circular buffer
55  *
56  * @param ctx to allocate the buffer in.
57  * @param size of buffer to allocate.
58  * @param lock If true, insert and next operations will lock the buffer.
59  * @return
60  * - New cbuff.
61  * - NULL on error.
62  */
63 #ifdef HAVE_PTHREAD_H
64 fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock)
65 #else
66 fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, UNUSED bool lock)
67 #endif
68 {
69  fr_cbuff_t *cbuff;
70 
71  uint32_t pow;
72 
73  /*
74  * Find the nearest power of 2 (rounding up)
75  */
76  for (pow = 0x00000001;
77  pow < size;
78  pow <<= 1);
79  size = pow;
80  size--;
81 
82  cbuff = talloc_zero(ctx, fr_cbuff_t);
83  if (!cbuff) {
84  return NULL;
85  }
86  cbuff->elem = talloc_zero_array(cbuff, void *, size);
87  if (!cbuff->elem) {
88  return NULL;
89  }
90  cbuff->size = size;
91 
92 #ifdef HAVE_PTHREAD_H
93  if (lock) {
94  cbuff->lock = true;
95  pthread_mutex_init(&cbuff->mutex, NULL);
96  }
97 #endif
98  return cbuff;
99 }
100 
101 /** Insert a new element into the buffer, and steal it from it's original context
102  *
103  * cbuff will steal obj and insert it into it's own context.
104  *
105  * @param cbuff to insert element into
106  * @param obj to insert, must of been allocated with talloc
107  */
108 void fr_cbuff_rp_insert(fr_cbuff_t *cbuff, void *obj)
109 {
110  PTHREAD_MUTEX_LOCK(cbuff);
111 
112  if (cbuff->elem[cbuff->in]) {
113  TALLOC_FREE(cbuff->elem[cbuff->in]);
114  }
115 
116  cbuff->elem[cbuff->in] = talloc_steal(cbuff, obj);
117 
118  cbuff->in = (cbuff->in + 1) & cbuff->size;
119 
120  /* overwrite - out is advanced ahead of in */
121  if (cbuff->in == cbuff->out) {
122  cbuff->out = (cbuff->out + 1) & cbuff->size;
123  }
124 
125  PTHREAD_MUTEX_UNLOCK(cbuff);
126 }
127 
128 /** Remove an item from the buffer, and reparent to ctx
129  *
130  * @param cbuff to remove element from
131  * @param ctx to hang obj off.
132  * @return
133  * - NULL if no elements in the buffer.
134  * - An element from the buffer reparented to ctx.
135  */
136 void *fr_cbuff_rp_next(fr_cbuff_t *cbuff, TALLOC_CTX *ctx)
137 {
138  void *obj = NULL;
139 
140  PTHREAD_MUTEX_LOCK(cbuff);
141 
142  /* Buffer is empty */
143  if (cbuff->out == cbuff->in) goto done;
144 
145  obj = talloc_steal(ctx, cbuff->elem[cbuff->out]);
146  cbuff->out = (cbuff->out + 1) & cbuff->size;
147 
148 done:
149  PTHREAD_MUTEX_UNLOCK(cbuff);
150 
151  return obj;
152 }
bool lock
Perform thread synchronisation.
Definition: cbuff.c:48
#define pthread_mutex_init(_x, _y)
Definition: rlm_eap.h:75
void fr_cbuff_rp_insert(fr_cbuff_t *cbuff, void *obj)
Insert a new element into the buffer, and steal it from it's original context.
Definition: cbuff.c:108
#define UNUSED
Definition: libradius.h:134
void * fr_cbuff_rp_next(fr_cbuff_t *cbuff, TALLOC_CTX *ctx)
Remove an item from the buffer, and reparent to ctx.
Definition: cbuff.c:136
#define PTHREAD_MUTEX_LOCK(_x)
Definition: cbuff.c:32
uint32_t in
Write index.
Definition: cbuff.c:43
static bool done
Definition: radclient.c:53
#define PTHREAD_MUTEX_UNLOCK(_x)
Definition: cbuff.c:33
uint32_t size
Definition: cbuff.c:42
fr_cbuff_t * fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, UNUSED bool lock)
Initialise a new circular buffer.
Definition: cbuff.c:66
uint32_t out
Read index.
Definition: cbuff.c:44
Standard thread safe circular buffer.
Definition: cbuff.c:39
void const * end
End of allocated memory.
Definition: cbuff.c:40
#define RCSID(id)
Definition: build.h:135
void ** elem
Ring buffer data.
Definition: cbuff.c:46