SMR_LIST_INIT(9) | Kernel Developer's Manual | SMR_LIST_INIT(9)

# NAME

`SMR_SLIST_ENTRY`, `SMR_SLIST_HEAD`, `SMR_SLIST_HEAD_INITIALIZER`, `SMR_SLIST_INIT`, `SMR_SLIST_FIRST`, `SMR_SLIST_NEXT`, `SMR_SLIST_FOREACH`, `SMR_SLIST_FIRST_LOCKED`, `SMR_SLIST_NEXT_LOCKED`, `SMR_SLIST_EMPTY_LOCKED`, `SMR_SLIST_FOREACH_LOCKED`, `SMR_SLIST_FOREACH_SAFE_LOCKED`, `SMR_SLIST_INSERT_HEAD_LOCKED`, `SMR_SLIST_INSERT_AFTER_LOCKED`, `SMR_SLIST_REMOVE_HEAD_LOCKED`, `SMR_SLIST_REMOVE_AFTER_LOCKED`, `SMR_SLIST_REMOVE_LOCKED`, `SMR_LIST_ENTRY`, `SMR_LIST_HEAD`, `SMR_LIST_HEAD_INITIALIZER`, `SMR_LIST_INIT`, `SMR_LIST_FIRST`, `SMR_LIST_NEXT`, `SMR_LIST_FOREACH`, `SMR_LIST_FIRST_LOCKED`, `SMR_LIST_NEXT_LOCKED`, `SMR_LIST_EMPTY_LOCKED`, `SMR_LIST_FOREACH_LOCKED`, `SMR_LIST_FOREACH_SAFE_LOCKED`, `SMR_LIST_INSERT_HEAD_LOCKED`, `SMR_LIST_INSERT_AFTER_LOCKED`, `SMR_LIST_INSERT_BEFORE_LOCKED`, `SMR_LIST_REMOVE_LOCKED`, `SMR_TAILQ_ENTRY`, `SMR_TAILQ_HEAD`, `SMR_TAILQ_HEAD_INITIALIZER`, `SMR_TAILQ_INIT`, `SMR_TAILQ_FIRST`, `SMR_TAILQ_NEXT`, `SMR_TAILQ_FOREACH`, `SMR_TAILQ_FIRST_LOCKED`, `SMR_TAILQ_NEXT_LOCKED`, `SMR_TAILQ_LAST_LOCKED`, `SMR_TAILQ_EMPTY_LOCKED`, `SMR_TAILQ_FOREACH_LOCKED`, `SMR_TAILQ_FOREACH_SAFE_LOCKED`, `SMR_TAILQ_INSERT_HEAD_LOCKED`, `SMR_TAILQ_INSERT_TAIL_LOCKED`, `SMR_TAILQ_INSERT_AFTER_LOCKED`, `SMR_TAILQ_INSERT_BEFORE_LOCKED`, `SMR_TAILQ_REMOVE_LOCKED` — SMR list macros

# SYNOPSIS

`#include <sys/smr.h>`

`SMR_SLIST_ENTRY`(TYPE);

void
`SMR_SLIST_INIT`(SMR_SLIST_HEAD *head);

TYPE *
`SMR_SLIST_FIRST`(SMR_SLIST_HEAD *head);

TYPE *
`SMR_SLIST_NEXT`(TYPE *elm, FIELDNAME);

`SMR_SLIST_FOREACH`(VARNAME, SMR_SLIST_HEAD *head, FIELDNAME);

TYPE *
`SMR_SLIST_FIRST_LOCKED`(SMR_SLIST_HEAD *head);

TYPE *
`SMR_SLIST_NEXT_LOCKED`(TYPE *elm, FIELDNAME);

int
`SMR_SLIST_EMPTY_LOCKED`(SMR_SLIST_HEAD *head);

`SMR_SLIST_FOREACH_LOCKED`(VARNAME, SMR_SLIST_HEAD *head, FIELDNAME);

`SMR_SLIST_FOREACH_SAFE_LOCKED`(VARNAME, SMR_LIST_HEAD *head, FIELDNAME, TEMP_VARNAME);

void
`SMR_SLIST_INSERT_HEAD_LOCKED`(SMR_SLIST_HEAD *head, struct TYPE *elm, FIELDNAME);

void
`SMR_SLIST_INSERT_AFTER_LOCKED`(struct TYPE *listelm, struct TYPE *elm, FIELDNAME);

void
`SMR_SLIST_REMOVE_HEAD_LOCKED`(SMR_SLIST_HEAD *head, FIELDNAME);

void
`SMR_SLIST_REMOVE_AFTER_LOCKED`(struct TYPE *elm, FIELDNAME);

void
`SMR_SLIST_REMOVE_LOCKED`(SMR_SLIST_HEAD *head, struct TYPE *elm, TYPE, FIELDNAME);

`SMR_LIST_ENTRY`(TYPE);

void
`SMR_LIST_INIT`(SMR_LIST_HEAD *head);

TYPE *
`SMR_LIST_FIRST`(SMR_LIST_HEAD *head);

TYPE *
`SMR_LIST_NEXT`(TYPE *elm, FIELDNAME);

TYPE *
`SMR_LIST_FIRST_LOCKED`(SMR_LIST_HEAD *head);

TYPE *
`SMR_LIST_NEXT_LOCKED`(TYPE *elm, FIELDNAME);

int
`SMR_LIST_EMPTY_LOCKED`(SMR_LIST_HEAD *head);

`SMR_LIST_FOREACH`(VARNAME, SMR_LIST_HEAD *head, FIELDNAME);

`SMR_LIST_FOREACH_LOCKED`(VARNAME, SMR_LIST_HEAD *head, FIELDNAME);

`SMR_LIST_FOREACH_SAFE_LOCKED`(VARNAME, SMR_LIST_HEAD *head, FIELDNAME, TEMP_VARNAME);

void
`SMR_LIST_INSERT_HEAD_LOCKED`(SMR_LIST_HEAD *head, struct TYPE *elm, FIELDNAME);

void
`SMR_LIST_INSERT_AFTER_LOCKED`(struct TYPE *listelm, struct TYPE *elm, FIELDNAME);

void
`SMR_LIST_INSERT_BEFORE_LOCKED`(struct TYPE *listelm, struct TYPE *elm, FIELDNAME);

void
`SMR_LIST_REMOVE_LOCKED`(struct TYPE *elm, FIELDNAME);

`SMR_TAILQ_ENTRY`(TYPE);

void
`SMR_TAILQ_INIT`(SMR_TAILQ_HEAD *head);

TYPE *
`SMR_TAILQ_FIRST`(SMR_TAILQ_HEAD *head);

TYPE *
`SMR_TAILQ_NEXT`(TYPE *elm, FIELDNAME);

TYPE *
`SMR_TAILQ_FIRST_LOCKED`(SMR_TAILQ_HEAD *head);

TYPE *
`SMR_TAILQ_NEXT_LOCKED`(TYPE *elm, FIELDNAME);

TYPE *
`SMR_TAILQ_LAST_LOCKED`(SMR_TAILQ_HEAD *head);

`SMR_TAILQ_FOREACH`(VARNAME, SMR_TAILQ_HEAD *head, FIELDNAME);

`SMR_TAILQ_FOREACH_LOCKED`(VARNAME, SMR_TAILQ_HEAD *head, FIELDNAME);

`SMR_TAILQ_FOREACH_SAFE_LOCKED`(VARNAME, SMR_TAILQ_HEAD *head, FIELDNAME, TEMP_VARNAME);

void
`SMR_TAILQ_INSERT_HEAD_LOCKED`(SMR_TAILQ_HEAD *head, struct TYPE *elm, FIELDNAME);

void
`SMR_TAILQ_INSERT_TAIL_LOCKED`(SMR_TAILQ_HEAD *head, struct TYPE *elm, FIELDNAME);

void
`SMR_TAILQ_INSERT_AFTER_LOCKED`(struct TYPE *listelm, struct TYPE *elm, FIELDNAME);

void
`SMR_TAILQ_INSERT_BEFORE_LOCKED`(struct TYPE *listelm, struct TYPE *elm, FIELDNAME);

void
`SMR_TAILQ_REMOVE_LOCKED`(struct TYPE *elm, FIELDNAME);

# DESCRIPTION

The SMR list macros define and operate on singly-linked lists, lists and tail queues that can be used with the safe memory reclamation mechanism. A data structure built with these macros can be accessed concurrently by multiple readers and a single writer.

Readers have to access the data structure inside SMR read-side critical section. The critical section is entered using smr_read_enter(9), and left using smr_read_leave(9).

Writers must ensure exclusive write access. That can be done using a lock, such as mutex(9) or rwlock(9). The mutual exclusion of writers does not need to apply to readers.

When an element has been removed from the data structure, the element must not be deleted or re-inserted before all reader references to it have disappeared. The writer has to use either smr_barrier(9) or smr_call(9) to ensure that the element can no longer be accessed by readers.

## Singly-Linked Lists

The `SMR_SLIST_ENTRY`() macro declares a structure that connects the elements in the list.

`SMR_SLIST_INIT`() initializes the list head to an empty state.

`SMR_SLIST_FIRST`() and `SMR_SLIST_FIRST_LOCKED`() return the first element on the list head, or NULL if the list is empty.

`SMR_SLIST_NEXT`() and `SMR_SLIST_NEXT_LOCKED`() return the successor of the element elm, or NULL if there are no more elements on the list.

`SMR_SLIST_EMPTY_LOCKED`() returns true if the list head is empty.

`SMR_SLIST_FOREACH`() and `SMR_SLIST_FOREACH_LOCKED`() traverse the list head in forward direction.

`SMR_SLIST_FOREACH_SAFE_LOCKED`() traverses the list head in forward direction. It is permitted to remove the element referenced by variable VARNAME from the list and defer its freeing using smr_call(9).

`SMR_SLIST_INSERT_HEAD_LOCKED`() inserts the new element elm at the head of the list.

`SMR_SLIST_INSERT_AFTER_LOCKED`() inserts the new element elm after the element listelm.

`SMR_SLIST_REMOVE_HEAD_LOCKED`() removes the first element of the list head.

`SMR_SLIST_REMOVE_AFTER_LOCKED`() removes the list element immediately following elm.

`SMR_SLIST_REMOVE_LOCKED`() removes the list element elm from the list head.

## Linked Lists

The `SMR_LIST_ENTRY`() macro declares a structure that connects the elements in the list.

`SMR_LIST_INIT`() initializes the list head to an empty state.

`SMR_LIST_FIRST`() and `SMR_LIST_FIRST_LOCKED`() return the first element on the list head, or NULL if the list is empty.

`SMR_LIST_NEXT`() and `SMR_LIST_NEXT_LOCKED`() return the successor of the element elm, or NULL if there are no more elements on the list.

`SMR_LIST_EMPTY_LOCKED`() returns true if the list head is empty.

`SMR_LIST_FOREACH`() and `SMR_LIST_FOREACH_LOCKED`() traverse the list head in forward direction.

`SMR_LIST_FOREACH_SAFE_LOCKED`() traverses the list head in forward direction. It is permitted to remove the element referenced by variable VARNAME from the list and defer its freeing using smr_call(9).

`SMR_LIST_INSERT_HEAD_LOCKED`() inserts the new element elm at the head of the list.

`SMR_LIST_INSERT_AFTER_LOCKED`() inserts the new element elm after the element listelm.

`SMR_LIST_INSERT_BEFORE_LOCKED`() inserts the new element elm before the element listelm.

`SMR_LIST_REMOVE_LOCKED`() removes the element elm from the list head.

## Tail Queues

The `SMR_TAILQ_ENTRY`() macro declares a structure that connects the elements in the tail queue.

`SMR_TAILQ_INIT`() initializes the tail queue head to an empty state.

`SMR_TAILQ_FIRST`() and `SMR_TAILQ_FIRST_LOCKED`() return the first element in the queue head, or NULL if the queue is empty.

`SMR_TAILQ_NEXT`() and `SMR_TAILQ_NEXT_LOCKED`() return the successor of the element elm, or NULL if there are no more elements in the queue.

`SMR_TAILQ_EMPTY_LOCKED`() returns true if the queue head is empty.

`SMR_TAILQ_FOREACH`() and `SMR_TAILQ_FOREACH_LOCKED`() traverse the queue head in forward direction.

`SMR_TAILQ_FOREACH_SAFE_LOCKED`() traverses the queue head in forward direction. It is permitted to remove the element referenced by variable VARNAME from the queue and defer its freeing using smr_call(9).

`SMR_TAILQ_INSERT_HEAD_LOCKED`() inserts the new element elm at the head of the queue.

`SMR_TAILQ_INSERT_TAIL_LOCKED`() inserts the new element elm at the tail of the queue.

`SMR_TAILQ_INSERT_AFTER_LOCKED`() inserts the new element elm after the element listelm.

`SMR_TAILQ_INSERT_BEFORE_LOCKED`() inserts the new element elm before the element listelm.

`SMR_TAILQ_REMOVE_LOCKED`() removes the element elm from the queue head.

# CONTEXT

All SMR list macros can be used during autoconf, from process context, or from interrupt context.

`SMR_SLIST_FIRST`, `SMR_SLIST_NEXT`, `SMR_SLIST_FOREACH`, `SMR_LIST_FIRST`, `SMR_LIST_NEXT`, `SMR_LIST_FOREACH`, `SMR_TAILQ_FIRST`, `SMR_TAILQ_NEXT` and `SMR_TAILQ_FOREACH` can be used from SMR read-side critical section.

`SMR_SLIST_INIT`, `SMR_SLIST_FIRST_LOCKED`, `SMR_SLIST_NEXT_LOCKED`, `SMR_SLIST_EMPTY_LOCKED`, `SMR_SLIST_FOREACH_LOCKED`, `SMR_SLIST_FOREACH_SAFE_LOCKED`, `SMR_SLIST_INSERT_HEAD_LOCKED`, `SMR_SLIST_INSERT_AFTER_LOCKED`, `SMR_SLIST_REMOVE_HEAD_LOCKED`, `SMR_SLIST_REMOVE_AFTER_LOCKED`, `SMR_SLIST_REMOVE_LOCKED`, `SMR_LIST_INIT`, `SMR_LIST_FIRST_LOCKED`, `SMR_LIST_NEXT_LOCKED`, `SMR_LIST_EMPTY_LOCKED`, `SMR_LIST_FOREACH_LOCKED`, `SMR_LIST_FOREACH_SAFE_LOCKED`, `SMR_LIST_INSERT_HEAD_LOCKED`, `SMR_LIST_INSERT_AFTER_LOCKED`, `SMR_LIST_INSERT_BEFORE_LOCKED`, `SMR_LIST_REMOVE_LOCKED`, `SMR_TAILQ_INIT`, `SMR_TAILQ_FIRST_LOCKED`, `SMR_TAILQ_NEXT_LOCKED`, `SMR_TAILQ_EMPTY_LOCKED`, `SMR_TAILQ_FOREACH_LOCKED`, `SMR_TAILQ_FOREACH_SAFE_LOCKED`, `SMR_TAILQ_INSERT_HEAD_LOCKED`, `SMR_TAILQ_INSERT_TAIL_LOCKED`, `SMR_TAILQ_INSERT_AFTER_LOCKED`, `SMR_TAILQ_INSERT_BEFORE_LOCKED`, and `SMR_TAILQ_REMOVE_LOCKED` can be used from writer context.

# SEE ALSO

queue(3), smr_call(9), SMR_PTR_GET(9)

# HISTORY

The SMR list macros first appeared in OpenBSD 6.5.

January 16, 2022 | Debian