/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef LLIST_H
#define LLIST_H
/*
* Lock - less NULL terminated single linked list
*
* Cases where locking is not needed :
* If there are multiple producers and multiple consumers , llist_add can be
* used in producers and llist_del_all can be used in consumers simultaneously
* without locking . Also a single consumer can use llist_del_first while
* multiple producers simultaneously use llist_add , without any locking .
*
* Cases where locking is needed :
* If we have multiple consumers with llist_del_first used in one consumer , and
* llist_del_first or llist_del_all used in other consumers , then a lock is
* needed . This is because llist_del_first depends on list - > first - > next not
* changing , but without lock protection , there ' s no way to be sure about that
* if a preemption happens in the middle of the delete operation and on being
* preempted back , the list - > first is the same as before causing the cmpxchg in
* llist_del_first to succeed . For example , while a llist_del_first operation
* is in progress in one consumer , then a llist_del_first , llist_add ,
* llist_add ( or llist_del_all , llist_add , llist_add ) sequence in another
* consumer may cause violations .
*
* This can be summarized as follows :
*
* | add | del_first | del_all
* add | - | - | -
* del_first | | L | L
* del_all | | | -
*
* Where , a particular row ' s operation can happen concurrently with a column ' s
* operation , with " - " being no lock needed , while " L " being lock is needed .
*
* The list entries deleted via llist_del_all can be traversed with
* traversing function such as llist_for_each etc . But the list
* entries can not be traversed safely before deleted from the list .
* The order of deleted entries is from the newest to the oldest added
* one . If you want to traverse from the oldest to the newest , you
* must reverse the order by yourself before traversing .
*
* The basic atomic operation of this list is cmpxchg on long . On
* architectures that don ' t have NMI - safe cmpxchg implementation , the
* list can NOT be used in NMI handlers . So code that uses the list in
* an NMI handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG .
*
* Copyright 2010 , 2011 Intel Corp .
* Author : Huang Ying < ying . huang @ intel . com >
*/
#include <linux/atomic.h>
#include <linux/container_of.h>
#include <linux/stddef.h>
#include <linux/types.h>
struct llist_head {
struct llist_node *first;
};
struct llist_node {
struct llist_node *next;
};
#define LLIST_HEAD_INIT(name) { NULL }
#define LLIST_HEAD(name) struct llist_head name = LLIST_HEAD_INIT(name)
/**
* init_llist_head - initialize lock - less list head
* @ head : the head for your lock - less list
*/
static inline void init_llist_head(struct llist_head *list)
{
list->first = NULL;
}
/**
* init_llist_node - initialize lock - less list node
* @ node : the node to be initialised
*
* In cases where there is a need to test if a node is on
* a list or not , this initialises the node to clearly
* not be on any list .
*/
static inline void init_llist_node(struct llist_node *node)
{
WRITE_ONCE(node->next, node);
}
/**
* llist_on_list - test if a lock - list list node is on a list
* @ node : the node to test
*
* When a node is on a list the - > next pointer will be NULL or
* some other node . It can never point to itself . We use that
* in init_llist_node ( ) to record that a node is not on any list ,
* and here to test whether it is on any list .
*/
static inline bool llist_on_list(const struct llist_node *node)
{
return READ_ONCE(node->next) != node;
}
/**
* llist_entry - get the struct of this entry
* @ ptr : the & struct llist_node pointer .
* @ type : the type of the struct this is embedded in .
* @ member : the name of the llist_node within the struct .
*/
#define llist_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* member_address_is_nonnull - check whether the member address is not NULL
* @ ptr : the object pointer ( struct type * that contains the llist_node )
* @ member : the name of the llist_node within the struct .
*
* This macro is conceptually the same as
* & ptr - > member ! = NULL
* but it works around the fact that compilers can decide that taking a member
* address is never a NULL pointer .
*
* Real objects that start at a high address and have a member at NULL are
* unlikely to exist , but such pointers may be returned e . g . by the
* container_of ( ) macro .
*/
#define member_address_is_nonnull(ptr, member) \
((uintptr_t)(ptr) + offsetof(typeof(*(ptr)), member) != 0 )
/**
* llist_for_each - iterate over some deleted entries of a lock - less list
* @ pos : the & struct llist_node to use as a loop cursor
* @ node : the first entry of deleted list entries
*
* In general , some entries of the lock - less list can be traversed
* safely only after being deleted from list , so start with an entry
* instead of list head .
*
* If being used on entries deleted from lock - less list directly , the
* traverse order is from the newest to the oldest added entry . If
* you want to traverse from the oldest to the newest , you must
* reverse the order by yourself before traversing .
*/
#define llist_for_each(pos, node) \
for ((pos) = (node); pos; (pos) = (pos)->next)
/**
* llist_for_each_safe - iterate over some deleted entries of a lock - less list
* safe against removal of list entry
* @ pos : the & struct llist_node to use as a loop cursor
* @ n : another & struct llist_node to use as temporary storage
* @ node : the first entry of deleted list entries
*
* In general , some entries of the lock - less list can be traversed
* safely only after being deleted from list , so start with an entry
* instead of list head .
*
* If being used on entries deleted from lock - less list directly , the
* traverse order is from the newest to the oldest added entry . If
* you want to traverse from the oldest to the newest , you must
* reverse the order by yourself before traversing .
*/
#define llist_for_each_safe(pos, n, node) \
for ((pos) = (node); (pos) && ((n) = (pos)->next, true ); (pos) = (n))
/**
* llist_for_each_entry - iterate over some deleted entries of lock - less list of given type
* @ pos : the type * to use as a loop cursor .
* @ node : the fist entry of deleted list entries .
* @ member : the name of the llist_node with the struct .
*
* In general , some entries of the lock - less list can be traversed
* safely only after being removed from list , so start with an entry
* instead of list head .
*
* If being used on entries deleted from lock - less list directly , the
* traverse order is from the newest to the oldest added entry . If
* you want to traverse from the oldest to the newest , you must
* reverse the order by yourself before traversing .
*/
#define llist_for_each_entry(pos, node, member) \
for ((pos) = llist_entry((node), typeof(*(pos)), member); \
member_address_is_nonnull(pos, member); \
(pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
/**
* llist_for_each_entry_safe - iterate over some deleted entries of lock - less list of given type
* safe against removal of list entry
* @ pos : the type * to use as a loop cursor .
* @ n : another type * to use as temporary storage
* @ node : the first entry of deleted list entries .
* @ member : the name of the llist_node with the struct .
*
* In general , some entries of the lock - less list can be traversed
* safely only after being removed from list , so start with an entry
* instead of list head .
*
* If being used on entries deleted from lock - less list directly , the
* traverse order is from the newest to the oldest added entry . If
* you want to traverse from the oldest to the newest , you must
* reverse the order by yourself before traversing .
*/
#define llist_for_each_entry_safe(pos, n, node, member) \
for (pos = llist_entry((node), typeof(*pos), member); \
member_address_is_nonnull(pos, member) && \
(n = llist_entry(pos->member.next, typeof(*n), member), true ); \
pos = n)
/**
* llist_empty - tests whether a lock - less list is empty
* @ head : the list to test
*
* Not guaranteed to be accurate or up to date . Just a quick way to
* test whether the list is empty without deleting something from the
* list .
*/
static inline bool llist_empty(const struct llist_head *head)
{
return READ_ONCE(head->first) == NULL;
}
static inline struct llist_node *llist_next(struct llist_node *node)
{
return READ_ONCE(node->next);
}
/**
* llist_add_batch - add several linked entries in batch
* @ new_first : first entry in batch to be added
* @ new_last : last entry in batch to be added
* @ head : the head for your lock - less list
*
* Return whether list is empty before adding .
*/
static inline bool llist_add_batch(struct llist_node *new_first,
struct llist_node *new_last,
struct llist_head *head)
{
struct llist_node *first = READ_ONCE(head->first);
do {
new_last->next = first;
} while (!try_cmpxchg(&head->first, &first, new_first));
return !first;
}
static inline bool __llist_add_batch(struct llist_node *new_first,
struct llist_node *new_last,
struct llist_head *head)
{
new_last->next = head->first;
head->first = new_first;
return new_last->next == NULL;
}
/**
* llist_add - add a new entry
* @ new : new entry to be added
* @ head : the head for your lock - less list
*
* Returns true if the list was empty prior to adding this entry .
*/
static inline bool llist_add(struct llist_node *new , struct llist_head *head)
{
return llist_add_batch(new , new , head);
}
static inline bool __llist_add(struct llist_node *new , struct llist_head *head)
{
return __llist_add_batch(new , new , head);
}
/**
* llist_del_all - delete all entries from lock - less list
* @ head : the head of lock - less list to delete all entries
*
* If list is empty , return NULL , otherwise , delete all entries and
* return the pointer to the first entry . The order of entries
* deleted is from the newest to the oldest added one .
*/
static inline struct llist_node *llist_del_all(struct llist_head *head)
{
return xchg(&head->first, NULL);
}
static inline struct llist_node *__llist_del_all(struct llist_head *head)
{
struct llist_node *first = head->first;
head->first = NULL;
return first;
}
extern struct llist_node *llist_del_first(struct llist_head *head);
/**
* llist_del_first_init - delete first entry from lock - list and mark is as being off - list
* @ head : the head of lock - less list to delete from .
*
* This behave the same as llist_del_first ( ) except that llist_init_node ( ) is called
* on the returned node so that llist_on_list ( ) will report false for the node .
*/
static inline struct llist_node *llist_del_first_init(struct llist_head *head)
{
struct llist_node *n = llist_del_first(head);
if (n)
init_llist_node(n);
return n;
}
extern bool llist_del_first_this(struct llist_head *head,
struct llist_node *this );
struct llist_node *llist_reverse_order(struct llist_node *head);
#endif /* LLIST_H */
Messung V0.5 in Prozent C=96 H=88 G=91
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland