LIST_CREATE(9F) Kernel Functions for Drivers LIST_CREATE(9F)

list_create, list_destroy, list_insert_after, list_insert_before, list_insert_head, list_insert_tail, list_remove, list_remove_head, list_remove_tail, list_head, list_tail, list_next, list_prev, list_is_empty,, list_link_init, list_link_active, list_move_tail, list_link_replacelist functions

#include <sys/list.h>

void
list_create(list_t *list, size_t size, size_t offset);

void
list_destroy(list_t *list);

void
list_insert_after(list_t *list, void *reference_item, void *new_item);

void
list_insert_before(list_t *list, void *reference_item, void *new_item);

void
list_insert_head(list_t *list*, void *new_item);

void
list_insert_tail(list_t *list, void *new_item);

void
list_remove(list_t *list, void *item);

void *
list_remove_head(list_t *list);

void *
list_remove_tail(list_t *list);

void *
list_head(list_t *list);

void *
list_tail(list_t *list);

void *
list_next(list_t *list, void *reference_item);

void *
list_prev(list_t *list, void *reference_item);

int
list_is_empty(list_t *list);

void
list_link_init(list_node_t *node);

int
list_link_active(list_node_t *node);

void
list_move_tail(list_t *dst, list_t *src);

void
list_link_replace(list_node_t *lold, list_node_t *lnew);

These functions provide a generic doubly-linked list implementation. To utilize it, simply embed a list_node_t field in the structures that will constitute the linked list elements and pass the list_node_t field offset to () in the appropriate parameter (see below). A single list_node_t field can only be used in a single list simultaneously, so to add a structure to multiple lists, embed multiple list_node_t fields in your user structure.

Please note that a list_node_t contains pointers back to its parent list_t so you cannot copy the list_t around once it has been initialized. In particular, this kind of construct will not work:

struct { list_t l; } a, b;
list_create(&a.l, ...);
b = a;    <= This will break the list in `b', as the `l' element
             in `a' got copied to a different memory address.

To do this you must move the list items to the new list using functions such as ().

The () function initializes a new list. The driver supplies the storage for the list handle, the size of an individual element, and the offset of a list_node_t within the element to use for the links of the list.

The () function destroys the list handle, including freeing any resources that may have been internally allocated for the list. The list must be empty when this function is called.

The () and () functions insert new_item into the linked list at a location after or before the reference item, which must already be on the list.

The () and () functions insert the new_item on the list at either the head or tail of the list. The head is the first item, the tail is the last item.

The () function removes the item from the list.

The () and () functions remove the head (first) or tail (last) item from the list. The item removed is returned to the caller. If the list is empty when these functions are called, then no change is made and NULL is returned to the caller.

The () and () functions simply return the head (first) or tail (last) item on the list. NULL is returned if the list is empty.

The () and () functions return the next or previous item in the list, relative to the named reference item which must be linked on the list. If the referenced item is either the last entry in the list for list_next() or the first entry in the list for list_prev(), then the functions will return NULL. This is useful for iterating over a list with the following pattern:

list_t list;
...
for (foo_t *foo = list_head(&list); foo != NULL;
    foo = list_next(&list, foo)) {
	/* Process each entry of the list */
}

for (foo_t *foo = list_tail(&list); foo != NULL;
    foo = list_prev(&list, foo)) {
	/* Same thing, but in reverse */
}

The () function returns 0 if the list has items in it, or non-zero otherwise.

The () function is used to append the items on the src list to the end of the dst list. It is mandatory that the two lists were initialized using identical size and offset parameters. Upon completion, the src list will be empty.

All functions may be called from , , or context.

Example 1 Removing a single item from a list safely

Calling list_remove() mutates a list and means that using a traditional for loop like in the discussion of list_next() above may not be safe. Instead, use the following pattern:

list_t list;
item_t *item, *next;

...

for (item = list_head(&list), next = NULL; item != NULL;
    item = next) {
        next = list_next(&list, item);

        if (condition) {
                list_remove(&list, item);
                free_item(item);
        }
}

Example 2 Removing and freeing all items from a list

Before destroying a list_t, one must ensure that it is empty. This example shows how to remove all items from a list and clean them up.

list_t list;
item_t *item;

...

while ((item = list_remove_head(&list)) != NULL) {
	free_item(item);
}

list_destroy(&list);

April 19, 2026 OmniOS