cl_list.c revision 219820
1/*
2 * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. 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 * OpenIB.org 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
36/*
37 * Abstract:
38 *	Implementation of quick list, and list.
39 *
40 */
41
42#if HAVE_CONFIG_H
43#  include <config.h>
44#endif				/* HAVE_CONFIG_H */
45
46#include <complib/cl_qlist.h>
47#include <complib/cl_list.h>
48
49#define FREE_ITEM_GROW_SIZE		10
50
51/******************************************************************************
52*******************************************************************************
53**************													   ************
54**************			 IMPLEMENTATION OF QUICK LIST			   ************
55**************													   ************
56*******************************************************************************
57******************************************************************************/
58void
59cl_qlist_insert_array_head(IN cl_qlist_t * const p_list,
60			   IN cl_list_item_t * const p_array,
61			   IN uint32_t item_count, IN const uint32_t item_size)
62{
63	cl_list_item_t *p_item;
64
65	CL_ASSERT(p_list);
66	CL_ASSERT(p_list->state == CL_INITIALIZED);
67	CL_ASSERT(p_array);
68	CL_ASSERT(item_size >= sizeof(cl_list_item_t));
69	CL_ASSERT(item_count);
70
71	/*
72	 * To add items from the array to the list in the same order as
73	 * the elements appear in the array, we add them starting with
74	 * the last one first.  Locate the last item.
75	 */
76	p_item = (cl_list_item_t *) ((uint8_t *) p_array +
77				     (item_size * (item_count - 1)));
78
79	/* Continue to add all items to the list. */
80	while (item_count--) {
81		cl_qlist_insert_head(p_list, p_item);
82
83		/* Get the next object to add to the list. */
84		p_item = (cl_list_item_t *) ((uint8_t *) p_item - item_size);
85	}
86}
87
88void
89cl_qlist_insert_array_tail(IN cl_qlist_t * const p_list,
90			   IN cl_list_item_t * const p_array,
91			   IN uint32_t item_count, IN const uint32_t item_size)
92{
93	cl_list_item_t *p_item;
94
95	CL_ASSERT(p_list);
96	CL_ASSERT(p_list->state == CL_INITIALIZED);
97	CL_ASSERT(p_array);
98	CL_ASSERT(item_size >= sizeof(cl_list_item_t));
99	CL_ASSERT(item_count);
100
101	/* Set the first item to add to the list. */
102	p_item = p_array;
103
104	/* Continue to add all items to the list. */
105	while (item_count--) {
106		cl_qlist_insert_tail(p_list, p_item);
107
108		/* Get the next object to add to the list. */
109		p_item = (cl_list_item_t *) ((uint8_t *) p_item + item_size);
110	}
111}
112
113void
114cl_qlist_insert_list_head(IN cl_qlist_t * const p_dest_list,
115			  IN cl_qlist_t * const p_src_list)
116{
117#if defined( _DEBUG_ )
118	cl_list_item_t *p_item;
119#endif
120
121	CL_ASSERT(p_dest_list);
122	CL_ASSERT(p_src_list);
123	CL_ASSERT(p_dest_list->state == CL_INITIALIZED);
124	CL_ASSERT(p_src_list->state == CL_INITIALIZED);
125
126	/*
127	 * Is the src list empty?
128	 * We must have this check here for code below to work.
129	 */
130	if (cl_is_qlist_empty(p_src_list))
131		return;
132
133#if defined( _DEBUG_ )
134	/* Check that all items in the source list belong there. */
135	p_item = cl_qlist_head(p_src_list);
136	while (p_item != cl_qlist_end(p_src_list)) {
137		/* All list items in the source list must point to it. */
138		CL_ASSERT(p_item->p_list == p_src_list);
139		/* Point them all to the destination list. */
140		p_item->p_list = p_dest_list;
141		p_item = cl_qlist_next(p_item);
142	}
143#endif
144
145	/* Chain the destination list to the tail of the source list. */
146	cl_qlist_tail(p_src_list)->p_next = cl_qlist_head(p_dest_list);
147	cl_qlist_head(p_dest_list)->p_prev = cl_qlist_tail(p_src_list);
148
149	/*
150	 * Update the head of the destination list to the head of
151	 * the source list.
152	 */
153	p_dest_list->end.p_next = cl_qlist_head(p_src_list);
154	cl_qlist_head(p_src_list)->p_prev = &p_dest_list->end;
155
156	/*
157	 * Update the count of the destination to reflect the source items having
158	 * been added.
159	 */
160	p_dest_list->count += p_src_list->count;
161
162	/* Update source list to reflect being empty. */
163	__cl_qlist_reset(p_src_list);
164}
165
166void
167cl_qlist_insert_list_tail(IN cl_qlist_t * const p_dest_list,
168			  IN cl_qlist_t * const p_src_list)
169{
170#if defined( _DEBUG_ )
171	cl_list_item_t *p_item;
172#endif
173
174	CL_ASSERT(p_dest_list);
175	CL_ASSERT(p_src_list);
176	CL_ASSERT(p_dest_list->state == CL_INITIALIZED);
177	CL_ASSERT(p_src_list->state == CL_INITIALIZED);
178
179	/*
180	 * Is the src list empty?
181	 * We must have this check here for code below to work.
182	 */
183	if (cl_is_qlist_empty(p_src_list))
184		return;
185
186#if defined( _DEBUG_ )
187	/* Check that all items in the source list belong there. */
188	p_item = cl_qlist_head(p_src_list);
189	while (p_item != cl_qlist_end(p_src_list)) {
190		/* All list items in the source list must point to it. */
191		CL_ASSERT(p_item->p_list == p_src_list);
192		/* Point them all to the destination list. */
193		p_item->p_list = p_dest_list;
194		p_item = cl_qlist_next(p_item);
195	}
196#endif
197
198	/* Chain the source list to the tail of the destination list. */
199	cl_qlist_tail(p_dest_list)->p_next = cl_qlist_head(p_src_list);
200	cl_qlist_head(p_src_list)->p_prev = cl_qlist_tail(p_dest_list);
201
202	/*
203	 * Update the tail of the destination list to the tail of
204	 * the source list.
205	 */
206	p_dest_list->end.p_prev = cl_qlist_tail(p_src_list);
207	cl_qlist_tail(p_src_list)->p_next = &p_dest_list->end;
208
209	/*
210	 * Update the count of the destination to reflect the source items having
211	 * been added.
212	 */
213	p_dest_list->count += p_src_list->count;
214
215	/* Update source list to reflect being empty. */
216	__cl_qlist_reset(p_src_list);
217}
218
219boolean_t
220cl_is_item_in_qlist(IN const cl_qlist_t * const p_list,
221		    IN const cl_list_item_t * const p_list_item)
222{
223	const cl_list_item_t *p_temp;
224
225	CL_ASSERT(p_list);
226	CL_ASSERT(p_list_item);
227	CL_ASSERT(p_list->state == CL_INITIALIZED);
228
229	/* Traverse looking for a match */
230	p_temp = cl_qlist_head(p_list);
231	while (p_temp != cl_qlist_end(p_list)) {
232		if (p_temp == p_list_item) {
233			CL_ASSERT(p_list_item->p_list == p_list);
234			return (TRUE);
235		}
236
237		p_temp = cl_qlist_next(p_temp);
238	}
239
240	return (FALSE);
241}
242
243cl_list_item_t *cl_qlist_find_next(IN const cl_qlist_t * const p_list,
244				   IN const cl_list_item_t * const p_list_item,
245				   IN cl_pfn_qlist_find_t pfn_func,
246				   IN const void *const context)
247{
248	cl_list_item_t *p_found_item;
249
250	CL_ASSERT(p_list);
251	CL_ASSERT(p_list->state == CL_INITIALIZED);
252	CL_ASSERT(p_list_item);
253	CL_ASSERT(p_list_item->p_list == p_list);
254	CL_ASSERT(pfn_func);
255
256	p_found_item = cl_qlist_next(p_list_item);
257
258	/* The user provided a compare function */
259	while (p_found_item != cl_qlist_end(p_list)) {
260		CL_ASSERT(p_found_item->p_list == p_list);
261
262		if (pfn_func(p_found_item, (void *)context) == CL_SUCCESS)
263			break;
264
265		p_found_item = cl_qlist_next(p_found_item);
266	}
267
268	/* No match */
269	return (p_found_item);
270}
271
272cl_list_item_t *cl_qlist_find_prev(IN const cl_qlist_t * const p_list,
273				   IN const cl_list_item_t * const p_list_item,
274				   IN cl_pfn_qlist_find_t pfn_func,
275				   IN const void *const context)
276{
277	cl_list_item_t *p_found_item;
278
279	CL_ASSERT(p_list);
280	CL_ASSERT(p_list->state == CL_INITIALIZED);
281	CL_ASSERT(p_list_item);
282	CL_ASSERT(p_list_item->p_list == p_list);
283	CL_ASSERT(pfn_func);
284
285	p_found_item = cl_qlist_prev(p_list_item);
286
287	/* The user provided a compare function */
288	while (p_found_item != cl_qlist_end(p_list)) {
289		CL_ASSERT(p_found_item->p_list == p_list);
290
291		if (pfn_func(p_found_item, (void *)context) == CL_SUCCESS)
292			break;
293
294		p_found_item = cl_qlist_prev(p_found_item);
295	}
296
297	/* No match */
298	return (p_found_item);
299}
300
301void
302cl_qlist_apply_func(IN const cl_qlist_t * const p_list,
303		    IN cl_pfn_qlist_apply_t pfn_func,
304		    IN const void *const context)
305{
306	cl_list_item_t *p_list_item;
307
308	/* Note that context can have any arbitrary value. */
309	CL_ASSERT(p_list);
310	CL_ASSERT(p_list->state == CL_INITIALIZED);
311	CL_ASSERT(pfn_func);
312
313	p_list_item = cl_qlist_head(p_list);
314	while (p_list_item != cl_qlist_end(p_list)) {
315		pfn_func(p_list_item, (void *)context);
316		p_list_item = cl_qlist_next(p_list_item);
317	}
318}
319
320void
321cl_qlist_move_items(IN cl_qlist_t * const p_src_list,
322		    IN cl_qlist_t * const p_dest_list,
323		    IN cl_pfn_qlist_find_t pfn_func,
324		    IN const void *const context)
325{
326	cl_list_item_t *p_current_item, *p_next;
327
328	CL_ASSERT(p_src_list);
329	CL_ASSERT(p_dest_list);
330	CL_ASSERT(p_src_list->state == CL_INITIALIZED);
331	CL_ASSERT(p_dest_list->state == CL_INITIALIZED);
332	CL_ASSERT(pfn_func);
333
334	p_current_item = cl_qlist_head(p_src_list);
335
336	while (p_current_item != cl_qlist_end(p_src_list)) {
337		/* Before we do anything, get a pointer to the next item. */
338		p_next = cl_qlist_next(p_current_item);
339
340		if (pfn_func(p_current_item, (void *)context) == CL_SUCCESS) {
341			/* Move the item from one list to the other. */
342			cl_qlist_remove_item(p_src_list, p_current_item);
343			cl_qlist_insert_tail(p_dest_list, p_current_item);
344		}
345		p_current_item = p_next;
346	}
347}
348
349/******************************************************************************
350*******************************************************************************
351**************													   ************
352**************			 IMPLEMENTATION OF LIST					   ************
353**************													   ************
354*******************************************************************************
355******************************************************************************/
356void cl_list_construct(IN cl_list_t * const p_list)
357{
358	CL_ASSERT(p_list);
359
360	cl_qpool_construct(&p_list->list_item_pool);
361}
362
363cl_status_t cl_list_init(IN cl_list_t * const p_list, IN const size_t min_items)
364{
365	uint32_t grow_size;
366
367	CL_ASSERT(p_list);
368	cl_qlist_init(&p_list->list);
369
370	/*
371	 * We will grow by min_items/8 items at a time, with a minimum of
372	 * FREE_ITEM_GROW_SIZE.
373	 */
374	grow_size = (uint32_t) min_items >> 3;
375	if (grow_size < FREE_ITEM_GROW_SIZE)
376		grow_size = FREE_ITEM_GROW_SIZE;
377
378	/* Initialize the pool of list items. */
379	return (cl_qpool_init(&p_list->list_item_pool, min_items, 0, grow_size,
380			      sizeof(cl_pool_obj_t), NULL, NULL, NULL));
381}
382
383void cl_list_destroy(IN cl_list_t * const p_list)
384{
385	CL_ASSERT(p_list);
386
387	cl_qpool_destroy(&p_list->list_item_pool);
388}
389
390static cl_status_t
391cl_list_find_cb(IN const cl_list_item_t * const p_list_item,
392		IN void *const context)
393{
394	CL_ASSERT(p_list_item);
395
396	if (cl_list_obj(p_list_item) == context)
397		return (CL_SUCCESS);
398
399	return (CL_NOT_FOUND);
400}
401
402cl_status_t
403cl_list_remove_object(IN cl_list_t * const p_list,
404		      IN const void *const p_object)
405{
406	cl_list_item_t *p_list_item;
407
408	CL_ASSERT(p_list);
409	CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool));
410
411	/* find the item in question */
412	p_list_item =
413	    cl_qlist_find_from_head(&p_list->list, cl_list_find_cb, p_object);
414	if (p_list_item != cl_qlist_end(&p_list->list)) {
415		/* remove this item */
416		cl_qlist_remove_item(&p_list->list, p_list_item);
417		cl_qpool_put(&p_list->list_item_pool,
418			     (cl_pool_item_t *) p_list_item);
419		return (CL_SUCCESS);
420	}
421	return (CL_NOT_FOUND);
422}
423
424boolean_t
425cl_is_object_in_list(IN const cl_list_t * const p_list,
426		     IN const void *const p_object)
427{
428	CL_ASSERT(p_list);
429	CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool));
430
431	return (cl_qlist_find_from_head
432		(&p_list->list, cl_list_find_cb, p_object)
433		!= cl_qlist_end(&p_list->list));
434}
435
436cl_status_t
437cl_list_insert_array_head(IN cl_list_t * const p_list,
438			  IN const void *const p_array,
439			  IN uint32_t item_count, IN const uint32_t item_size)
440{
441	cl_status_t status;
442	void *p_object;
443
444	CL_ASSERT(p_list);
445	CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool));
446	CL_ASSERT(p_array);
447	CL_ASSERT(item_size);
448	CL_ASSERT(item_count);
449
450	/*
451	 * To add items from the array to the list in the same order as
452	 * the elements appear in the array, we add them starting with
453	 * the last one first.  Locate the last item.
454	 */
455	p_object = ((uint8_t *) p_array + (item_size * (item_count - 1)));
456
457	/* Continue to add all items to the list. */
458	while (item_count--) {
459		status = cl_list_insert_head(p_list, p_object);
460		if (status != CL_SUCCESS) {
461			/* Remove all items that have been inserted. */
462			while (item_count++ < item_count)
463				cl_list_remove_head(p_list);
464			return (status);
465		}
466
467		/* Get the next object to add to the list. */
468		p_object = ((uint8_t *) p_object - item_size);
469	}
470
471	return (CL_SUCCESS);
472}
473
474cl_status_t
475cl_list_insert_array_tail(IN cl_list_t * const p_list,
476			  IN const void *const p_array,
477			  IN uint32_t item_count, IN const uint32_t item_size)
478{
479	cl_status_t status;
480	void *p_object;
481
482	CL_ASSERT(p_list);
483	CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool));
484	CL_ASSERT(p_array);
485	CL_ASSERT(item_size);
486	CL_ASSERT(item_count);
487
488	/* Set the first item to add to the list. */
489	p_object = (void *)p_array;
490
491	/* Continue to add all items to the list. */
492	while (item_count--) {
493		status = cl_list_insert_tail(p_list, p_object);
494		if (status != CL_SUCCESS) {
495			/* Remove all items that have been inserted. */
496			while (item_count++ < item_count)
497				cl_list_remove_tail(p_list);
498			return (status);
499		}
500
501		/* Get the next object to add to the list. */
502		p_object = ((uint8_t *) p_object + item_size);
503	}
504
505	return (CL_SUCCESS);
506}
507
508cl_list_iterator_t
509cl_list_find_from_head(IN const cl_list_t * const p_list,
510		       IN cl_pfn_list_find_t pfn_func,
511		       IN const void *const context)
512{
513	cl_status_t status;
514	cl_list_iterator_t itor;
515
516	/* Note that context can have any arbitrary value. */
517	CL_ASSERT(p_list);
518	CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool));
519	CL_ASSERT(pfn_func);
520
521	itor = cl_list_head(p_list);
522
523	while (itor != cl_list_end(p_list)) {
524		status = pfn_func(cl_list_obj(itor), (void *)context);
525		if (status == CL_SUCCESS)
526			break;
527
528		itor = cl_list_next(itor);
529	}
530
531	/* no match */
532	return (itor);
533}
534
535cl_list_iterator_t
536cl_list_find_from_tail(IN const cl_list_t * const p_list,
537		       IN cl_pfn_list_find_t pfn_func,
538		       IN const void *const context)
539{
540	cl_status_t status;
541	cl_list_iterator_t itor;
542
543	/* Note that context can have any arbitrary value. */
544	CL_ASSERT(p_list);
545	CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool));
546	CL_ASSERT(pfn_func);
547
548	itor = cl_list_tail(p_list);
549
550	while (itor != cl_list_end(p_list)) {
551		status = pfn_func(cl_list_obj(itor), (void *)context);
552		if (status == CL_SUCCESS)
553			break;
554
555		itor = cl_list_prev(itor);
556	}
557
558	/* no match */
559	return (itor);
560}
561
562void
563cl_list_apply_func(IN const cl_list_t * const p_list,
564		   IN cl_pfn_list_apply_t pfn_func,
565		   IN const void *const context)
566{
567	cl_list_iterator_t itor;
568
569	/* Note that context can have any arbitrary value. */
570	CL_ASSERT(p_list);
571	CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool));
572	CL_ASSERT(pfn_func);
573
574	itor = cl_list_head(p_list);
575
576	while (itor != cl_list_end(p_list)) {
577		pfn_func(cl_list_obj(itor), (void *)context);
578
579		itor = cl_list_next(itor);
580	}
581}
582