The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
fring.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/** Implementation of a circular buffer with fixed element size
18 *
19 * This offers similar functionality to ring_buffer.c, but uses a fixed
20 * element size, and expects all elements to be talloced.
21 *
22 * @file src/lib/util/fring.c
23 *
24 * @copyright 2013 The FreeRADIUS server project
25 * @copyright 2013 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
26 */
27RCSID("$Id: 9438d77eea3fafc3f2a3bb54cdc90a036fba9154 $")
28
29#include <freeradius-devel/util/fring.h>
30
31#include <pthread.h>
32
33/** Standard thread safe circular buffer
34 *
35 */
37 void const *end; //!< End of allocated memory
38
40 uint32_t in; //!< Write index
41 uint32_t out; //!< Read index
42
43 void **data; //!< Ring buffer data
44
45 bool lock; //!< Perform thread synchronisation
46
47 pthread_mutex_t mutex; //!< Thread synchronisation mutex
48};
49
50/** Destroy mutex associated with ring buffer
51 *
52 * @param[in] fring being freed.
53 * @return 0
54 */
55static int _fring_free(fr_fring_t *fring)
56{
57 void *next;
58
59 /*
60 * Free any data left in the buffer
61 */
62 while ((next = fr_fring_next(fring))) talloc_free(next);
63
64 if (fring->lock) pthread_mutex_destroy(&fring->mutex);
65
66 return 0;
67}
68
69/** Initialise a ring buffer with fixed element size
70 *
71 * @param[in] ctx to allocate the buffer in.
72 * @param[in] size of buffer to allocate.
73 * @param[in] lock If true, insert and next operations will lock the buffer.
74 * @return
75 * - New fring.
76 * - NULL on error.
77 */
78fr_fring_t *fr_fring_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock)
79{
80 fr_fring_t *fring;
81
82 uint32_t pow;
83
84 /*
85 * Find the nearest power of 2 (rounding up)
86 */
87 for (pow = 0x00000001;
88 pow < size;
89 pow <<= 1);
90 size = pow;
91 size--;
92
93 fring = talloc_zero(ctx, fr_fring_t);
94 if (!fring) return NULL;
95 talloc_set_destructor(fring, _fring_free);
96
97 fring->data = talloc_zero_array(fring, void *, size);
98 if (!fring->data) {
99 talloc_free(fring);
100 return NULL;
101 }
102 fring->size = size;
103
104 if (lock) {
105 fring->lock = true;
106 pthread_mutex_init(&fring->mutex, NULL);
107 }
108
109 return fring;
110}
111
112/** Insert a new item into the circular buffer, freeing the tail if we hit it
113 *
114 * @param[in] fring to insert item into
115 * @param[in] in item to insert (must have been allocated with talloc).
116 * @return
117 * - 0 if we inserted the item without freeing existing items.
118 * - 1 if we inserted the item, but needed to free an existing item.
119 */
121{
122 bool freed = false;
123 if (fring->lock) pthread_mutex_lock(&fring->mutex);
124
125 if (fring->data[fring->in]) {
126 freed = true;
127 talloc_free(fring->data[fring->in]);
128 }
129
130 fring->data[fring->in] = in;
131 fring->in = (fring->in + 1) & fring->size;
132
133 /* overwrite - out is advanced ahead of in */
134 if (fring->in == fring->out) fring->out = (fring->out + 1) & fring->size;
135
136 if (fring->lock) pthread_mutex_unlock(&fring->mutex);
137
138 return freed ? 1 : 0;
139}
140
141/** Insert a new item into the circular buffer if the buffer is not full
142 *
143 * @param[in] fring to insert item into.
144 * @param[in] in item to insert.
145 * @return
146 * - 0 if we inserted the item.
147 * - -1 if there's no more space in the buffer to insert items
148 */
149int fr_fring_insert(fr_fring_t *fring, void *in)
150{
151 if (fring->lock) pthread_mutex_lock(&fring->mutex);
152
153 if (fring->data[fring->in]) {
154 if (fring->lock) pthread_mutex_unlock(&fring->mutex);
155
156 return -1;
157 }
158
159 fring->data[fring->in] = in;
160 fring->in = (fring->in + 1) & fring->size;
161
162 /* overwrite - out is advanced ahead of in */
163 if (fring->in == fring->out) fring->out = (fring->out + 1) & fring->size;
164
165 if (fring->lock) pthread_mutex_unlock(&fring->mutex);
166
167 return 0;
168}
169
170/** Remove an item from the buffer
171 *
172 * @param[in] fring to drain data from.
173 * @return
174 * - NULL if no dataents in the buffer.
175 * - An dataent from the buffer reparented to ctx.
176 */
178{
179 void *out = NULL;
180
181 if (fring->lock) pthread_mutex_lock(&fring->mutex);
182
183 /* Buffer is empty */
184 if (fring->out == fring->in) goto done;
185
186 out = fring->data[fring->out];
187 fring->data[fring->out] = NULL;
188 fring->out = (fring->out + 1) & fring->size;
189
190done:
191 if (fring->lock) pthread_mutex_unlock(&fring->mutex);
192
193 return out;
194}
#define RCSID(id)
Definition build.h:483
static fr_slen_t in
Definition dict.h:823
void const * end
End of allocated memory.
Definition fring.c:37
uint32_t size
Definition fring.c:39
bool lock
Perform thread synchronisation.
Definition fring.c:45
uint32_t in
Write index.
Definition fring.c:40
void ** data
Ring buffer data.
Definition fring.c:43
int fr_fring_overwrite(fr_fring_t *fring, void *in)
Insert a new item into the circular buffer, freeing the tail if we hit it.
Definition fring.c:120
void * fr_fring_next(fr_fring_t *fring)
Remove an item from the buffer.
Definition fring.c:177
pthread_mutex_t mutex
Thread synchronisation mutex.
Definition fring.c:47
int fr_fring_insert(fr_fring_t *fring, void *in)
Insert a new item into the circular buffer if the buffer is not full.
Definition fring.c:149
fr_fring_t * fr_fring_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock)
Initialise a ring buffer with fixed element size.
Definition fring.c:78
uint32_t out
Read index.
Definition fring.c:41
static int _fring_free(fr_fring_t *fring)
Destroy mutex associated with ring buffer.
Definition fring.c:55
Standard thread safe circular buffer.
Definition fring.c:36
talloc_free(reap)
unsigned int uint32_t
static bool done
Definition radclient.c:80
static size_t char ** out
Definition value.h:997