Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_array.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 #include "ocs.h"
39 #include "ocs_array.h"
40 
41 #define DEFAULT_SLAB_LEN (16*1024)
42 
43 struct ocs_array_s {
44  ocs_os_handle_t os;
45 
46  uint32_t size;
47  uint32_t count;
48 
49  uint32_t n_rows;
50  uint32_t elems_per_row;
51  uint32_t bytes_per_row;
52 
53  void **array_rows;
54  uint32_t array_rows_len;
55 };
56 
57 static uint32_t slab_len = DEFAULT_SLAB_LEN;
58 
59 /**
60  * @brief Set array slab allocation length
61  *
62  * The slab length is the maximum allocation length that the array uses.
63  * The default 64k slab length may be overridden using this function.
64  *
65  * @param len new slab length.
66  *
67  * @return none
68  */
69 void
70 ocs_array_set_slablen(uint32_t len)
71 {
72  slab_len = len;
73 }
74 
75 /**
76  * @brief Allocate an array object
77  *
78  * An array object of size and number of elements is allocated
79  *
80  * @param os OS handle
81  * @param size size of array elements in bytes
82  * @param count number of elements in array
83  *
84  * @return pointer to array object or NULL
85  */
86 ocs_array_t *
87 ocs_array_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count)
88 {
89  ocs_array_t *array = NULL;
90  uint32_t i;
91 
92  /* Fail if the item size exceeds slab_len - caller should increase slab_size,
93  * or not use this API.
94  */
95  if (size > slab_len) {
96  ocs_log_err(NULL, "Error: size exceeds slab length\n");
97  return NULL;
98  }
99 
100  array = ocs_malloc(os, sizeof(*array), OCS_M_ZERO | OCS_M_NOWAIT);
101  if (array == NULL) {
102  return NULL;
103  }
104 
105  array->os = os;
106  array->size = size;
107  array->count = count;
108  array->elems_per_row = slab_len / size;
109  array->n_rows = (count + array->elems_per_row - 1) / array->elems_per_row;
110  array->bytes_per_row = array->elems_per_row * array->size;
111 
112  array->array_rows_len = array->n_rows * sizeof(*array->array_rows);
113  array->array_rows = ocs_malloc(os, array->array_rows_len, OCS_M_ZERO | OCS_M_NOWAIT);
114  if (array->array_rows == NULL) {
115  ocs_array_free(array);
116  return NULL;
117  }
118  for (i = 0; i < array->n_rows; i++) {
119  array->array_rows[i] = ocs_malloc(os, array->bytes_per_row, OCS_M_ZERO | OCS_M_NOWAIT);
120  if (array->array_rows[i] == NULL) {
121  ocs_array_free(array);
122  return NULL;
123  }
124  }
125 
126  return array;
127 }
128 
129 /**
130  * @brief Free an array object
131  *
132  * Frees a prevously allocated array object
133  *
134  * @param array pointer to array object
135  *
136  * @return none
137  */
138 void
139 ocs_array_free(ocs_array_t *array)
140 {
141  uint32_t i;
142 
143  if (array != NULL) {
144  if (array->array_rows != NULL) {
145  for (i = 0; i < array->n_rows; i++) {
146  if (array->array_rows[i] != NULL) {
147  ocs_free(array->os, array->array_rows[i], array->bytes_per_row);
148  }
149  }
150  ocs_free(array->os, array->array_rows, array->array_rows_len);
151  }
152  ocs_free(array->os, array, sizeof(*array));
153  }
154 }
155 
156 /**
157  * @brief Return reference to an element of an array object
158  *
159  * Return the address of an array element given an index
160  *
161  * @param array pointer to array object
162  * @param idx array element index
163  *
164  * @return rointer to array element, or NULL if index out of range
165  */
166 void *ocs_array_get(ocs_array_t *array, uint32_t idx)
167 {
168  void *entry = NULL;
169 
170  if (idx < array->count) {
171  uint32_t row = idx / array->elems_per_row;
172  uint32_t offset = idx % array->elems_per_row;
173  entry = ((uint8_t*)array->array_rows[row]) + (offset * array->size);
174  }
175  return entry;
176 }
177 
178 /**
179  * @brief Return number of elements in an array
180  *
181  * Return the number of elements in an array
182  *
183  * @param array pointer to array object
184  *
185  * @return returns count of elements in an array
186  */
187 uint32_t
188 ocs_array_get_count(ocs_array_t *array)
189 {
190  return array->count;
191 }
192 
193 /**
194  * @brief Return size of array elements in bytes
195  *
196  * Returns the size in bytes of each array element
197  *
198  * @param array pointer to array object
199  *
200  * @return size of array element
201  */
202 uint32_t
203 ocs_array_get_size(ocs_array_t *array)
204 {
205  return array->size;
206 }
207 
208 /**
209  * @brief Void pointer array structure
210  *
211  * This structure describes an object consisting of an array of void
212  * pointers. The object is allocated with a maximum array size, entries
213  * are then added to the array with while maintaining an entry count. A set of
214  * iterator APIs are included to allow facilitate cycling through the array
215  * entries in a circular fashion.
216  *
217  */
218 struct ocs_varray_s {
219  ocs_os_handle_t os;
220  uint32_t array_count; /*>> maximum entry count in array */
221  void **array; /*>> pointer to allocated array memory */
222  uint32_t entry_count; /*>> number of entries added to the array */
223  uint32_t next_index; /*>> iterator next index */
224  ocs_lock_t lock; /*>> iterator lock */
225 };
226 
227 /**
228  * @brief Allocate a void pointer array
229  *
230  * A void pointer array of given length is allocated.
231  *
232  * @param os OS handle
233  * @param array_count Array size
234  *
235  * @return returns a pointer to the ocs_varray_t object, other NULL on error
236  */
237 ocs_varray_t *
238 ocs_varray_alloc(ocs_os_handle_t os, uint32_t array_count)
239 {
240  ocs_varray_t *va;
241 
242  va = ocs_malloc(os, sizeof(*va), OCS_M_ZERO | OCS_M_NOWAIT);
243  if (va != NULL) {
244  va->os = os;
245  va->array_count = array_count;
246  va->array = ocs_malloc(os, sizeof(*va->array) * va->array_count, OCS_M_ZERO | OCS_M_NOWAIT);
247  if (va->array != NULL) {
248  va->next_index = 0;
249  ocs_lock_init(os, &va->lock, "varray:%p", va);
250  } else {
251  ocs_free(os, va, sizeof(*va));
252  va = NULL;
253  }
254  }
255  return va;
256 }
257 
258 /**
259  * @brief Free a void pointer array
260  *
261  * The void pointer array object is free'd
262  *
263  * @param va Pointer to void pointer array
264  *
265  * @return none
266  */
267 void
268 ocs_varray_free(ocs_varray_t *va)
269 {
270  if (va != NULL) {
271  ocs_lock_free(&va->lock);
272  if (va->array != NULL) {
273  ocs_free(va->os, va->array, sizeof(*va->array) * va->array_count);
274  }
275  ocs_free(va->os, va, sizeof(*va));
276  }
277 }
278 
279 /**
280  * @brief Add an entry to a void pointer array
281  *
282  * An entry is added to the void pointer array
283  *
284  * @param va Pointer to void pointer array
285  * @param entry Pointer to entry to add
286  *
287  * @return returns 0 if entry was added, -1 if there is no more space in the array
288  */
289 int32_t
290 ocs_varray_add(ocs_varray_t *va, void *entry)
291 {
292  uint32_t rc = -1;
293 
294  ocs_lock(&va->lock);
295  if (va->entry_count < va->array_count) {
296  va->array[va->entry_count++] = entry;
297  rc = 0;
298  }
299  ocs_unlock(&va->lock);
300 
301  return rc;
302 }
303 
304 /**
305  * @brief Reset the void pointer array iterator
306  *
307  * The next index value of the void pointer array iterator is cleared.
308  *
309  * @param va Pointer to void pointer array
310  *
311  * @return none
312  */
313 void
314 ocs_varray_iter_reset(ocs_varray_t *va)
315 {
316  ocs_lock(&va->lock);
317  va->next_index = 0;
318  ocs_unlock(&va->lock);
319 }
320 
321 /**
322  * @brief Return next entry from a void pointer array
323  *
324  * The next entry in the void pointer array is returned.
325  *
326  * @param va Pointer to void point array
327  *
328  * Note: takes the void pointer array lock
329  *
330  * @return returns next void pointer entry
331  */
332 void *
333 ocs_varray_iter_next(ocs_varray_t *va)
334 {
335  void *rval = NULL;
336 
337  if (va != NULL) {
338  ocs_lock(&va->lock);
339  rval = _ocs_varray_iter_next(va);
340  ocs_unlock(&va->lock);
341  }
342  return rval;
343 }
344 
345 /**
346  * @brief Return next entry from a void pointer array
347  *
348  * The next entry in the void pointer array is returned.
349  *
350  * @param va Pointer to void point array
351  *
352  * Note: doesn't take the void pointer array lock
353  *
354  * @return returns next void pointer entry
355  */
356 void *
357 _ocs_varray_iter_next(ocs_varray_t *va)
358 {
359  void *rval;
360 
361  rval = va->array[va->next_index];
362  if (++va->next_index >= va->entry_count) {
363  va->next_index = 0;
364  }
365  return rval;
366 }
367 
368 /**
369  * @brief Take void pointer array lock
370  *
371  * Takes the lock for the given void pointer array
372  *
373  * @param va Pointer to void pointer array
374  *
375  * @return none
376  */
377 void
378 ocs_varray_lock(ocs_varray_t *va)
379 {
380  ocs_lock(&va->lock);
381 }
382 
383 /**
384  * @brief Release void pointer array lock
385  *
386  * Releases the lock for the given void pointer array
387  *
388  * @param va Pointer to void pointer array
389  *
390  * @return none
391  */
392 void
393 ocs_varray_unlock(ocs_varray_t *va)
394 {
395  ocs_unlock(&va->lock);
396 }
397 
398 /**
399  * @brief Return entry count for a void pointer array
400  *
401  * The entry count for a void pointer array is returned
402  *
403  * @param va Pointer to void pointer array
404  *
405  * @return returns entry count
406  */
407 uint32_t
408 ocs_varray_get_count(ocs_varray_t *va)
409 {
410  uint32_t rc;
411 
412  ocs_lock(&va->lock);
413  rc = va->entry_count;
414  ocs_unlock(&va->lock);
415  return rc;
416 }
void ** array_rows
Definition: ocs_array.c:53
uint32_t array_count
Definition: ocs_array.c:220
ocs_os_handle_t os
Definition: ocs_array.c:219
Void pointer array structure.
Definition: ocs_array.c:218
void * _ocs_varray_iter_next(ocs_varray_t *va)
Return next entry from a void pointer array.
Definition: ocs_array.c:357
uint32_t count
Definition: ocs_array.c:47
static uint32_t slab_len
Definition: ocs_array.c:57
uint32_t array_rows_len
Definition: ocs_array.c:54
uint32_t ocs_array_get_size(ocs_array_t *array)
Return size of array elements in bytes.
Definition: ocs_array.c:203
void ocs_varray_iter_reset(ocs_varray_t *va)
Reset the void pointer array iterator.
Definition: ocs_array.c:314
void ocs_varray_unlock(ocs_varray_t *va)
Release void pointer array lock.
Definition: ocs_array.c:393
uint32_t elems_per_row
Definition: ocs_array.c:50
uint32_t next_index
Definition: ocs_array.c:223
void ocs_varray_lock(ocs_varray_t *va)
Take void pointer array lock.
Definition: ocs_array.c:378
uint32_t n_rows
Definition: ocs_array.c:49
ocs_lock_t lock
Definition: ocs_array.c:224
ocs_array_t * ocs_array_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count)
Allocate an array object.
Definition: ocs_array.c:87
void ocs_array_free(ocs_array_t *array)
Free an array object.
Definition: ocs_array.c:139
void ** array
Definition: ocs_array.c:221
uint32_t ocs_array_get_count(ocs_array_t *array)
Return number of elements in an array.
Definition: ocs_array.c:188
uint32_t ocs_varray_get_count(ocs_varray_t *va)
Return entry count for a void pointer array.
Definition: ocs_array.c:408
void ocs_array_set_slablen(uint32_t len)
Set array slab allocation length.
Definition: ocs_array.c:70
void * ocs_varray_iter_next(ocs_varray_t *va)
Return next entry from a void pointer array.
Definition: ocs_array.c:333
void ocs_varray_free(ocs_varray_t *va)
Free a void pointer array.
Definition: ocs_array.c:268
uint32_t size
Definition: ocs_array.c:46
uint32_t entry_count
Definition: ocs_array.c:222
uint32_t bytes_per_row
Definition: ocs_array.c:51
ocs_os_handle_t os
Definition: ocs_array.c:44
int32_t ocs_varray_add(ocs_varray_t *va, void *entry)
Add an entry to a void pointer array.
Definition: ocs_array.c:290
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
#define DEFAULT_SLAB_LEN
Definition: ocs_array.c:41
ocs_varray_t * ocs_varray_alloc(ocs_os_handle_t os, uint32_t array_count)
Allocate a void pointer array.
Definition: ocs_array.c:238