1 /*
2 * Copyright (c) 2015-2016 Los Alamos National Security, LLC.
3 * All rights reserved.
4 * Copyright (c) 2016 Cray Inc. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * BSD license below:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 */
34
35 #ifndef GNIX_VECTOR_H_
36 #define GNIX_VECTOR_H_
37
38 #include "gnix.h"
39 #include "gnix_util.h"
40
41 #include "stdlib.h"
42 #include "string.h"
43
44 /*******************************************************************************
45 * DATASTRUCTS
46 ******************************************************************************/
47 typedef enum gnix_vec_state {
48 GNIX_VEC_STATE_READY = 0xdeadbeef,
49 GNIX_VEC_STATE_DEAD,
50 } gnix_vec_state_e;
51
52 typedef enum gnix_vec_increase {
53 GNIX_VEC_INCREASE_ADD,
54 GNIX_VEC_INCREASE_MULT,
55 } gnix_vec_increase_e;
56
57 typedef enum gnix_vec_lock {
58 GNIX_VEC_UNLOCKED,
59 GNIX_VEC_LOCKED,
60 } gnix_vec_lock_e;
61
62 typedef uint32_t gnix_vec_index_t;
63 typedef void * gnix_vec_entry_t;
64
65 /**
66 * Set of attributes that MUST be initialized and passed to _gnix_vec_init.
67 *
68 * @var vec_initial_size Initial size of the vector
69 * @var vec_maximum_size Maximum size of the vector
70 * @var vec_increase_step Type of step to increase vector by, ADD or MULT
71 * @var vec_internal_locking GNIX_VEC_UNLOCKED for unlocked, otherwise locked
72 * @var creator fn required to properly alloc the vector element
73 */
74 typedef struct gnix_vec_attr {
75 uint32_t vec_initial_size;
76 uint32_t cur_size;
77 uint32_t vec_maximum_size;
78
79 uint32_t vec_increase_step;
80
81 gnix_vec_increase_e vec_increase_type;
82
83 gnix_vec_lock_e vec_internal_locking;
84 } gnix_vec_attr_t;
85
86 struct gnix_vector;
87
88 struct gnix_vector_iter {
89 struct gnix_vector *vec;
90 uint32_t cur_idx;
91 };
92
93 #define GNIX_VECTOR_ITERATOR(_vec, _iter) \
94 struct gnix_vector_iter _iter = { \
95 .vec = (_vec), \
96 .cur_idx = 0, \
97 }
98
99 /* Returns the current index of the iterator */
100 #define GNIX_VECTOR_ITERATOR_IDX(_iter) ((_iter).cur_idx - 1)
101
102 /**
103 * Vector operations
104 *
105 * @var insert_last Insert an entry into the last index of the vector.
106 * @var insert_at Insert an entry into the vector at the given index.
107 *
108 * @var remove_last Removes the last element from the vector.
109 * @var remove_at Removes the element at index from the vector.
110 *
111 * @var last Return the last element of the vector.
112 * @var at Return the element at the specified index.
113 *
114 * @var iter_next Return the element at the current index and move them
115 * index to the next element.
116 */
117 typedef struct gnix_vector_ops {
118 int (*resize)(struct gnix_vector *, uint32_t);
119
120 int (*insert_last)(struct gnix_vector *, gnix_vec_entry_t *);
121 int (*insert_at)(struct gnix_vector *, gnix_vec_entry_t *,
122 gnix_vec_index_t);
123
124 int (*remove_last)(struct gnix_vector *);
125 int (*remove_at)(struct gnix_vector *, gnix_vec_index_t);
126
127 int (*last)(struct gnix_vector *, void **);
128 int (*at)(struct gnix_vector *, void **, gnix_vec_index_t);
129
130 gnix_vec_entry_t *(*iter_next)(struct gnix_vector_iter *);
131 } gnix_vector_ops_t;
132
133 /**
134 * Vector handle
135 *
136 * @var state The current state of the vector instance.
137 * @var attr The attributes of this vector.
138 * @var ops The supported operations on this vector.
139 * @var vector The begging address of the vector.
140 * @var size The current size of the vector.
141 * @var lock A read/write lock for the vector.
142 */
143 typedef struct gnix_vector {
144 gnix_vec_state_e state;
145 gnix_vec_attr_t attr;
146 gnix_vector_ops_t *ops;
147 gnix_vec_entry_t *vector;
148 rwlock_t lock;
149 } gnix_vector_t;
150
151
152 /*******************************************************************************
153 * API Prototypes
154 ******************************************************************************/
155 /**
156 * Create the initial vector. The user is responsible for initializing the
157 * "attr" parameter prior to calling this function.
158 *
159 * @param[in] vec the vector to initialize
160 * @param[in] attr the vector attributes
161 *
162 * @return FI_SUCCESS Upon successfully creating the vector
163 * @return -FI_EINVAL Upon receiving an invalid parameter
164 * @return -FI_ENOMEM Upon insufficient memory to create the vector
165 */
166 int _gnix_vec_init(struct gnix_vector *vec, gnix_vec_attr_t *attr);
167
168 /**
169 * Close the vector elements and then the vector.
170 *
171 * @param[in] vec the vector to close
172 *
173 * @return FI_SUCCESS Upon successfully closing the vector
174 * @return -FI_EINVAL Upon a uninitialized or dead vector
175 */
176 int _gnix_vec_close(gnix_vector_t *vec);
177
178 /*******************************************************************************
179 * INLINE OPS FNS
180 ******************************************************************************/
181 /**
182 * Resize the vector to size.
183 *
184 * @param[in] vec the vector to resize
185 * @param[in] size the new size of the vector
186 *
187 * @return FI_SUCCESS Upon successfully resizing the vector
188 * @return -FI_EINVAL Upon passing a uninitialized or dead vector, a size
189 * less than the minimum vector size, or a size greater
190 * than the maximum vector size
191 * @return -FI_ENOMEM Upon running out of memory
192 */
_gnix_vec_resize(gnix_vector_t * vec,uint32_t size)193 static inline int _gnix_vec_resize(gnix_vector_t *vec, uint32_t size)
194 {
195 GNIX_TRACE(FI_LOG_EP_CTRL, "\n");
196
197 if (OFI_UNLIKELY(!vec)) {
198 GNIX_WARN(FI_LOG_EP_CTRL, "Invalid parameter to "
199 "_gnix_vec_resize.\n");
200 return -FI_EINVAL;
201 } else {
202 return vec->ops->resize(vec, size);
203 }
204 }
205
206 /**
207 * Get the element at index in the vector.
208 *
209 * @param[in] vec The vector to return an element from
210 * @param[in/out] element The element at the specified index in the vector
211 * @param[in] index The index of the desired element
212 *
213 * @return FI_SUCCESS Upon successfully returning the element
214 * @return -FI_EINVAL Upon passing a NULL or dead vector
215 * @return -FI_ECANCLED Upon attempting to get an empty element
216 */
_gnix_vec_at(gnix_vector_t * vec,void ** element,gnix_vec_index_t index)217 static inline int _gnix_vec_at(gnix_vector_t *vec, void **element,
218 gnix_vec_index_t index)
219 {
220 GNIX_TRACE(FI_LOG_EP_CTRL, "\n");
221
222 if (OFI_UNLIKELY(!vec || !element)) {
223 GNIX_WARN(FI_LOG_EP_CTRL, "Invalid parameter to "
224 "_gnix_vec_at\n");
225 return -FI_EINVAL;
226 } else {
227 return vec->ops->at(vec, element, index);
228 }
229 }
230
231 /**
232 * Get the first element in the vector.
233 *
234 * @param[in] vec The vector to return an element from
235 * @param[in/out] element the first element in the vector
236 *
237 * @return FI_SUCCESS Upon successfully returning the element
238 * @return -FI_EINVAL Upon passing a NULL or dead vector
239 * @return -FI_ECANCLED Upon attempting to get an empty element
240 */
_gnix_vec_last(gnix_vector_t * vec,void ** element)241 static inline int _gnix_vec_last(gnix_vector_t *vec, void **element)
242 {
243 GNIX_TRACE(FI_LOG_EP_CTRL, "\n");
244
245 if (OFI_UNLIKELY(!vec || !element)) {
246 GNIX_WARN(FI_LOG_EP_CTRL, "Invalid parameter to "
247 "_gnix_vec_last\n");
248 return -FI_EINVAL;
249 } else {
250 return vec->ops->last(vec, element);
251 }
252 }
253
254 /**
255 * Get the first element in the vector.
256 *
257 * @param[in] vec The vector to return an element from
258 * @param[in/out] element the first element in the vector
259 *
260 * @return FI_SUCCESS Upon successfully returning the element
261 * @return -FI_EINVAL Upon passing a NULL or dead vector
262 * @return -FI_ECANCLED Upon attempting to get an empty element
263 */
_gnix_vec_first(gnix_vector_t * vec,void ** element)264 static inline int _gnix_vec_first(gnix_vector_t *vec, void **element)
265 {
266 return _gnix_vec_at(vec, element, 0);
267 }
268
269 /**
270 * Removes the element at index from the vector. Note that
271 * the user is responsible for properly disconnecting and/or destroying
272 * this vector element.
273 *
274 * @param[in] vec the vector to remove an entry from
275 * @param[in] index the index of the entry to remove
276 *
277 * @return FI_SUCCESS Upon successfully removing the entry
278 * @return -FI_EINVAL Upon passing a dead vector
279 * @return -FI_ECANCELED Upon attempting to remove an empty entry
280 */
_gnix_vec_remove_at(gnix_vector_t * vec,gnix_vec_index_t index)281 static inline int _gnix_vec_remove_at(gnix_vector_t *vec,
282 gnix_vec_index_t index)
283 {
284 GNIX_TRACE(FI_LOG_EP_CTRL, "\n");
285
286 if (OFI_UNLIKELY(!vec)) {
287 GNIX_WARN(FI_LOG_EP_CTRL, "Invalid parameter to "
288 "_gnix_vec_remove_at\n");
289 return -FI_EINVAL;
290 } else {
291 return vec->ops->remove_at(vec, index);
292 }
293 }
294
295 /**
296 * Removes the last element from the vector. Note that
297 * the user is responsible for properly disconnecting and/or destroying
298 * this vector element.
299 *
300 * @param[in] vec the vector to remove an entry from
301 *
302 * @return FI_SUCCESS Upon successfully removing and destroying the entry
303 * @return -FI_EINVAL Upon passing a dead entry
304 * @return -FI_ECANCELED Upon attempting to remove an empty entry
305 */
_gnix_vec_remove_last(gnix_vector_t * vec)306 static inline int _gnix_vec_remove_last(gnix_vector_t *vec)
307 {
308 GNIX_TRACE(FI_LOG_EP_CTRL, "\n");
309
310 if (OFI_UNLIKELY(!vec)) {
311 GNIX_WARN(FI_LOG_EP_CTRL, "Invalid parameter to "
312 "_gnix_vec_remove_at\n");
313 return -FI_EINVAL;
314 } else {
315 return vec->ops->remove_last(vec);
316 }
317 }
318
319 /**
320 * Removes the first element from the vector. Note that
321 * the user is responsible for properly disconnecting and/or destroying
322 * this vector element.
323 *
324 * @param[in] vec the vector to remove an entry from
325 *
326 * @return FI_SUCCESS Upon successfully removing and destroying the entry
327 * @return -FI_EINVAL Upon passing a dead entry
328 * @return -FI_ECANCELED Upon attempting to remove an empty entry
329 */
_gnix_vec_remove_first(gnix_vector_t * vec)330 static inline int _gnix_vec_remove_first(gnix_vector_t *vec)
331 {
332 return _gnix_vec_remove_at(vec, 0);
333 }
334
335 /**
336 * Inserts an entry into the vector at the given index. If the current size
337 * of the vector is not large enough to satisfy the insertion then the vector
338 * will be grown up to the maximum size. If the entry at index is not empty
339 * the insertion will be canceled.
340 *
341 * @param[in] vec the vector to insert entry into
342 * @param[in] entry the item to insert into the vector
343 * @param[in] index the index to insert the item at
344 *
345 * @return FI_SUCCESS Upon successfully inserting the entry into the vector
346 * @return -FI_ENOMEM Upon exceeding the available memory
347 * @return -FI_EINVAL Upon passing a dead or null vector, or an index passed
348 * the maximum size.
349 * @return -FI_ECANCELED Upon an existing non-empty entry being found at index
350 * or reaching the maximum vector size.
351 */
_gnix_vec_insert_at(gnix_vector_t * vec,gnix_vec_entry_t * entry,gnix_vec_index_t index)352 static inline int _gnix_vec_insert_at(gnix_vector_t *vec,
353 gnix_vec_entry_t *entry,
354 gnix_vec_index_t index)
355 {
356 if (OFI_UNLIKELY(!vec || !entry)) {
357 GNIX_WARN(FI_LOG_EP_CTRL, "Invalid parameter to "
358 "_gnix_vec_insert_at\n");
359 return -FI_EINVAL;
360 } else {
361 return vec->ops->insert_at(vec, entry, index);
362 }
363 }
364
365 /**
366 * Inserts an entry into the last index of the vector. If the entry at the
367 * last index is not empty the insertion will be canceled.
368 *
369 * @param[in] vec the vector to insert entry into
370 * @param[in] entry the item to insert into the vector
371 *
372 * @return FI_SUCCESS Upon successfully inserting the entry into the vector
373 * @return -FI_EINVAL Upon passing a dead vector, or a null
374 * entry
375 * @return -FI_ECANCELED Upon an existing non-empty entry being found at the
376 * last index
377 */
_gnix_vec_insert_last(gnix_vector_t * vec,gnix_vec_entry_t * entry)378 static inline int _gnix_vec_insert_last(gnix_vector_t *vec,
379 gnix_vec_entry_t *entry)
380 {
381 if (OFI_UNLIKELY(!vec || !entry)) {
382 GNIX_WARN(FI_LOG_EP_CTRL, "Invalid parameter to "
383 "_gnix_vec_insert_last\n");
384 return -FI_EINVAL;
385 } else {
386 return vec->ops->insert_last(vec, entry);
387 }
388 }
389
390 /**
391 * Inserts an entry into the first index of the vector. If the entry at the
392 * first index is not empty the insertion will be canceled.
393 *
394 * @param[in] vec the vector to insert entry into
395 * @param[in] entry the item to insert into the vector
396 *
397 * @return FI_SUCCESS Upon successfully inserting the entry into the vector
398 * @return -FI_EINVAL Upon passing a dead vector, or a null
399 * entry
400 * @return -FI_ECANCELED Upon an existing non-empty entry being found at index 0
401 */
_gnix_vec_insert_first(gnix_vector_t * vec,gnix_vec_entry_t * entry)402 static inline int _gnix_vec_insert_first(gnix_vector_t *vec,
403 gnix_vec_entry_t *entry)
404 {
405 return _gnix_vec_insert_at(vec, entry, 0);
406 }
407
408 /**
409 * Return the current element in the vector iterator and move
410 * the iterator to the next element.
411 *
412 * @param iter pointer to the vector iterator
413 * @return pointer to current element in the vector
414 */
415 static inline
_gnix_vec_iterator_next(struct gnix_vector_iter * iter)416 gnix_vec_entry_t *_gnix_vec_iterator_next(struct gnix_vector_iter *iter)
417 {
418 if (iter == NULL) {
419 GNIX_WARN(FI_LOG_EP_DATA, "Invalid parameter to"
420 "_gnix_vec_iterator_next\n");
421 return NULL;
422 } else {
423 return iter->vec->ops->iter_next(iter);
424 }
425 }
426
427 #endif /* GNIX_VECTOR_H_ */
428