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