1 /*****************************************************************************
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2001-2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Chris Dunlap <cdunlap@llnl.gov>.
8 * This file is from LSD-Tools, the LLNL Software Development Toolbox.
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.
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
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * You should have received a copy of the GNU General Public License along
21 * with LSD-Tools. If not, see <http://www.gnu.org/licenses/>.
22 *****************************************************************************
23 * Refer to "list.h" for documentation on public functions.
24 *****************************************************************************/
28 #endif /* WITH_PTHREADS */
37 /*********************
39 *********************/
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
49 # define lsd_fatal_error(file, line, mesg) \
51 fprintf(stderr, "ERROR: [%s:%d] %s: %s\n", \
52 file, line, mesg, strerror(errno)); \
54 # endif /* !lsd_fatal_error */
55 #endif /* !WITH_LSD_FATAL_ERROR_FUNC */
58 /*********************
60 *********************/
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 */
77 #define LIST_MAGIC 0xDEADBEEF
85 void *data
; /* node's data */
86 struct listNode
*next
; /* next node in list */
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() */
95 unsigned int magic
; /* sentinel for asserting validity */
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 */
106 pthread_mutex_t mutex
; /* mutex to protect access to list */
107 #endif /* WITH_PTHREADS */
109 unsigned int magic
; /* sentinel for asserting validity */
113 typedef struct listNode
* ListNode
;
120 static void * list_node_create (List l
, ListNode
*pp
, void *x
);
121 static void * list_node_destroy (List l
, ListNode
*pp
);
122 static List
list_alloc (void);
123 static void list_free (List l
);
124 static ListNode
list_node_alloc (void);
125 static void list_node_free (ListNode p
);
126 static ListIterator
list_iterator_alloc (void);
127 static void list_iterator_free (ListIterator i
);
128 static void * list_alloc_aux (int size
, void *pfreelist
);
129 static void list_free_aux (void *x
, void *pfreelist
);
136 static List list_free_lists
= NULL
;
137 static ListNode list_free_nodes
= NULL
;
138 static ListIterator list_free_iterators
= NULL
;
141 static pthread_mutex_t list_free_lock
= PTHREAD_MUTEX_INITIALIZER
;
142 #endif /* WITH_PTHREADS */
151 # define list_mutex_init(mutex) \
153 int e = pthread_mutex_init(mutex, NULL); \
156 lsd_fatal_error(__FILE__, __LINE__, "list mutex init"); \
161 # define list_mutex_lock(mutex) \
163 int e = pthread_mutex_lock(mutex); \
166 lsd_fatal_error(__FILE__, __LINE__, "list mutex lock"); \
171 # define list_mutex_unlock(mutex) \
173 int e = pthread_mutex_unlock(mutex); \
176 lsd_fatal_error(__FILE__, __LINE__, "list mutex unlock"); \
181 # define list_mutex_destroy(mutex) \
183 int e = pthread_mutex_destroy(mutex); \
186 lsd_fatal_error(__FILE__, __LINE__, "list mutex destroy"); \
192 static int list_mutex_is_locked (pthread_mutex_t
*mutex
);
193 # endif /* !NDEBUG */
195 #else /* !WITH_PTHREADS */
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)
203 #endif /* !WITH_PTHREADS */
211 list_create (ListDelF f
)
215 if (!(l
= list_alloc()))
216 return(lsd_nomem_error(__FILE__
, __LINE__
, "list create"));
222 list_mutex_init(&l
->mutex
);
224 l
->magic
= LIST_MAGIC
;
231 list_destroy (List l
)
233 ListIterator i
, iTmp
;
237 list_mutex_lock(&l
->mutex
);
238 assert(l
->magic
== LIST_MAGIC
);
241 assert(i
->magic
== LIST_MAGIC
);
244 i
->magic
= ~LIST_MAGIC
;
246 list_iterator_free(i
);
252 if (p
->data
&& l
->fDel
)
258 l
->magic
= ~LIST_MAGIC
;
260 list_mutex_unlock(&l
->mutex
);
261 list_mutex_destroy(&l
->mutex
);
268 list_is_empty (List l
)
273 list_mutex_lock(&l
->mutex
);
274 assert(l
->magic
== LIST_MAGIC
);
276 list_mutex_unlock(&l
->mutex
);
287 list_mutex_lock(&l
->mutex
);
288 assert(l
->magic
== LIST_MAGIC
);
290 list_mutex_unlock(&l
->mutex
);
296 list_append (List l
, void *x
)
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
);
311 list_prepend (List l
, void *x
)
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
);
326 list_find_first (List l
, ListFindF f
, void *key
)
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
)) {
341 list_mutex_unlock(&l
->mutex
);
347 list_delete_all (List l
, ListFindF f
, void *key
)
355 list_mutex_lock(&l
->mutex
);
356 assert(l
->magic
== LIST_MAGIC
);
359 if (f((*pp
)->data
, key
)) {
360 if ((v
= list_node_destroy(l
, pp
))) {
370 list_mutex_unlock(&l
->mutex
);
376 list_for_each (List l
, ListForF f
, void *arg
)
383 list_mutex_lock(&l
->mutex
);
384 assert(l
->magic
== LIST_MAGIC
);
385 for (p
=l
->head
; p
; p
=p
->next
) {
387 if (f(p
->data
, arg
) < 0) {
392 list_mutex_unlock(&l
->mutex
);
398 list_sort (List l
, ListCmpF f
)
400 /* Note: Time complexity O(n^2).
402 ListNode
*pp
, *ppPrev
, *ppPos
, pTmp
;
407 list_mutex_lock(&l
->mutex
);
408 assert(l
->magic
== LIST_MAGIC
);
411 pp
= &(*ppPrev
)->next
;
413 if (f((*pp
)->data
, (*ppPrev
)->data
) < 0) {
415 while (f((*pp
)->data
, (*ppPos
)->data
) >= 0)
416 ppPos
= &(*ppPos
)->next
;
418 (*pp
)->next
= *ppPos
;
422 ppPrev
= &(*ppPrev
)->next
;
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
;
437 list_mutex_unlock(&l
->mutex
);
443 list_push (List l
, void *x
)
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
);
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
);
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
);
486 list_enqueue (List l
, void *x
)
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
);
501 list_dequeue (List l
)
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
);
515 list_iterator_create (List l
)
520 if (!(i
= list_iterator_alloc()))
521 return(lsd_nomem_error(__FILE__
, __LINE__
, "list iterator create"));
523 list_mutex_lock(&l
->mutex
);
524 assert(l
->magic
== LIST_MAGIC
);
530 i
->magic
= LIST_MAGIC
;
532 list_mutex_unlock(&l
->mutex
);
538 list_iterator_reset (ListIterator i
)
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
);
552 list_iterator_destroy (ListIterator i
)
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
);
567 list_mutex_unlock(&i
->list
->mutex
);
569 i
->magic
= ~LIST_MAGIC
;
571 list_iterator_free(i
);
577 list_next (ListIterator i
)
582 assert(i
->magic
== LIST_MAGIC
);
583 list_mutex_lock(&i
->list
->mutex
);
584 assert(i
->list
->magic
== LIST_MAGIC
);
588 i
->prev
= &(*i
->prev
)->next
;
589 list_mutex_unlock(&i
->list
->mutex
);
590 return(p
? p
->data
: NULL
);
595 list_insert (ListIterator i
, void *x
)
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
);
611 list_find (ListIterator i
, ListFindF f
, void *key
)
617 assert(i
->magic
== LIST_MAGIC
);
618 while ((v
=list_next(i
)) && !f(v
,key
)) {;}
624 list_remove (ListIterator i
)
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
);
640 list_delete (ListIterator i
)
645 assert(i
->magic
== LIST_MAGIC
);
646 if ((v
= list_remove(i
))) {
656 list_node_create (List l
, ListNode
*pp
, void *x
)
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.
667 assert(l
->magic
== LIST_MAGIC
);
668 assert(list_mutex_is_locked(&l
->mutex
));
671 if (!(p
= list_node_alloc()))
672 return(lsd_nomem_error(__FILE__
, __LINE__
, "list node create"));
674 if (!(p
->next
= *pp
))
678 for (i
=l
->iNext
; i
; i
=i
->iNext
) {
679 assert(i
->magic
== LIST_MAGIC
);
682 else if (i
->pos
== p
->next
)
684 assert((i
->pos
== *i
->prev
) || (i
->pos
== (*i
->prev
)->next
));
691 list_node_destroy (List l
, ListNode
*pp
)
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.
704 assert(l
->magic
== LIST_MAGIC
);
705 assert(list_mutex_is_locked(&l
->mutex
));
710 if (!(*pp
= p
->next
))
713 for (i
=l
->iNext
; i
; i
=i
->iNext
) {
714 assert(i
->magic
== LIST_MAGIC
);
716 i
->pos
= p
->next
, i
->prev
= pp
;
717 else if (i
->prev
== &p
->next
)
719 assert((i
->pos
== *i
->prev
) || (i
->pos
== (*i
->prev
)->next
));
729 return(list_alloc_aux(sizeof(struct list
), &list_free_lists
));
736 list_free_aux(l
, &list_free_lists
);
742 list_node_alloc (void)
744 return(list_alloc_aux(sizeof(struct listNode
), &list_free_nodes
));
749 list_node_free (ListNode p
)
751 list_free_aux(p
, &list_free_nodes
);
757 list_iterator_alloc (void)
759 return(list_alloc_aux(sizeof(struct listIterator
), &list_free_iterators
));
764 list_iterator_free (ListIterator i
)
766 list_free_aux(i
, &list_free_iterators
);
772 list_alloc_aux (int size
, void *pfreelist
)
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.
779 void **pfree
= pfreelist
;
782 assert(sizeof(char) == 1);
783 assert(size
>= (int)sizeof(void *));
784 assert(pfreelist
!= NULL
);
785 assert(LIST_ALLOC
> 0);
786 list_mutex_lock(&list_free_lock
);
788 if ((*pfree
= malloc(LIST_ALLOC
* size
))) {
790 plast
= (void **) ((char *) *pfree
+ ((LIST_ALLOC
- 1) * size
));
792 *px
= (char *) px
+ size
, px
= *px
;
800 list_mutex_unlock(&list_free_lock
);
806 list_free_aux (void *x
, void *pfreelist
)
808 /* Frees the object [x], returning it to the freelist [*pfreelist].
811 void **pfree
= pfreelist
;
814 assert(pfreelist
!= NULL
);
815 list_mutex_lock(&list_free_lock
);
818 list_mutex_unlock(&list_free_lock
);
826 list_mutex_is_locked (pthread_mutex_t
*mutex
)
828 /* Returns true if the mutex is locked; o/w, returns false.
832 assert(mutex
!= NULL
);
833 rc
= pthread_mutex_trylock(mutex
);
834 return(rc
== EBUSY
? 1 : 0);
836 #endif /* WITH_PTHREADS */