Cleanup code and correct License
[demo.git] / vnfs / VES5.0 / evel / evel-library / code / evel_library / ring_buffer.c
1 /*************************************************************************//**
2  *
3  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and 
14  * limitations under the License.
15  *
16  ****************************************************************************/
17 /**************************************************************************//**
18  * @file
19  * A ring buffer with multi-threaded synchronization.
20  *
21  ****************************************************************************/
22
23 #include <assert.h>
24 #include <malloc.h>
25
26 #include "ring_buffer.h"
27 #include "evel.h"
28
29 /**************************************************************************//**
30  * Ring buffer initialization.
31  *
32  * Initialize the buffer supplied to the specified size.
33  *
34  * @param   buffer  Pointer to the ring-buffer to be initialized.
35  * @param   size    How many elements to be stored in the ring-buffer.
36  *
37  * @returns Nothing
38 ******************************************************************************/
39 void ring_buffer_initialize(ring_buffer * buffer, int size)
40 {
41   int pthread_rc = 0;
42
43   EVEL_ENTER();
44
45   /***************************************************************************/
46   /* Check assumptions.                                                      */
47   /***************************************************************************/
48   assert(buffer != NULL);
49   assert(size > 0);
50
51   /***************************************************************************/
52   /* Initialize the synchronization objects.                                 */
53   /***************************************************************************/
54   pthread_rc = pthread_mutex_init(&buffer->ring_mutex, NULL);
55   assert(pthread_rc == 0);
56   pthread_rc = pthread_cond_init(&buffer->ring_cv, NULL);
57   assert(pthread_rc == 0);
58
59   /***************************************************************************/
60   /* Allocate the ring buffer itself.                                        */
61   /***************************************************************************/
62   buffer->ring = malloc(size * sizeof(void *));
63   assert(buffer->ring != NULL);
64
65   /***************************************************************************/
66   /* Initialize the ring as empty.                                           */
67   /***************************************************************************/
68   buffer->next_write = 0;
69   buffer->next_read = 0;
70   buffer->size = size;
71
72   EVEL_EXIT();
73 }
74
75 /**************************************************************************//**
76  * Read an element from a ring_buffer.
77  *
78  * Reads an element from the ring_buffer, advancing the next-read position.
79  * Operation is synchronized and therefore MT-safe.  Blocks if no data is
80  * available.
81  *
82  * @param   buffer  Pointer to the ring-buffer to be read.
83  *
84  * @returns Pointer to the element read from the buffer.
85 ******************************************************************************/
86 void * ring_buffer_read(ring_buffer * buffer)
87 {
88   void *msg = NULL;
89   EVEL_DEBUG("RBR: Ring buffer read");
90
91   pthread_mutex_lock(&buffer->ring_mutex);
92   while (1)
93   {
94     EVEL_DEBUG("RBR: got lock. NR=%d NW=%d",
95                buffer->next_read,
96                buffer->next_write);
97     if(buffer->next_read != buffer->next_write)
98     {
99       EVEL_DEBUG("RBR: buffer has item available");
100       msg = (buffer->ring)[buffer->next_read];
101       buffer->ring[buffer->next_read] = NULL;
102       buffer->next_read = (buffer->next_read + 1) % buffer->size;
103       EVEL_DEBUG("RBR: next read location is %d", buffer->next_read);
104       pthread_mutex_unlock(&buffer->ring_mutex);
105       break;
106     }
107     else
108     {
109       EVEL_DEBUG("RBR: Waiting for condition variable");
110       pthread_cond_wait(&buffer->ring_cv, &buffer->ring_mutex);
111       EVEL_DEBUG("RBR: Condition variable wait completed");
112     }
113   }
114   EVEL_DEBUG("RBR: Ring buffer read returning data at %lp", msg);
115   return msg;
116 }
117
118 /**************************************************************************//**
119  * Write an element into a ring_buffer.
120  *
121  * Writes an element into the ring_buffer, advancing the next-write position.
122  * Operation is synchronized and therefore MT-safe.  Fails if the buffer is
123  * full without blocking.
124  *
125  * @param   buffer  Pointer to the ring-buffer to be written.
126  * @param   msg     Pointer to data to be stored in the ring_buffer.
127  *
128  * @returns Number of items written.
129  * @retval  1       The data was written successfully.
130  * @retval  0       The ring_buffer was full so no data written.
131 ******************************************************************************/
132 int ring_buffer_write(ring_buffer * buffer, void * msg)
133 {
134   int item_count = 0;
135   int items_written = 0;
136   EVEL_DEBUG("RBW: Ring Buffer Write message at %lp", msg);
137
138   pthread_mutex_lock(&buffer->ring_mutex);
139   EVEL_DEBUG("RBW: got lock. NR=%d NW=%d SZ=%d",
140              buffer->next_read,
141              buffer->next_write,
142              buffer->size);
143
144   item_count = (buffer->next_write - buffer->next_read) % buffer->size;
145   if (item_count < 0)
146   {
147     item_count += buffer->size;
148   }
149   if (item_count < buffer->size - 1)
150   {
151     EVEL_DEBUG("RBW: %d items in buffer", item_count);
152     buffer->ring[buffer->next_write] = msg;
153     buffer->next_write = (buffer->next_write + 1) % buffer->size;
154     EVEL_DEBUG("RBW: next write location is %d", buffer->next_write);
155     items_written = 1;
156   }
157   else
158   {
159     EVEL_ERROR("RBW: ring buffer full - unable to write event");
160   }
161
162   pthread_mutex_unlock(&buffer->ring_mutex);
163   EVEL_DEBUG("RBW: released lock");
164   pthread_cond_signal(&buffer->ring_cv);
165
166   return items_written;
167 }
168
169 /**************************************************************************//**
170  * Tests whether there is data in the ring_buffer.
171  *
172  * Tests whether there is currently data in the ring_buffer without blocking.
173  *
174  * @param   buffer  Pointer to the ring-buffer to be tested.
175  *
176  * @returns Whether there is data in the ring_buffer.
177  * @retval  0       There isn't any data in the ring_buffer.
178  * @retval  1       There is data in the ring_buffer.
179 ******************************************************************************/
180 int ring_buffer_is_empty(ring_buffer * buffer)
181 {
182   int is_empty = 0;
183   EVEL_DEBUG("RBE: Ring empty check");
184
185   pthread_mutex_lock(&buffer->ring_mutex);
186   is_empty = (buffer->next_read == buffer->next_write);
187   pthread_mutex_unlock(&buffer->ring_mutex);
188
189   EVEL_DEBUG("RBE: Ring state= %d", is_empty);
190   return is_empty;
191 }
192