The RCU-protected list API
URCU provides two types of RCU-protected lists that are derived from the GNU libc implementation. One set is circular and doubly linked and the other set is linear but still doubly linked. In both cases, insertion and deletion are O(1) operations even given only a pointer to the item in question.
The circular lists use the cds_list_head structure
for both the list header and for list elements.
This structure is embedded within the data structure to be included
in the list.
A given data structure can be placed on multiple lists by having
multiple cds_list_head structure embedded within it.
This same cds_list_head structure can be used
both for RCU-protected lists and for lists protected by other
synchronization mechanisms.
The circular lists are best for a great many situations, but if you
are creating a large hash table, the cds_list_head structure's
pair of pointers can consume excessive amounts of storage.
This use case is better served by linear lists that have smaller header
structures.
The linear lists use the cds_hlist_head structure for
the list header and the the cds_hlist_node structure for
the list elements.
Similar to the circular list, the cds_hlist_node structure is
normally embedded within the data structure to be included in the list.
The APIs for these two types of lists should be reasonably familiar, so they are listed below with minimal explanation. The first list is for the circular lists, and the second one for the linear lists. In all cases, unless otherwise noted, the caller must take whatever action is required to ensure exclusive access by updaters and non-RCU readers to the list and elements in question, for example, by holding appropriate locks.
The operations on circular cds_list_head lists are:
- 	CDS_INIT_LIST_HEAD(ptr): Initialize acds_list_headstructure from executable code.
- 	CDS_LIST_HEAD_INIT(name): Initializer for acds_list_headstructure declaration. Example use:
 struct cds_list_head my_list = CDS_LIST_HEAD_INIT(my_list);
- 	CDS_LIST_HEAD(name): Declare and initialize acds_list_headstructure as either a global variable or an on-stack variable.
- 	void cds_list_add(struct cds_list_head *newp, struct cds_list_head *head): Add elementnewpto the head of listhead.
- 	void cds_list_add_tail(struct cds_list_head *newp, struct cds_list_head *head): Add elementnewpto the tail of listhead.
- 	void cds_list_del(struct cds_list_head *elem): Delete elementelemfrom whatever list it is part of. It is legal to call this function on an element that is not part of a list only if that element has been properly initialized.
- 	void cds_list_del_init(struct cds_list_head *elem): Similar tocds_list_del(), but initialize the element after deleting it.
- 	int cds_list_empty(struct cds_list_head *head): Returntrueif listheadis empty.
- 	cds_list_entry(ptr, type, member): Given a pointerptrto acds_list_headstructure that is embedded in a structure of typetypeas fieldmember, return a pointer to the enclosing structure.
- 	cds_list_first_entry(ptr, type, member): Given a pointerptrto acds_list_headstructure, and given that the list elements are embedded in a structure of typetypeas fieldmember, return a pointer to the enclosing structure for the first element in the list.
- 	cds_list_for_each_entry(pos, head, member): Iterate over listheadusing pointerpos(which is of the type of the enclosing structure), where thecds_list_headare fieldmemberwithin the enclosing structure. In short,posreferences each element of the list on each pass through the loop. This macro expands to aforloop, and must therefore be immediately followed by a statement or a statement block.
- 	cds_list_for_each_entry_reverse(pos, head, member): Similar tocds_list_for_each_entry(), but iterating over the list in reverse order.
- 	cds_list_for_each(pos, head): Iterate pointerposover thecds_list_headstructures in the list headed byhead.
- 	cds_list_for_each_safe(pos, p, head): Similar tocds_list_for_each(), but pre-traversing the->nextpointer so that the body of the loop can safely delete the current element.
- 	cds_list_for_each_prev(pos, head): Similar tocds_list_for_each(), but starting the traversal at the element precedingheadand preceding in reverse order.
- 	cds_list_for_each_prev_safe(pos, p, head): Similar tocds_list_for_each_prev(), but pre-traversing the->prevpointer so that the body of the loop can safely delete the current element.
- 	void cds_list_move(struct cds_list_head *elem, struct cds_list_head *head): Move elementelemfrom whatever list it is in and then add it as the first element ofhead.
- 	void cds_list_replace(struct cds_list_head *old, struct cds_list_head *_new): Remove elementoldfrom whatever list it was in and replacing it withnew.
- 	void cds_list_replace_init(struct cds_list_head *old, struct cds_list_head *_new): Similar tocds_list_replace(), but initializingold.
- 	void cds_list_splice(struct cds_list_head *add, struct cds_list_head *head): Splice the list headed byaddinto the beginning of the list headed byhead.
In addition, the following RCU-protected operations may also be used
on circular cds_list_head lists:
- 	void cds_list_add_rcu(struct cds_list_head *newp, struct cds_list_head *head): Add elementnewpto the head of listhead, allowing for concurrent RCU readers. Threads invoking this function need not be registered as RCU readers.
- 	void cds_list_del_rcu(struct cds_list_head *elem): Similar tocds_list_del(), but allow concurrent RCU readers. Threads invoking this function need not be registered as RCU readers.
- 	void cds_list_replace_rcu(struct cds_list_head *old, struct cds_list_head *_new): Similar tocds_list_replace(), but allowing concurrent RCU readers. Threads invoking this function need not be registered as RCU readers.
- 	cds_list_for_each_entry_rcu(pos, head, member): Similar tocds_list_for_each_entry(), but allowing for concurrent RCU updaters. Note that the calling thread must be registered as an RCU reader and furthermore must be in an RCU read-side critical section.
- 	cds_list_for_each_rcu(pos, head): Similar tocds_list_for_each(), but allowing concurrent RCU readers. Note that the calling thread must be registered as an RCU reader and furthermore must be in an RCU read-side critical section.
The operations on linear cds_hlist_head lists are:
- 	void CDS_INIT_HLIST_HEAD(struct cds_hlist_head *ptr): Initialize acds_hlist_headstructure from executable code.
- 	void cds_hlist_add_head(struct cds_hlist_node *newp, struct cds_hlist_head *head): Add elementnewpto the head of listhead.
- 	void cds_hlist_del(struct cds_hlist_node *elem): Delete elementelemfrom whatever list it is in.
- 	cds_hlist_entry(ptr, type, member): Given a pointerptrto acds_hlist_nodestructure that is embedded in a structure of typetypeas fieldmember, return a pointer to the enclosing structure.
- 	cds_hlist_for_each_entry(entry, pos, head, member): Iterate pointerentryover the enclosing structures of the list pointed to byhead, where thecds_hlist_nodestructures are embedded in the enclosing structures as fieldmember. Theposargument is used internally, and must be of typecds_hlist_node. This macro expands to aforstatement, so it must be immediately followed by either a statement or a statement block.
- 	cds_hlist_for_each_entry_2(entry, head, member): Iterate pointerentryover the enclosing structures of the list pointed to byhead, where thecds_hlist_nodestructures are embedded in the enclosing structures as fieldmember. This macro expands to aforstatement, so it must be immediately followed by either a statement or a statement block.
- 	cds_hlist_for_each_entry_safe(entry, pos, p, head, member): Similar tocds_hlist_for_each_entry(), but allowing the current element to be deleted and freed by the body of the loop.
- 	cds_hlist_for_each_entry_safe_2(entry, p, head, member): Similar tocds_hlist_for_each_entry_2(), but allowing the current element to be deleted and freed by the body of the loop.
In addition, the following RCU-protected operations may also be used
on linear cds_hlist_head lists:
- 	void cds_hlist_add_head_rcu(struct cds_hlist_node *newp, struct cds_hlist_head *head): Similar tocds_hlist_add_head(), but allowing concurrent RCU readers. Threads invoking this function need not be registered as RCU readers.
- 	void cds_hlist_del_rcu(struct cds_hlist_node *elem): Similar tocds_hlist_del(), but allowing concurrent RCU readers. Threads invoking this function need not be registered as RCU readers.
- 	cds_hlist_for_each_entry_rcu(entry, pos, head, member): Similar tocds_hlist_for_each_entry(), but allowing concurrent readers.
- 	cds_hlist_for_each_entry_rcu_2(entry, head, member): Similar tocds_hlist_for_each_entry_2(), but allowing concurrent readers.
Of course, parallel operations on a single list do not scale well,
at least in the absence of a very large fraction of RCU readers.
Therefore, the usual approach is to have a large number of lists,
each of which may be operated on independently.
One organized way to do this is to group lists into hash tables,
which are covered in a separate article.
 
           