Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_cbuf.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file
35  *
36  */
37 
38 
39 #include "ocs_os.h"
40 #include "ocs_array.h"
41 
42 struct ocs_cbuf_s {
43  ocs_os_handle_t os; /*<< OS handle */
44  uint32_t entry_count; /*<< entry count */
45  void **array; /*<< pointer to array of cbuf pointers */
46  uint32_t pidx; /*<< producer index */
47  uint32_t cidx; /*<< consumer index */
48  ocs_lock_t cbuf_plock; /*<< idx lock */
49  ocs_lock_t cbuf_clock; /*<< idx lock */
50  ocs_sem_t cbuf_psem; /*<< cbuf producer counting semaphore */
51  ocs_sem_t cbuf_csem; /*<< cbuf consumer counting semaphore */
52 };
53 
54 /**
55  * @brief Initialize a circular buffer queue
56  *
57  * A circular buffer with producer/consumer API is allocated
58  *
59  * @param os OS handle
60  * @param entry_count count of entries
61  *
62  * @return returns pointer to circular buffer, or NULL
63  */
64 ocs_cbuf_t*
65 ocs_cbuf_alloc(ocs_os_handle_t os, uint32_t entry_count)
66 {
67  ocs_cbuf_t *cbuf;
68 
69  cbuf = ocs_malloc(os, sizeof(*cbuf), OCS_M_NOWAIT | OCS_M_ZERO);
70  if (cbuf == NULL) {
71  return NULL;
72  }
73 
74  cbuf->os = os;
75  cbuf->entry_count = entry_count;
76  cbuf->pidx = 0;
77  cbuf->cidx = 0;
78 
79  ocs_lock_init(NULL, &cbuf->cbuf_clock, "cbuf_c:%p", cbuf);
80  ocs_lock_init(NULL, &cbuf->cbuf_plock, "cbuf_p:%p", cbuf);
81  ocs_sem_init(&cbuf->cbuf_csem, 0, "cbuf:%p", cbuf);
82  ocs_sem_init(&cbuf->cbuf_psem, cbuf->entry_count, "cbuf:%p", cbuf);
83 
84  cbuf->array = ocs_malloc(os, entry_count * sizeof(*cbuf->array), OCS_M_NOWAIT | OCS_M_ZERO);
85  if (cbuf->array == NULL) {
86  ocs_cbuf_free(cbuf);
87  return NULL;
88  }
89 
90  return cbuf;
91 }
92 
93 /**
94  * @brief Free a circular buffer
95  *
96  * The memory resources of a circular buffer are free'd
97  *
98  * @param cbuf pointer to circular buffer
99  *
100  * @return none
101  */
102 void
103 ocs_cbuf_free(ocs_cbuf_t *cbuf)
104 {
105  if (cbuf != NULL) {
106  if (cbuf->array != NULL) {
107  ocs_free(cbuf->os, cbuf->array, sizeof(*cbuf->array) * cbuf->entry_count);
108  }
109  ocs_lock_free(&cbuf->cbuf_clock);
110  ocs_lock_free(&cbuf->cbuf_plock);
111  ocs_free(cbuf->os, cbuf, sizeof(*cbuf));
112  }
113 }
114 
115 /**
116  * @brief Get pointer to buffer
117  *
118  * Wait for a buffer to become available, and return a pointer to the buffer.
119  *
120  * @param cbuf pointer to circular buffer
121  * @param timeout_usec timeout in microseconds
122  *
123  * @return pointer to buffer, or NULL if timeout
124  */
125 void*
126 ocs_cbuf_get(ocs_cbuf_t *cbuf, int32_t timeout_usec)
127 {
128  void *ret = NULL;
129 
130  if (likely(ocs_sem_p(&cbuf->cbuf_csem, timeout_usec) == 0)) {
131  ocs_lock(&cbuf->cbuf_clock);
132  ret = cbuf->array[cbuf->cidx];
133  if (unlikely(++cbuf->cidx >= cbuf->entry_count)) {
134  cbuf->cidx = 0;
135  }
136  ocs_unlock(&cbuf->cbuf_clock);
137  ocs_sem_v(&cbuf->cbuf_psem);
138  }
139  return ret;
140 }
141 
142 /**
143  * @brief write a buffer
144  *
145  * The buffer is written to the circular buffer.
146  *
147  * @param cbuf pointer to circular buffer
148  * @param elem pointer to entry
149  *
150  * @return returns 0 for success, a negative error code value for failure.
151  */
152 int32_t
153 ocs_cbuf_put(ocs_cbuf_t *cbuf, void *elem)
154 {
155  int32_t rc = 0;
156 
157  if (likely(ocs_sem_p(&cbuf->cbuf_psem, -1) == 0)) {
158  ocs_lock(&cbuf->cbuf_plock);
159  cbuf->array[cbuf->pidx] = elem;
160  if (unlikely(++cbuf->pidx >= cbuf->entry_count)) {
161  cbuf->pidx = 0;
162  }
163  ocs_unlock(&cbuf->cbuf_plock);
164  ocs_sem_v(&cbuf->cbuf_csem);
165  } else {
166  rc = -1;
167  }
168  return rc;
169 }
170 
171 /**
172  * @brief Prime a circular buffer data
173  *
174  * Post array buffers to a circular buffer
175  *
176  * @param cbuf pointer to circular buffer
177  * @param array pointer to buffer array
178  *
179  * @return returns 0 for success, a negative error code value for failure.
180  */
181 int32_t
182 ocs_cbuf_prime(ocs_cbuf_t *cbuf, ocs_array_t *array)
183 {
184  uint32_t i;
185  uint32_t count = MIN(ocs_array_get_count(array), cbuf->entry_count);
186 
187  for (i = 0; i < count; i++) {
188  ocs_cbuf_put(cbuf, ocs_array_get(array, i));
189  }
190  return 0;
191 }
192 
ocs_sem_t cbuf_psem
Definition: ocs_cbuf.c:50
void ocs_cbuf_free(ocs_cbuf_t *cbuf)
Free a circular buffer.
Definition: ocs_cbuf.c:103
ocs_lock_t cbuf_clock
Definition: ocs_cbuf.c:49
ocs_lock_t cbuf_plock
Definition: ocs_cbuf.c:48
uint32_t pidx
Definition: ocs_cbuf.c:46
ocs_os_handle_t os
Definition: ocs_cbuf.c:43
uint32_t ocs_array_get_count(ocs_array_t *array)
Return number of elements in an array.
Definition: ocs_array.c:188
uint32_t entry_count
Definition: ocs_cbuf.c:44
void * ocs_cbuf_get(ocs_cbuf_t *cbuf, int32_t timeout_usec)
Get pointer to buffer.
Definition: ocs_cbuf.c:126
int32_t ocs_cbuf_prime(ocs_cbuf_t *cbuf, ocs_array_t *array)
Prime a circular buffer data.
Definition: ocs_cbuf.c:182
void ** array
Definition: ocs_cbuf.c:45
ocs_cbuf_t * ocs_cbuf_alloc(ocs_os_handle_t os, uint32_t entry_count)
Initialize a circular buffer queue.
Definition: ocs_cbuf.c:65
int32_t ocs_cbuf_put(ocs_cbuf_t *cbuf, void *elem)
write a buffer
Definition: ocs_cbuf.c:153
uint32_t cidx
Definition: ocs_cbuf.c:47
void * ocs_array_get(ocs_array_t *array, uint32_t idx)
Return reference to an element of an array object.
Definition: ocs_array.c:166
ocs_sem_t cbuf_csem
Definition: ocs_cbuf.c:51