]> git.proxmox.com Git - mirror_spl.git/blame - lib/list.c
Update README: run autogen first
[mirror_spl.git] / lib / list.c
CommitLineData
564f6d15 1/*****************************************************************************
716154c5
BB
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2001-2007 The Regents of the University of California.
564f6d15 4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Chris Dunlap <cdunlap@llnl.gov>.
716154c5 6 * UCRL-CODE-235197
564f6d15 7 *
8 * This file is from LSD-Tools, the LLNL Software Development Toolbox.
9 *
716154c5
BB
10 * LSD-Tools is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
564f6d15 14 *
15 * LSD-Tools is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
716154c5
BB
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * for more details.
564f6d15 19 *
20 * You should have received a copy of the GNU General Public License along
716154c5 21 * with LSD-Tools. If not, see <http://www.gnu.org/licenses/>.
564f6d15 22 *****************************************************************************
23 * Refer to "list.h" for documentation on public functions.
24 *****************************************************************************/
25
564f6d15 26#ifdef WITH_PTHREADS
27# include <pthread.h>
28#endif /* WITH_PTHREADS */
29
30#include <assert.h>
31#include <errno.h>
32#include <stdlib.h>
33#include <string.h>
34#include "list.h"
35
36
37/*********************
38 * lsd_fatal_error *
39 *********************/
40
41#ifdef WITH_LSD_FATAL_ERROR_FUNC
42# undef lsd_fatal_error
43 extern void lsd_fatal_error(char *file, int line, char *mesg);
44#else /* !WITH_LSD_FATAL_ERROR_FUNC */
45# ifndef lsd_fatal_error
46# include <errno.h>
47# include <stdio.h>
48# include <string.h>
49# define lsd_fatal_error(file, line, mesg) \
50 do { \
51 fprintf(stderr, "ERROR: [%s:%d] %s: %s\n", \
52 file, line, mesg, strerror(errno)); \
53 } while (0)
54# endif /* !lsd_fatal_error */
55#endif /* !WITH_LSD_FATAL_ERROR_FUNC */
56
57
58/*********************
59 * lsd_nomem_error *
60 *********************/
61
62#ifdef WITH_LSD_NOMEM_ERROR_FUNC
63# undef lsd_nomem_error
64 extern void * lsd_nomem_error(char *file, int line, char *mesg);
65#else /* !WITH_LSD_NOMEM_ERROR_FUNC */
66# ifndef lsd_nomem_error
67# define lsd_nomem_error(file, line, mesg) (NULL)
68# endif /* !lsd_nomem_error */
69#endif /* !WITH_LSD_NOMEM_ERROR_FUNC */
70
71
72/***************
73 * Constants *
74 ***************/
75
76#define LIST_ALLOC 32
77#define LIST_MAGIC 0xDEADBEEF
78
79
80/****************
81 * Data Types *
82 ****************/
83
84struct listNode {
85 void *data; /* node's data */
86 struct listNode *next; /* next node in list */
87};
88
89struct listIterator {
90 struct list *list; /* the list being iterated */
91 struct listNode *pos; /* the next node to be iterated */
92 struct listNode **prev; /* addr of 'next' ptr to prv It node */
93 struct listIterator *iNext; /* iterator chain for list_destroy() */
94#ifndef NDEBUG
95 unsigned int magic; /* sentinel for asserting validity */
96#endif /* !NDEBUG */
97};
98
99struct list {
100 struct listNode *head; /* head of the list */
101 struct listNode **tail; /* addr of last node's 'next' ptr */
102 struct listIterator *iNext; /* iterator chain for list_destroy() */
103 ListDelF fDel; /* function to delete node data */
104 int count; /* number of nodes in list */
105#ifdef WITH_PTHREADS
106 pthread_mutex_t mutex; /* mutex to protect access to list */
107#endif /* WITH_PTHREADS */
108#ifndef NDEBUG
109 unsigned int magic; /* sentinel for asserting validity */
110#endif /* !NDEBUG */
111};
112
113typedef struct listNode * ListNode;
114
115
116/****************
117 * Prototypes *
118 ****************/
119
120static void * list_node_create (List l, ListNode *pp, void *x);
121static void * list_node_destroy (List l, ListNode *pp);
122static List list_alloc (void);
123static void list_free (List l);
124static ListNode list_node_alloc (void);
125static void list_node_free (ListNode p);
126static ListIterator list_iterator_alloc (void);
127static void list_iterator_free (ListIterator i);
128static void * list_alloc_aux (int size, void *pfreelist);
129static void list_free_aux (void *x, void *pfreelist);
130
131
132/***************
133 * Variables *
134 ***************/
135
136static List list_free_lists = NULL;
137static ListNode list_free_nodes = NULL;
138static ListIterator list_free_iterators = NULL;
139
140#ifdef WITH_PTHREADS
141static pthread_mutex_t list_free_lock = PTHREAD_MUTEX_INITIALIZER;
142#endif /* WITH_PTHREADS */
143
144
145/************
146 * Macros *
147 ************/
148
149#ifdef WITH_PTHREADS
150
151# define list_mutex_init(mutex) \
152 do { \
153 int e = pthread_mutex_init(mutex, NULL); \
154 if (e != 0) { \
155 errno = e; \
156 lsd_fatal_error(__FILE__, __LINE__, "list mutex init"); \
157 abort(); \
158 } \
159 } while (0)
160
161# define list_mutex_lock(mutex) \
162 do { \
163 int e = pthread_mutex_lock(mutex); \
164 if (e != 0) { \
165 errno = e; \
166 lsd_fatal_error(__FILE__, __LINE__, "list mutex lock"); \
167 abort(); \
168 } \
169 } while (0)
170
171# define list_mutex_unlock(mutex) \
172 do { \
173 int e = pthread_mutex_unlock(mutex); \
174 if (e != 0) { \
175 errno = e; \
176 lsd_fatal_error(__FILE__, __LINE__, "list mutex unlock"); \
177 abort(); \
178 } \
179 } while (0)
180
181# define list_mutex_destroy(mutex) \
182 do { \
183 int e = pthread_mutex_destroy(mutex); \
184 if (e != 0) { \
185 errno = e; \
186 lsd_fatal_error(__FILE__, __LINE__, "list mutex destroy"); \
187 abort(); \
188 } \
189 } while (0)
190
191# ifndef NDEBUG
192 static int list_mutex_is_locked (pthread_mutex_t *mutex);
193# endif /* !NDEBUG */
194
195#else /* !WITH_PTHREADS */
196
197# define list_mutex_init(mutex)
198# define list_mutex_lock(mutex)
199# define list_mutex_unlock(mutex)
200# define list_mutex_destroy(mutex)
201# define list_mutex_is_locked(mutex) (1)
202
203#endif /* !WITH_PTHREADS */
204
205
206/***************
207 * Functions *
208 ***************/
209
210List
211list_create (ListDelF f)
212{
213 List l;
214
215 if (!(l = list_alloc()))
216 return(lsd_nomem_error(__FILE__, __LINE__, "list create"));
217 l->head = NULL;
218 l->tail = &l->head;
219 l->iNext = NULL;
220 l->fDel = f;
221 l->count = 0;
222 list_mutex_init(&l->mutex);
481762f6
OF
223#ifndef NDEBUG
224 l->magic = LIST_MAGIC;
225#endif
564f6d15 226 return(l);
227}
228
229
230void
231list_destroy (List l)
232{
233 ListIterator i, iTmp;
234 ListNode p, pTmp;
235
236 assert(l != NULL);
237 list_mutex_lock(&l->mutex);
238 assert(l->magic == LIST_MAGIC);
239 i = l->iNext;
240 while (i) {
241 assert(i->magic == LIST_MAGIC);
242 iTmp = i->iNext;
481762f6
OF
243#ifndef NDEBUG
244 i->magic = ~LIST_MAGIC;
245#endif /* !NDEBUG */
564f6d15 246 list_iterator_free(i);
247 i = iTmp;
248 }
249 p = l->head;
250 while (p) {
251 pTmp = p->next;
252 if (p->data && l->fDel)
253 l->fDel(p->data);
254 list_node_free(p);
255 p = pTmp;
256 }
481762f6
OF
257#ifndef NDEBUG
258 l->magic = ~LIST_MAGIC;
259#endif /* !NDEBUG */
564f6d15 260 list_mutex_unlock(&l->mutex);
261 list_mutex_destroy(&l->mutex);
262 list_free(l);
263 return;
264}
265
266
267int
268list_is_empty (List l)
269{
270 int n;
271
272 assert(l != NULL);
273 list_mutex_lock(&l->mutex);
274 assert(l->magic == LIST_MAGIC);
275 n = l->count;
276 list_mutex_unlock(&l->mutex);
277 return(n == 0);
278}
279
280
281int
282list_count (List l)
283{
284 int n;
285
286 assert(l != NULL);
287 list_mutex_lock(&l->mutex);
288 assert(l->magic == LIST_MAGIC);
289 n = l->count;
290 list_mutex_unlock(&l->mutex);
291 return(n);
292}
293
294
295void *
296list_append (List l, void *x)
297{
298 void *v;
299
300 assert(l != NULL);
301 assert(x != NULL);
302 list_mutex_lock(&l->mutex);
303 assert(l->magic == LIST_MAGIC);
304 v = list_node_create(l, l->tail, x);
305 list_mutex_unlock(&l->mutex);
306 return(v);
307}
308
309
310void *
311list_prepend (List l, void *x)
312{
313 void *v;
314
315 assert(l != NULL);
316 assert(x != NULL);
317 list_mutex_lock(&l->mutex);
318 assert(l->magic == LIST_MAGIC);
319 v = list_node_create(l, &l->head, x);
320 list_mutex_unlock(&l->mutex);
321 return(v);
322}
323
324
325void *
326list_find_first (List l, ListFindF f, void *key)
327{
328 ListNode p;
329 void *v = NULL;
330
331 assert(l != NULL);
332 assert(f != NULL);
333 list_mutex_lock(&l->mutex);
334 assert(l->magic == LIST_MAGIC);
335 for (p=l->head; p; p=p->next) {
336 if (f(p->data, key)) {
337 v = p->data;
338 break;
339 }
340 }
341 list_mutex_unlock(&l->mutex);
342 return(v);
343}
344
345
346int
347list_delete_all (List l, ListFindF f, void *key)
348{
349 ListNode *pp;
350 void *v;
351 int n = 0;
352
353 assert(l != NULL);
354 assert(f != NULL);
355 list_mutex_lock(&l->mutex);
356 assert(l->magic == LIST_MAGIC);
357 pp = &l->head;
358 while (*pp) {
359 if (f((*pp)->data, key)) {
360 if ((v = list_node_destroy(l, pp))) {
361 if (l->fDel)
362 l->fDel(v);
363 n++;
364 }
365 }
366 else {
367 pp = &(*pp)->next;
368 }
369 }
370 list_mutex_unlock(&l->mutex);
371 return(n);
372}
373
374
375int
376list_for_each (List l, ListForF f, void *arg)
377{
378 ListNode p;
379 int n = 0;
380
381 assert(l != NULL);
382 assert(f != NULL);
383 list_mutex_lock(&l->mutex);
384 assert(l->magic == LIST_MAGIC);
385 for (p=l->head; p; p=p->next) {
386 n++;
387 if (f(p->data, arg) < 0) {
388 n = -n;
389 break;
390 }
391 }
392 list_mutex_unlock(&l->mutex);
393 return(n);
394}
395
396
397void
398list_sort (List l, ListCmpF f)
399{
400/* Note: Time complexity O(n^2).
401 */
402 ListNode *pp, *ppPrev, *ppPos, pTmp;
403 ListIterator i;
404
405 assert(l != NULL);
406 assert(f != NULL);
407 list_mutex_lock(&l->mutex);
408 assert(l->magic == LIST_MAGIC);
409 if (l->count > 1) {
410 ppPrev = &l->head;
411 pp = &(*ppPrev)->next;
412 while (*pp) {
413 if (f((*pp)->data, (*ppPrev)->data) < 0) {
414 ppPos = &l->head;
415 while (f((*pp)->data, (*ppPos)->data) >= 0)
416 ppPos = &(*ppPos)->next;
417 pTmp = (*pp)->next;
418 (*pp)->next = *ppPos;
419 *ppPos = *pp;
420 *pp = pTmp;
421 if (ppPrev == ppPos)
422 ppPrev = &(*ppPrev)->next;
423 }
424 else {
425 ppPrev = pp;
426 pp = &(*pp)->next;
427 }
428 }
429 l->tail = pp;
430
431 for (i=l->iNext; i; i=i->iNext) {
432 assert(i->magic == LIST_MAGIC);
433 i->pos = i->list->head;
434 i->prev = &i->list->head;
435 }
436 }
437 list_mutex_unlock(&l->mutex);
438 return;
439}
440
441
442void *
443list_push (List l, void *x)
444{
445 void *v;
446
447 assert(l != NULL);
448 assert(x != NULL);
449 list_mutex_lock(&l->mutex);
450 assert(l->magic == LIST_MAGIC);
451 v = list_node_create(l, &l->head, x);
452 list_mutex_unlock(&l->mutex);
453 return(v);
454}
455
456
457void *
458list_pop (List l)
459{
460 void *v;
461
462 assert(l != NULL);
463 list_mutex_lock(&l->mutex);
464 assert(l->magic == LIST_MAGIC);
465 v = list_node_destroy(l, &l->head);
466 list_mutex_unlock(&l->mutex);
467 return(v);
468}
469
470
471void *
472list_peek (List l)
473{
474 void *v;
475
476 assert(l != NULL);
477 list_mutex_lock(&l->mutex);
478 assert(l->magic == LIST_MAGIC);
479 v = (l->head) ? l->head->data : NULL;
480 list_mutex_unlock(&l->mutex);
481 return(v);
482}
483
484
485void *
486list_enqueue (List l, void *x)
487{
488 void *v;
489
490 assert(l != NULL);
491 assert(x != NULL);
492 list_mutex_lock(&l->mutex);
493 assert(l->magic == LIST_MAGIC);
494 v = list_node_create(l, l->tail, x);
495 list_mutex_unlock(&l->mutex);
496 return(v);
497}
498
499
500void *
501list_dequeue (List l)
502{
503 void *v;
504
505 assert(l != NULL);
506 list_mutex_lock(&l->mutex);
507 assert(l->magic == LIST_MAGIC);
508 v = list_node_destroy(l, &l->head);
509 list_mutex_unlock(&l->mutex);
510 return(v);
511}
512
513
514ListIterator
515list_iterator_create (List l)
516{
517 ListIterator i;
518
519 assert(l != NULL);
520 if (!(i = list_iterator_alloc()))
521 return(lsd_nomem_error(__FILE__, __LINE__, "list iterator create"));
522 i->list = l;
523 list_mutex_lock(&l->mutex);
524 assert(l->magic == LIST_MAGIC);
525 i->pos = l->head;
526 i->prev = &l->head;
527 i->iNext = l->iNext;
528 l->iNext = i;
481762f6
OF
529#ifndef NDEBUG
530 i->magic = LIST_MAGIC;
531#endif /* !NDEBUG */
564f6d15 532 list_mutex_unlock(&l->mutex);
533 return(i);
534}
535
536
537void
538list_iterator_reset (ListIterator i)
539{
540 assert(i != NULL);
541 assert(i->magic == LIST_MAGIC);
542 list_mutex_lock(&i->list->mutex);
543 assert(i->list->magic == LIST_MAGIC);
544 i->pos = i->list->head;
545 i->prev = &i->list->head;
546 list_mutex_unlock(&i->list->mutex);
547 return;
548}
549
550
551void
552list_iterator_destroy (ListIterator i)
553{
554 ListIterator *pi;
555
556 assert(i != NULL);
557 assert(i->magic == LIST_MAGIC);
558 list_mutex_lock(&i->list->mutex);
559 assert(i->list->magic == LIST_MAGIC);
560 for (pi=&i->list->iNext; *pi; pi=&(*pi)->iNext) {
561 assert((*pi)->magic == LIST_MAGIC);
562 if (*pi == i) {
563 *pi = (*pi)->iNext;
564 break;
565 }
566 }
567 list_mutex_unlock(&i->list->mutex);
481762f6
OF
568#ifndef NDEBUG
569 i->magic = ~LIST_MAGIC;
570#endif /* !NDEBUG */
564f6d15 571 list_iterator_free(i);
572 return;
573}
574
575
576void *
577list_next (ListIterator i)
578{
579 ListNode p;
580
581 assert(i != NULL);
582 assert(i->magic == LIST_MAGIC);
583 list_mutex_lock(&i->list->mutex);
584 assert(i->list->magic == LIST_MAGIC);
585 if ((p = i->pos))
586 i->pos = p->next;
587 if (*i->prev != p)
588 i->prev = &(*i->prev)->next;
589 list_mutex_unlock(&i->list->mutex);
590 return(p ? p->data : NULL);
591}
592
593
594void *
595list_insert (ListIterator i, void *x)
596{
597 void *v;
598
599 assert(i != NULL);
600 assert(x != NULL);
601 assert(i->magic == LIST_MAGIC);
602 list_mutex_lock(&i->list->mutex);
603 assert(i->list->magic == LIST_MAGIC);
604 v = list_node_create(i->list, i->prev, x);
605 list_mutex_unlock(&i->list->mutex);
606 return(v);
607}
608
609
610void *
611list_find (ListIterator i, ListFindF f, void *key)
612{
613 void *v;
614
615 assert(i != NULL);
616 assert(f != NULL);
617 assert(i->magic == LIST_MAGIC);
618 while ((v=list_next(i)) && !f(v,key)) {;}
619 return(v);
620}
621
622
623void *
624list_remove (ListIterator i)
625{
626 void *v = NULL;
627
628 assert(i != NULL);
629 assert(i->magic == LIST_MAGIC);
630 list_mutex_lock(&i->list->mutex);
631 assert(i->list->magic == LIST_MAGIC);
632 if (*i->prev != i->pos)
633 v = list_node_destroy(i->list, i->prev);
634 list_mutex_unlock(&i->list->mutex);
635 return(v);
636}
637
638
639int
640list_delete (ListIterator i)
641{
642 void *v;
643
644 assert(i != NULL);
645 assert(i->magic == LIST_MAGIC);
646 if ((v = list_remove(i))) {
647 if (i->list->fDel)
648 i->list->fDel(v);
649 return(1);
650 }
651 return(0);
652}
653
654
655static void *
656list_node_create (List l, ListNode *pp, void *x)
657{
658/* Inserts data pointed to by [x] into list [l] after [pp],
659 * the address of the previous node's "next" ptr.
660 * Returns a ptr to data [x], or NULL if insertion fails.
661 * This routine assumes the list is already locked upon entry.
662 */
663 ListNode p;
664 ListIterator i;
665
666 assert(l != NULL);
667 assert(l->magic == LIST_MAGIC);
668 assert(list_mutex_is_locked(&l->mutex));
669 assert(pp != NULL);
670 assert(x != NULL);
671 if (!(p = list_node_alloc()))
672 return(lsd_nomem_error(__FILE__, __LINE__, "list node create"));
673 p->data = x;
674 if (!(p->next = *pp))
675 l->tail = &p->next;
676 *pp = p;
677 l->count++;
678 for (i=l->iNext; i; i=i->iNext) {
679 assert(i->magic == LIST_MAGIC);
680 if (i->prev == pp)
681 i->prev = &p->next;
682 else if (i->pos == p->next)
683 i->pos = p;
684 assert((i->pos == *i->prev) || (i->pos == (*i->prev)->next));
685 }
686 return(x);
687}
688
689
690static void *
691list_node_destroy (List l, ListNode *pp)
692{
693/* Removes the node pointed to by [*pp] from from list [l],
694 * where [pp] is the address of the previous node's "next" ptr.
695 * Returns the data ptr associated with list item being removed,
696 * or NULL if [*pp] points to the NULL element.
697 * This routine assumes the list is already locked upon entry.
698 */
699 void *v;
700 ListNode p;
701 ListIterator i;
702
703 assert(l != NULL);
704 assert(l->magic == LIST_MAGIC);
705 assert(list_mutex_is_locked(&l->mutex));
706 assert(pp != NULL);
707 if (!(p = *pp))
708 return(NULL);
709 v = p->data;
710 if (!(*pp = p->next))
711 l->tail = pp;
712 l->count--;
713 for (i=l->iNext; i; i=i->iNext) {
714 assert(i->magic == LIST_MAGIC);
715 if (i->pos == p)
716 i->pos = p->next, i->prev = pp;
717 else if (i->prev == &p->next)
718 i->prev = pp;
719 assert((i->pos == *i->prev) || (i->pos == (*i->prev)->next));
720 }
721 list_node_free(p);
722 return(v);
723}
724
725
726static List
727list_alloc (void)
728{
729 return(list_alloc_aux(sizeof(struct list), &list_free_lists));
730}
731
732
733static void
734list_free (List l)
735{
736 list_free_aux(l, &list_free_lists);
737 return;
738}
739
740
741static ListNode
742list_node_alloc (void)
743{
744 return(list_alloc_aux(sizeof(struct listNode), &list_free_nodes));
745}
746
747
748static void
749list_node_free (ListNode p)
750{
751 list_free_aux(p, &list_free_nodes);
752 return;
753}
754
755
756static ListIterator
757list_iterator_alloc (void)
758{
759 return(list_alloc_aux(sizeof(struct listIterator), &list_free_iterators));
760}
761
762
763static void
764list_iterator_free (ListIterator i)
765{
766 list_free_aux(i, &list_free_iterators);
767 return;
768}
769
770
771static void *
772list_alloc_aux (int size, void *pfreelist)
773{
774/* Allocates an object of [size] bytes from the freelist [*pfreelist].
775 * Memory is added to the freelist in chunks of size LIST_ALLOC.
776 * Returns a ptr to the object, or NULL if the memory request fails.
777 */
778 void **px;
779 void **pfree = pfreelist;
780 void **plast;
781
782 assert(sizeof(char) == 1);
f4b37741 783 assert(size >= (int)sizeof(void *));
564f6d15 784 assert(pfreelist != NULL);
785 assert(LIST_ALLOC > 0);
786 list_mutex_lock(&list_free_lock);
787 if (!*pfree) {
788 if ((*pfree = malloc(LIST_ALLOC * size))) {
789 px = *pfree;
790 plast = (void **) ((char *) *pfree + ((LIST_ALLOC - 1) * size));
791 while (px < plast)
792 *px = (char *) px + size, px = *px;
793 *plast = NULL;
794 }
795 }
796 if ((px = *pfree))
797 *pfree = *px;
798 else
799 errno = ENOMEM;
800 list_mutex_unlock(&list_free_lock);
801 return(px);
802}
803
804
805static void
806list_free_aux (void *x, void *pfreelist)
807{
808/* Frees the object [x], returning it to the freelist [*pfreelist].
809 */
810 void **px = x;
811 void **pfree = pfreelist;
812
813 assert(x != NULL);
814 assert(pfreelist != NULL);
815 list_mutex_lock(&list_free_lock);
816 *px = *pfree;
817 *pfree = px;
818 list_mutex_unlock(&list_free_lock);
819 return;
820}
821
822
823#ifndef NDEBUG
824#ifdef WITH_PTHREADS
825static int
826list_mutex_is_locked (pthread_mutex_t *mutex)
827{
828/* Returns true if the mutex is locked; o/w, returns false.
829 */
830 int rc;
831
832 assert(mutex != NULL);
833 rc = pthread_mutex_trylock(mutex);
834 return(rc == EBUSY ? 1 : 0);
835}
836#endif /* WITH_PTHREADS */
837#endif /* !NDEBUG */