The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: acef49804e222a1e58c7d3539820dbd24a33bb8f $")
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 if (size == 0 || size > 0x80000000U) return NULL;
85
86 /*
87 * Find the nearest power of 2 (rounding up)
88 */
89 for (pow = 0x00000001;
90 pow < size;
91 pow <<= 1);
92 size = pow;
93 size--;
94
95 fring = talloc_zero(ctx, fr_fring_t);
96 if (!fring) return NULL;
97 talloc_set_destructor(fring, _fring_free);
98
99 fring->data = talloc_zero_array(fring, void *, size);
100 if (!fring->data) {
101 talloc_free(fring);
102 return NULL;
103 }
104 fring->size = size;
105
106 if (lock) {
107 fring->lock = true;
108 pthread_mutex_init(&fring->mutex, NULL);
109 }
110
111 return fring;
112}
113
114/** Insert a new item into the circular buffer, freeing the tail if we hit it
115 *
116 * @param[in] fring to insert item into
117 * @param[in] in item to insert (must have been allocated with talloc).
118 * @return
119 * - 0 if we inserted the item without freeing existing items.
120 * - 1 if we inserted the item, but needed to free an existing item.
121 */
123{
124 bool freed = false;
125 if (fring->lock) pthread_mutex_lock(&fring->mutex);
126
127 if (fring->data[fring->in]) {
128 freed = true;
129 talloc_free(fring->data[fring->in]);
130 }
131
132 fring->data[fring->in] = in;
133 fring->in = (fring->in + 1) & fring->size;
134
135 /* overwrite - out is advanced ahead of in */
136 if (fring->in == fring->out) fring->out = (fring->out + 1) & fring->size;
137
138 if (fring->lock) pthread_mutex_unlock(&fring->mutex);
139
140 return freed ? 1 : 0;
141}
142
143/** Insert a new item into the circular buffer if the buffer is not full
144 *
145 * @param[in] fring to insert item into.
146 * @param[in] in item to insert.
147 * @return
148 * - 0 if we inserted the item.
149 * - -1 if there's no more space in the buffer to insert items
150 */
151int fr_fring_insert(fr_fring_t *fring, void *in)
152{
153 if (fring->lock) pthread_mutex_lock(&fring->mutex);
154
155 if (fring->data[fring->in]) {
156 if (fring->lock) pthread_mutex_unlock(&fring->mutex);
157
158 return -1;
159 }
160
161 fring->data[fring->in] = in;
162 fring->in = (fring->in + 1) & fring->size;
163
164 /* overwrite - out is advanced ahead of in */
165 if (fring->in == fring->out) fring->out = (fring->out + 1) & fring->size;
166
167 if (fring->lock) pthread_mutex_unlock(&fring->mutex);
168
169 return 0;
170}
171
172/** Remove an item from the buffer
173 *
174 * @param[in] fring to drain data from.
175 * @return
176 * - NULL if no dataents in the buffer.
177 * - An dataent from the buffer reparented to ctx.
178 */
180{
181 void *out = NULL;
182
183 if (fring->lock) pthread_mutex_lock(&fring->mutex);
184
185 /* Buffer is empty */
186 if (fring->out == fring->in) goto done;
187
188 out = fring->data[fring->out];
189 fring->data[fring->out] = NULL;
190 fring->out = (fring->out + 1) & fring->size;
191
192done:
193 if (fring->lock) pthread_mutex_unlock(&fring->mutex);
194
195 return out;
196}
#define RCSID(id)
Definition build.h:512
static fr_slen_t in
Definition dict.h:882
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:122
void * fr_fring_next(fr_fring_t *fring)
Remove an item from the buffer.
Definition fring.c:179
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:151
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(hp)
unsigned int uint32_t
static bool done
Definition radclient.c:80
static size_t char ** out
Definition value.h:1030