]> git.tuebingen.mpg.de Git - paraslash.git/blob - ringbuffer.c
Avoid busy loop if someone nasty removes the semaphores currently in use.
[paraslash.git] / ringbuffer.c
1 /*
2  * Copyright (C) 2006 Andre Noll <maan@systemlinux.org>
3  *
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  *
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  *
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18
19 /** \file ringbuffer.c simple ringbuffer implementation */
20
21 #include "gcc-compat.h"
22 #include "para.h"
23 #include "ringbuffer.h"
24 #include "string.h"
25
26 /**
27  * holds all information about one ring buffer
28  *
29  * It is intentionally not exported via ringbuffer.h. Think abstract.
30  */
31 struct ringbuffer
32 {
33 /**
34  *
35  *
36  * the size of this ring buffer
37 */
38 unsigned size;
39 /**
40  *
41  *
42  * the actual entries of the ringbuffer
43 */
44 void **entries;
45 /**
46  *
47  *
48  * the next entry will be added at this position
49  */
50 int head;
51 /**
52  *
53  * how many entries the ring buffer contains
54 */
55 unsigned filled;
56 };
57
58 /**
59  * initialize a new ringbuffer
60  *
61  * @param size the number of entries the ringbuffer holds
62  *
63  * This function initializes a circular ring buffer which can hold up to \a
64  * size entries of arbitrary type. If performance is an issue, \a size should
65  * be a power of two to make the underlying modulo operations cheap. Arbitrary
66  * many ringbuffers may be initialized via this function. Each ringbuffer is
67  * identified by a 'cookie'.
68  *
69  * Return value: A 'cookie' which identifies the ringbuffer just created and
70  * which must be passed to ringbuffer_add() and ringbuffer_get().
71  */
72 void *ringbuffer_new(unsigned size)
73 {
74         struct ringbuffer *rb = para_calloc(sizeof(struct ringbuffer));
75         rb->entries = para_calloc(size * sizeof(void *));
76         rb->size = size;
77         return rb;
78 };
79
80 /**
81  * add one entry to a ringbuffer
82  *
83  * @param cookie the ringbuffer identifier
84  * @param data the data to be inserted
85  *
86  * insert \a data into the ringbuffer associated with \a cookie.  As soon as
87  * the ringbuffer fills up, its oldest entry is disregarded and replaced by \a
88  * data.
89  *
90  * \return The old \a data pointer which is going to be disregarded, or
91  * NULL if the ringbuffer is not yet full.
92  */
93 void *ringbuffer_add(void *cookie, void *data)
94 {
95         struct ringbuffer *rb = cookie;
96         void *ret = rb->entries[rb->head];
97         rb->entries[rb->head] = data;
98         rb->head = (rb->head + 1) % rb->size;
99         if (rb->filled < rb->size)
100                 rb->filled++;
101         return ret;
102 }
103
104 /**
105  * get one entry from a ringbuffer
106  *
107  * @param cookie the ringbuffer identifier
108  * @param num the number of the entry
109  *
110  * \return A pointer to data previously added, or NULL if entry number
111  * \a num is not available. \a num counts backwards from zero, i.e.
112  * ringbuffer_get_entry(0) gets the entry which was added most recently.
113  */
114 void *ringbuffer_get(void *cookie, int num)
115 {
116         struct ringbuffer *rb = cookie;
117         int pos = (rb->head + rb->size - 1 - num) % rb->size;
118 //      fprintf(stderr, "pos = %d\n", pos);
119         return rb->entries[pos];
120 }
121
122 /**
123  * get the number of entries in the ring buffer
124  *
125  * @param cookie the ringbuffer identifier
126  *
127  * This function always succeeds and never returns a number greater than the
128  * size of the ring buffer.
129  */
130 unsigned ringbuffer_filled(void *cookie)
131 {
132         struct ringbuffer *rb = cookie;
133         return rb->filled;
134 }