1 /**************************************************************************//**
3 * A ring buffer with multi-threaded synchronization.
8 * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement: This product includes
20 * software developed by the AT&T.
21 * 4. Neither the name of AT&T nor the names of its contributors may be used to
22 * endorse or promote products derived from this software without specific
23 * prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
26 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
29 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *****************************************************************************/
40 #include "ring_buffer.h"
43 /**************************************************************************//**
44 * Ring buffer initialization.
46 * Initialize the buffer supplied to the specified size.
48 * @param buffer Pointer to the ring-buffer to be initialized.
49 * @param size How many elements to be stored in the ring-buffer.
52 ******************************************************************************/
53 void ring_buffer_initialize(ring_buffer * buffer, int size)
59 /***************************************************************************/
60 /* Check assumptions. */
61 /***************************************************************************/
62 assert(buffer != NULL);
65 /***************************************************************************/
66 /* Initialize the synchronization objects. */
67 /***************************************************************************/
68 pthread_rc = pthread_mutex_init(&buffer->ring_mutex, NULL);
69 assert(pthread_rc == 0);
70 pthread_rc = pthread_cond_init(&buffer->ring_cv, NULL);
71 assert(pthread_rc == 0);
73 /***************************************************************************/
74 /* Allocate the ring buffer itself. */
75 /***************************************************************************/
76 buffer->ring = malloc(size * sizeof(void *));
77 assert(buffer->ring != NULL);
79 /***************************************************************************/
80 /* Initialize the ring as empty. */
81 /***************************************************************************/
82 buffer->next_write = 0;
83 buffer->next_read = 0;
89 /**************************************************************************//**
90 * Read an element from a ring_buffer.
92 * Reads an element from the ring_buffer, advancing the next-read position.
93 * Operation is synchronized and therefore MT-safe. Blocks if no data is
96 * @param buffer Pointer to the ring-buffer to be read.
98 * @returns Pointer to the element read from the buffer.
99 ******************************************************************************/
100 void * ring_buffer_read(ring_buffer * buffer)
103 EVEL_DEBUG("RBR: Ring buffer read");
105 pthread_mutex_lock(&buffer->ring_mutex);
108 EVEL_DEBUG("RBR: got lock. NR=%d NW=%d",
111 if(buffer->next_read != buffer->next_write)
113 EVEL_DEBUG("RBR: buffer has item available");
114 msg = (buffer->ring)[buffer->next_read];
115 buffer->ring[buffer->next_read] = NULL;
116 buffer->next_read = (buffer->next_read + 1) % buffer->size;
117 EVEL_DEBUG("RBR: next read location is %d", buffer->next_read);
118 pthread_mutex_unlock(&buffer->ring_mutex);
123 EVEL_DEBUG("RBR: Waiting for condition variable");
124 pthread_cond_wait(&buffer->ring_cv, &buffer->ring_mutex);
125 EVEL_DEBUG("RBR: Condition variable wait completed");
128 EVEL_DEBUG("RBR: Ring buffer read returning data at %lp", msg);
132 /**************************************************************************//**
133 * Write an element into a ring_buffer.
135 * Writes an element into the ring_buffer, advancing the next-write position.
136 * Operation is synchronized and therefore MT-safe. Fails if the buffer is
137 * full without blocking.
139 * @param buffer Pointer to the ring-buffer to be written.
140 * @param msg Pointer to data to be stored in the ring_buffer.
142 * @returns Number of items written.
143 * @retval 1 The data was written successfully.
144 * @retval 0 The ring_buffer was full so no data written.
145 ******************************************************************************/
146 int ring_buffer_write(ring_buffer * buffer, void * msg)
149 int items_written = 0;
150 EVEL_DEBUG("RBW: Ring Buffer Write message at %lp", msg);
152 pthread_mutex_lock(&buffer->ring_mutex);
153 EVEL_DEBUG("RBW: got lock. NR=%d NW=%d SZ=%d",
158 item_count = (buffer->next_write - buffer->next_read) % buffer->size;
161 item_count += buffer->size;
163 if (item_count < buffer->size - 1)
165 EVEL_DEBUG("RBW: %d items in buffer", item_count);
166 buffer->ring[buffer->next_write] = msg;
167 buffer->next_write = (buffer->next_write + 1) % buffer->size;
168 EVEL_DEBUG("RBW: next write location is %d", buffer->next_write);
173 EVEL_ERROR("RBW: ring buffer full - unable to write event");
176 pthread_mutex_unlock(&buffer->ring_mutex);
177 EVEL_DEBUG("RBW: released lock");
178 pthread_cond_signal(&buffer->ring_cv);
180 return items_written;
183 /**************************************************************************//**
184 * Tests whether there is data in the ring_buffer.
186 * Tests whether there is currently data in the ring_buffer without blocking.
188 * @param buffer Pointer to the ring-buffer to be tested.
190 * @returns Whether there is data in the ring_buffer.
191 * @retval 0 There isn't any data in the ring_buffer.
192 * @retval 1 There is data in the ring_buffer.
193 ******************************************************************************/
194 int ring_buffer_is_empty(ring_buffer * buffer)
197 EVEL_DEBUG("RBE: Ring empty check");
199 pthread_mutex_lock(&buffer->ring_mutex);
200 is_empty = (buffer->next_read == buffer->next_write);
201 pthread_mutex_unlock(&buffer->ring_mutex);
203 EVEL_DEBUG("RBE: Ring state= %d", is_empty);