Initial OpenECOMP Demo commit
[demo.git] / vnfs / VES / code / evel_library / ring_buffer.c
1 /**************************************************************************//**
2  * @file
3  * A ring buffer with multi-threaded synchronization.
4  *
5  * License
6  * -------
7  *
8  * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
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.
24  *
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  *****************************************************************************/
36
37 #include <assert.h>
38 #include <malloc.h>
39
40 #include "ring_buffer.h"
41 #include "evel.h"
42
43 /**************************************************************************//**
44  * Ring buffer initialization.
45  *
46  * Initialize the buffer supplied to the specified size.
47  *
48  * @param   buffer  Pointer to the ring-buffer to be initialized.
49  * @param   size    How many elements to be stored in the ring-buffer.
50  *
51  * @returns Nothing
52 ******************************************************************************/
53 void ring_buffer_initialize(ring_buffer * buffer, int size)
54 {
55   int pthread_rc = 0;
56
57   EVEL_ENTER();
58
59   /***************************************************************************/
60   /* Check assumptions.                                                      */
61   /***************************************************************************/
62   assert(buffer != NULL);
63   assert(size > 0);
64
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);
72
73   /***************************************************************************/
74   /* Allocate the ring buffer itself.                                        */
75   /***************************************************************************/
76   buffer->ring = malloc(size * sizeof(void *));
77   assert(buffer->ring != NULL);
78
79   /***************************************************************************/
80   /* Initialize the ring as empty.                                           */
81   /***************************************************************************/
82   buffer->next_write = 0;
83   buffer->next_read = 0;
84   buffer->size = size;
85
86   EVEL_EXIT();
87 }
88
89 /**************************************************************************//**
90  * Read an element from a ring_buffer.
91  *
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
94  * available.
95  *
96  * @param   buffer  Pointer to the ring-buffer to be read.
97  *
98  * @returns Pointer to the element read from the buffer.
99 ******************************************************************************/
100 void * ring_buffer_read(ring_buffer * buffer)
101 {
102   void *msg = NULL;
103   EVEL_DEBUG("RBR: Ring buffer read");
104
105   pthread_mutex_lock(&buffer->ring_mutex);
106   while (1)
107   {
108     EVEL_DEBUG("RBR: got lock. NR=%d NW=%d",
109                buffer->next_read,
110                buffer->next_write);
111     if(buffer->next_read != buffer->next_write)
112     {
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);
119       break;
120     }
121     else
122     {
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");
126     }
127   }
128   EVEL_DEBUG("RBR: Ring buffer read returning data at %lp", msg);
129   return msg;
130 }
131
132 /**************************************************************************//**
133  * Write an element into a ring_buffer.
134  *
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.
138  *
139  * @param   buffer  Pointer to the ring-buffer to be written.
140  * @param   msg     Pointer to data to be stored in the ring_buffer.
141  *
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)
147 {
148   int item_count = 0;
149   int items_written = 0;
150   EVEL_DEBUG("RBW: Ring Buffer Write message at %lp", msg);
151
152   pthread_mutex_lock(&buffer->ring_mutex);
153   EVEL_DEBUG("RBW: got lock. NR=%d NW=%d SZ=%d",
154              buffer->next_read,
155              buffer->next_write,
156              buffer->size);
157
158   item_count = (buffer->next_write - buffer->next_read) % buffer->size;
159   if (item_count < 0)
160   {
161     item_count += buffer->size;
162   }
163   if (item_count < buffer->size - 1)
164   {
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);
169     items_written = 1;
170   }
171   else
172   {
173     EVEL_ERROR("RBW: ring buffer full - unable to write event");
174   }
175
176   pthread_mutex_unlock(&buffer->ring_mutex);
177   EVEL_DEBUG("RBW: released lock");
178   pthread_cond_signal(&buffer->ring_cv);
179
180   return items_written;
181 }
182
183 /**************************************************************************//**
184  * Tests whether there is data in the ring_buffer.
185  *
186  * Tests whether there is currently data in the ring_buffer without blocking.
187  *
188  * @param   buffer  Pointer to the ring-buffer to be tested.
189  *
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)
195 {
196   int is_empty = 0;
197   EVEL_DEBUG("RBE: Ring empty check");
198
199   pthread_mutex_lock(&buffer->ring_mutex);
200   is_empty = (buffer->next_read == buffer->next_write);
201   pthread_mutex_unlock(&buffer->ring_mutex);
202
203   EVEL_DEBUG("RBE: Ring state= %d", is_empty);
204   return is_empty;
205 }
206