| hlist.h | | hlist.h | |
| | | | |
| skipping to change at line 12 | | skipping to change at line 12 | |
| #define _KCOMPAT_HLIST_H | | #define _KCOMPAT_HLIST_H | |
| | | | |
| /* | | /* | |
| * Kernel sourcecode compatible lightweight single pointer list head useful | | * Kernel sourcecode compatible lightweight single pointer list head useful | |
| * for implementing hash tables | | * for implementing hash tables | |
| * | | * | |
| * Copyright (C) 2009 Novell Inc. | | * Copyright (C) 2009 Novell Inc. | |
| * | | * | |
| * Author: Jan Blunck <jblunck@suse.de> | | * Author: Jan Blunck <jblunck@suse.de> | |
| * | | * | |
|
| * Copyright (C) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | | * Copyright (C) 2010-2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.co
m> | |
| * | | * | |
| * This program is free software; you can redistribute it and/or modify it | | * This program is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU Lesser General Public License version 2.1 as | | * under the terms of the GNU Lesser General Public License version 2.1 as | |
| * published by the Free Software Foundation. | | * published by the Free Software Foundation. | |
| */ | | */ | |
| | | | |
| #include <stddef.h> | | #include <stddef.h> | |
| | | | |
|
| struct cds_hlist_head | | struct cds_hlist_head { | |
| { | | | |
| struct cds_hlist_node *next; | | struct cds_hlist_node *next; | |
| }; | | }; | |
| | | | |
|
| struct cds_hlist_node | | struct cds_hlist_node { | |
| { | | struct cds_hlist_node *next, *prev; | |
| struct cds_hlist_node *next; | | | |
| struct cds_hlist_node *prev; | | | |
| }; | | }; | |
| | | | |
|
| /* Initialize a new list head. */ | | /* Initialize a new list head. */ | |
| static inline void CDS_INIT_HLIST_HEAD(struct cds_hlist_head *ptr) | | static inline | |
| | | void CDS_INIT_HLIST_HEAD(struct cds_hlist_head *ptr) | |
| { | | { | |
| ptr->next = NULL; | | ptr->next = NULL; | |
| } | | } | |
| | | | |
|
| /* Get typed element from list at a given position. */ | | #define CDS_HLIST_HEAD(name) \ | |
| #define cds_hlist_entry(ptr, type, member) | | struct cds_hlist_head name = { NULL } | |
| \ | | | |
| | | #define CDS_HLIST_HEAD_INIT(name) \ | |
| | | { .next = NULL } | |
| | | | |
| | | /* Get typed element from list at a given position. */ | |
| | | #define cds_hlist_entry(ptr, type, member) \ | |
| ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))
) | | ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))
) | |
| | | | |
|
| /* Add new element at the head of the list. */ | | /* Add new element at the head of the list. */ | |
| static inline void cds_hlist_add_head (struct cds_hlist_node *newp, | | static inline | |
| struct cds_hlist_head *head) | | void cds_hlist_add_head(struct cds_hlist_node *newp, | |
| | | struct cds_hlist_head *head) | |
| { | | { | |
| if (head->next) | | if (head->next) | |
| head->next->prev = newp; | | head->next->prev = newp; | |
|
| | | | |
| newp->next = head->next; | | newp->next = head->next; | |
|
| newp->prev = (struct cds_hlist_node *)head; | | newp->prev = (struct cds_hlist_node *) head; | |
| head->next = newp; | | head->next = newp; | |
| } | | } | |
| | | | |
|
| /* Remove element from list. */ | | /* Remove element from list. */ | |
| static inline void cds_hlist_del (struct cds_hlist_node *elem) | | static inline | |
| | | void cds_hlist_del(struct cds_hlist_node *elem) | |
| { | | { | |
| if (elem->next) | | if (elem->next) | |
| elem->next->prev = elem->prev; | | elem->next->prev = elem->prev; | |
|
| | | | |
| elem->prev->next = elem->next; | | elem->prev->next = elem->next; | |
| } | | } | |
| | | | |
|
| #define cds_hlist_for_each_entry(entry, pos, head, member) | | #define cds_hlist_for_each(pos, head) \ | |
| \ | | for (pos = (head)->next; pos != NULL; pos = pos->next) | |
| for (pos = (head)->next, \ | | | |
| entry = cds_hlist_entry(pos, __typeof__(*entry), member | | #define cds_hlist_for_each_safe(pos, p, head) \ | |
| ); \ | | for (pos = (head)->next; \ | |
| pos != NULL; \ | | (pos != NULL) && (p = pos->next, 1); \ | |
| pos = pos->next, \ | | pos = p) | |
| entry = cds_hlist_entry(pos, __typeof__(*entry), member | | | |
| )) | | /* | |
| | | * cds_hlist_for_each_entry and cds_hlist_for_each_entry_safe take | |
| #define cds_hlist_for_each_entry_safe(entry, pos, p, head, member) | | * respectively 4 and 5 arguments, while the Linux kernel APIs take 3, | |
| \ | | * and 4. We implement cds_hlist_for_each_entry_2() and | |
| for (pos = (head)->next, \ | | * cds_hlist_for_each_entry_safe_2() to follow the Linux kernel APIs. | |
| entry = cds_hlist_entry(pos, __typeof__(*entry), member | | */ | |
| ); \ | | #define cds_hlist_for_each_entry(entry, pos, head, member) \ | |
| (pos != NULL) && ({ p = pos->next; 1;}); \ | | for (pos = (head)->next, \ | |
| pos = p, \ | | entry = cds_hlist_entry(pos, __typeof__(*entry), mem | |
| entry = cds_hlist_entry(pos, __typeof__(*entry), member | | ber); \ | |
| )) | | pos != NULL; \ | |
| | | pos = pos->next, \ | |
| | | entry = cds_hlist_entry(pos, __typeof__(*entry), mem | |
| | | ber)) | |
| | | | |
| | | #define cds_hlist_for_each_entry_safe(entry, pos, p, head, member) \ | |
| | | for (pos = (head)->next, \ | |
| | | entry = cds_hlist_entry(pos, __typeof__(*entry), mem | |
| | | ber); \ | |
| | | (pos != NULL) && (p = pos->next, 1); \ | |
| | | pos = p, \ | |
| | | entry = cds_hlist_entry(pos, __typeof__(*entry), mem | |
| | | ber)) | |
| | | | |
| | | #define cds_hlist_for_each_entry_2(entry, head, member) \ | |
| | | for (entry = cds_hlist_entry((head)->next, __typeof__(*entry), membe | |
| | | r); \ | |
| | | &entry->member != NULL; \ | |
| | | entry = cds_hlist_entry(entry->member.next, __typeof__(*entr | |
| | | y), member)) | |
| | | | |
| | | #define cds_hlist_for_each_entry_safe_2(entry, e, head, member) \ | |
| | | for (entry = cds_hlist_entry((head)->next, __typeof__(*entry), membe | |
| | | r); \ | |
| | | (&entry->member != NULL) && (e = cds_hlist_entry(entry->memb | |
| | | er.next, \ | |
| | | __typeof__(*entry), member), | |
| | | 1); \ | |
| | | entry = e) | |
| | | | |
| #endif /* _KCOMPAT_HLIST_H */ | | #endif /* _KCOMPAT_HLIST_H */ | |
| | | | |
End of changes. 11 change blocks. |
| 39 lines changed or deleted | | 70 lines changed or added | |
|
| list.h | | list.h | |
| | | | |
| skipping to change at line 28 | | skipping to change at line 28 | |
| * Lesser General Public License for more details. | | * Lesser General Public License for more details. | |
| * | | * | |
| * You should have received a copy of the GNU Lesser General Public | | * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | | * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | |
| */ | | */ | |
| | | | |
| #ifndef _CDS_LIST_H | | #ifndef _CDS_LIST_H | |
| #define _CDS_LIST_H 1 | | #define _CDS_LIST_H 1 | |
| | | | |
|
| /* The definitions of this file are adopted from those which can be | | /* | |
| found in the Linux kernel headers to enable people familiar with | | * The definitions of this file are adopted from those which can be | |
| the latter find their way in these sources as well. */ | | * found in the Linux kernel headers to enable people familiar with the | |
| | | * latter find their way in these sources as well. | |
| | | */ | |
| | | | |
|
| /* Basic type for the double-link list. */ | | /* Basic type for the double-link list. */ | |
| struct cds_list_head | | struct cds_list_head { | |
| { | | struct cds_list_head *next, *prev; | |
| struct cds_list_head *next; | | | |
| struct cds_list_head *prev; | | | |
| }; | | }; | |
| | | | |
|
| /* Define a variable with the head and tail of the list. */ | | /* Define a variable with the head and tail of the list. */ | |
| #define CDS_LIST_HEAD(name) \ | | #define CDS_LIST_HEAD(name) \ | |
|
| struct cds_list_head name = { &(name), &(name) } | | struct cds_list_head name = { &(name), &(name) } | |
| | | | |
|
| /* Initialize a new list head. */ | | /* Initialize a new list head. */ | |
| #define CDS_INIT_LIST_HEAD(ptr) \ | | #define CDS_INIT_LIST_HEAD(ptr) \ | |
|
| (ptr)->next = (ptr)->prev = (ptr) | | (ptr)->next = (ptr)->prev = (ptr) | |
| | | | |
| #define CDS_LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) } | | #define CDS_LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) } | |
| | | | |
|
| /* Add new element at the head of the list. */ | | /* Add new element at the head of the list. */ | |
| static inline void | | static inline | |
| cds_list_add (struct cds_list_head *newp, struct cds_list_head *head) | | void cds_list_add(struct cds_list_head *newp, struct cds_list_head *head) | |
| { | | { | |
|
| head->next->prev = newp; | | head->next->prev = newp; | |
| newp->next = head->next; | | newp->next = head->next; | |
| newp->prev = head; | | newp->prev = head; | |
| head->next = newp; | | head->next = newp; | |
| } | | } | |
| | | | |
|
| /* Add new element at the tail of the list. */ | | /* Add new element at the tail of the list. */ | |
| static inline void | | static inline | |
| cds_list_add_tail (struct cds_list_head *newp, struct cds_list_head *head) | | void cds_list_add_tail(struct cds_list_head *newp, struct cds_list_head *he | |
| | | ad) | |
| { | | { | |
|
| head->prev->next = newp; | | head->prev->next = newp; | |
| newp->next = head; | | newp->next = head; | |
| newp->prev = head->prev; | | newp->prev = head->prev; | |
| head->prev = newp; | | head->prev = newp; | |
| } | | } | |
| | | | |
|
| /* Remove element from list. */ | | /* Remove element from list. */ | |
| static inline void | | static inline | |
| __cds_list_del (struct cds_list_head *prev, struct cds_list_head *next) | | void __cds_list_del(struct cds_list_head *prev, struct cds_list_head *next) | |
| { | | { | |
|
| next->prev = prev; | | next->prev = prev; | |
| prev->next = next; | | prev->next = next; | |
| } | | } | |
| | | | |
|
| /* Remove element from list. */ | | /* Remove element from list. */ | |
| static inline void | | static inline | |
| cds_list_del (struct cds_list_head *elem) | | void cds_list_del(struct cds_list_head *elem) | |
| { | | { | |
|
| __cds_list_del (elem->prev, elem->next); | | __cds_list_del(elem->prev, elem->next); | |
| } | | } | |
| | | | |
| /* Remove element from list, initializing the element's list pointers. */ | | /* Remove element from list, initializing the element's list pointers. */ | |
|
| static inline void | | static inline | |
| cds_list_del_init (struct cds_list_head *elem) | | void cds_list_del_init(struct cds_list_head *elem) | |
| { | | { | |
| cds_list_del(elem); | | cds_list_del(elem); | |
| CDS_INIT_LIST_HEAD(elem); | | CDS_INIT_LIST_HEAD(elem); | |
| } | | } | |
| | | | |
|
| /* delete from list, add to another list as head */ | | /* Delete from list, add to another list as head. */ | |
| static inline void | | static inline | |
| cds_list_move (struct cds_list_head *elem, struct cds_list_head *head) | | void cds_list_move(struct cds_list_head *elem, struct cds_list_head *head) | |
| { | | { | |
|
| __cds_list_del (elem->prev, elem->next); | | __cds_list_del(elem->prev, elem->next); | |
| cds_list_add (elem, head); | | cds_list_add(elem, head); | |
| } | | } | |
| | | | |
|
| /* replace an old entry. | | /* Replace an old entry. */ | |
| */ | | static inline | |
| static inline void | | void cds_list_replace(struct cds_list_head *old, struct cds_list_head *_new | |
| cds_list_replace(struct cds_list_head *old, struct cds_list_head *_new) | | ) | |
| { | | { | |
| _new->next = old->next; | | _new->next = old->next; | |
| _new->prev = old->prev; | | _new->prev = old->prev; | |
| _new->prev->next = _new; | | _new->prev->next = _new; | |
| _new->next->prev = _new; | | _new->next->prev = _new; | |
| } | | } | |
| | | | |
|
| /* Join two lists. */ | | /* Join two lists. */ | |
| static inline void | | static inline | |
| cds_list_splice (struct cds_list_head *add, struct cds_list_head *head) | | void cds_list_splice(struct cds_list_head *add, struct cds_list_head *head) | |
| { | | { | |
| /* Do nothing if the list which gets added is empty. */ | | /* Do nothing if the list which gets added is empty. */ | |
| if (add != add->next) | | if (add != add->next) { | |
| { | | add->next->prev = head; | |
| add->next->prev = head; | | add->prev->next = head->next; | |
| add->prev->next = head->next; | | head->next->prev = add->prev; | |
| head->next->prev = add->prev; | | head->next = add->next; | |
| head->next = add->next; | | } | |
| } | | | |
| } | | } | |
| | | | |
|
| /* Get typed element from list at a given position. */ | | /* Get typed element from list at a given position. */ | |
| #define cds_list_entry(ptr, type, member) \ | | #define cds_list_entry(ptr, type, member) \ | |
|
| ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) | | ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))
) | |
| | | | |
| /* Get first entry from a list. */ | | /* Get first entry from a list. */ | |
| #define cds_list_first_entry(ptr, type, member) \ | | #define cds_list_first_entry(ptr, type, member) \ | |
| cds_list_entry((ptr)->next, type, member) | | cds_list_entry((ptr)->next, type, member) | |
| | | | |
|
| /* Iterate forward over the elements of the list. */ | | /* Iterate forward over the elements of the list. */ | |
| #define cds_list_for_each(pos, head) \ | | #define cds_list_for_each(pos, head) \ | |
|
| for (pos = (head)->next; pos != (head); pos = pos->next) | | for (pos = (head)->next; pos != (head); pos = pos->next) | |
| | | | |
|
| /* Iterate forward over the elements of the list. */ | | /* | |
| | | * Iterate forward over the elements list. The list elements can be | |
| | | * removed from the list while doing this. | |
| | | */ | |
| | | #define cds_list_for_each_safe(pos, p, head) \ | |
| | | for (pos = (head)->next, p = pos->next; \ | |
| | | pos != (head); \ | |
| | | pos = p, p = pos->next) | |
| | | | |
| | | /* Iterate backward over the elements of the list. */ | |
| #define cds_list_for_each_prev(pos, head) \ | | #define cds_list_for_each_prev(pos, head) \ | |
|
| for (pos = (head)->prev; pos != (head); pos = pos->prev) | | for (pos = (head)->prev; pos != (head); pos = pos->prev) | |
| | | | |
|
| /* Iterate backwards over the elements list. The list elements can be | | /* | |
| removed from the list while doing this. */ | | * Iterate backwards over the elements list. The list elements can be | |
| | | * removed from the list while doing this. | |
| | | */ | |
| #define cds_list_for_each_prev_safe(pos, p, head) \ | | #define cds_list_for_each_prev_safe(pos, p, head) \ | |
|
| for (pos = (head)->prev, p = pos->prev; \ | | for (pos = (head)->prev, p = pos->prev; \ | |
| pos != (head); \ | | pos != (head); \ | |
| pos = p, p = pos->prev) | | pos = p, p = pos->prev) | |
| | | | |
|
| #define cds_list_for_each_entry(pos, head, member)
\ | | #define cds_list_for_each_entry(pos, head, member) \ | |
| for (pos = cds_list_entry((head)->next, __typeof__(*pos), member); \ | | for (pos = cds_list_entry((head)->next, __typeof__(*pos), member); \ | |
|
| &pos->member != (head); \ | | &pos->member != (head); \ | |
| pos = cds_list_entry(pos->member.next, __typeof__(*pos), member | | pos = cds_list_entry(pos->member.next, __typeof__(*pos), mem | |
| )) | | ber)) | |
| | | | |
|
| #define cds_list_for_each_entry_reverse(pos, head, member)
\ | | #define cds_list_for_each_entry_reverse(pos, head, member) \ | |
| for (pos = cds_list_entry((head)->prev, __typeof__(*pos), member); \ | | for (pos = cds_list_entry((head)->prev, __typeof__(*pos), member); \ | |
|
| &pos->member != (head); \ | | &pos->member != (head); \ | |
| pos = cds_list_entry(pos->member.prev, __typeof__(*pos), member | | pos = cds_list_entry(pos->member.prev, __typeof__(*pos), mem | |
| )) | | ber)) | |
| | | | |
|
| #define cds_list_for_each_entry_safe(pos, p, head, member)
\ | | #define cds_list_for_each_entry_safe(pos, p, head, member) \ | |
| for (pos = cds_list_entry((head)->next, __typeof__(*pos), member), \ | | for (pos = cds_list_entry((head)->next, __typeof__(*pos), member), \ | |
|
| p = cds_list_entry(pos->member.next, __typeof__(*pos), | | p = cds_list_entry(pos->member.next, __typeof__(*pos | |
| member); \ | | ), member); \ | |
| &pos->member != (head); \ | | &pos->member != (head); \ | |
| pos = p, p = cds_list_entry(pos->member.next, __typeof__(*pos), | | pos = p, p = cds_list_entry(pos->member.next, __typeof__(*po | |
| member)) | | s), member)) | |
| | | | |
|
| static inline int cds_list_empty(struct cds_list_head *head) | | static inline | |
| | | int cds_list_empty(struct cds_list_head *head) | |
| { | | { | |
| return head == head->next; | | return head == head->next; | |
| } | | } | |
| | | | |
|
| static inline void cds_list_replace_init(struct cds_list_head *old, | | static inline | |
| struct cds_list_head *_new) | | void cds_list_replace_init(struct cds_list_head *old, | |
| | | struct cds_list_head *_new) | |
| { | | { | |
| struct cds_list_head *head = old->next; | | struct cds_list_head *head = old->next; | |
|
| | | | |
| cds_list_del(old); | | cds_list_del(old); | |
| cds_list_add_tail(_new, head); | | cds_list_add_tail(_new, head); | |
| CDS_INIT_LIST_HEAD(old); | | CDS_INIT_LIST_HEAD(old); | |
| } | | } | |
| | | | |
| #endif /* _CDS_LIST_H */ | | #endif /* _CDS_LIST_H */ | |
| | | | |
End of changes. 36 change blocks. |
| 86 lines changed or deleted | | 100 lines changed or added | |
|
| rculfhash.h | | rculfhash.h | |
| | | | |
| skipping to change at line 121 | | skipping to change at line 121 | |
| unsigned long index); | | unsigned long index); | |
| }; | | }; | |
| | | | |
| extern const struct cds_lfht_mm_type cds_lfht_mm_order; | | extern const struct cds_lfht_mm_type cds_lfht_mm_order; | |
| extern const struct cds_lfht_mm_type cds_lfht_mm_chunk; | | extern const struct cds_lfht_mm_type cds_lfht_mm_chunk; | |
| extern const struct cds_lfht_mm_type cds_lfht_mm_mmap; | | extern const struct cds_lfht_mm_type cds_lfht_mm_mmap; | |
| | | | |
| /* | | /* | |
| * _cds_lfht_new - API used by cds_lfht_new wrapper. Do not use directly. | | * _cds_lfht_new - API used by cds_lfht_new wrapper. Do not use directly. | |
| */ | | */ | |
|
| | | extern | |
| struct cds_lfht *_cds_lfht_new(unsigned long init_size, | | struct cds_lfht *_cds_lfht_new(unsigned long init_size, | |
| unsigned long min_nr_alloc_buckets, | | unsigned long min_nr_alloc_buckets, | |
| unsigned long max_nr_buckets, | | unsigned long max_nr_buckets, | |
| int flags, | | int flags, | |
| const struct cds_lfht_mm_type *mm, | | const struct cds_lfht_mm_type *mm, | |
| const struct rcu_flavor_struct *flavor, | | const struct rcu_flavor_struct *flavor, | |
| pthread_attr_t *attr); | | pthread_attr_t *attr); | |
| | | | |
| /* | | /* | |
| * cds_lfht_new - allocate a hash table. | | * cds_lfht_new - allocate a hash table. | |
| * @init_size: number of buckets to allocate initially. Must be power of tw
o. | | * @init_size: number of buckets to allocate initially. Must be power of tw
o. | |
| * @min_nr_alloc_buckets: the minimum number of allocated buckets. | | * @min_nr_alloc_buckets: the minimum number of allocated buckets. | |
| * (must be power of two) | | * (must be power of two) | |
| * @max_nr_buckets: the maximum number of hash table buckets allowed. | | * @max_nr_buckets: the maximum number of hash table buckets allowed. | |
|
| * (must be power of two, 0 is accepted, means | | * (must be power of two) | |
| * "infinite") | | | |
| * @flags: hash table creation flags (can be combined with bitwise or: '|')
. | | * @flags: hash table creation flags (can be combined with bitwise or: '|')
. | |
| * 0: no flags. | | * 0: no flags. | |
| * CDS_LFHT_AUTO_RESIZE: automatically resize hash table. | | * CDS_LFHT_AUTO_RESIZE: automatically resize hash table. | |
| * CDS_LFHT_ACCOUNTING: count the number of node addition | | * CDS_LFHT_ACCOUNTING: count the number of node addition | |
| * and removal in the table | | * and removal in the table | |
| * @attr: optional resize worker thread attributes. NULL for default. | | * @attr: optional resize worker thread attributes. NULL for default. | |
| * | | * | |
| * Return NULL on error. | | * Return NULL on error. | |
| * Note: the RCU flavor must be already included before the hash table head
er. | | * Note: the RCU flavor must be already included before the hash table head
er. | |
| * | | * | |
| | | | |
| skipping to change at line 180 | | skipping to change at line 180 | |
| * cds_lfht_destroy - destroy a hash table. | | * cds_lfht_destroy - destroy a hash table. | |
| * @ht: the hash table to destroy. | | * @ht: the hash table to destroy. | |
| * @attr: (output) resize worker thread attributes, as received by cds_lfht
_new. | | * @attr: (output) resize worker thread attributes, as received by cds_lfht
_new. | |
| * The caller will typically want to free this pointer if dynamicall
y | | * The caller will typically want to free this pointer if dynamicall
y | |
| * allocated. The attr point can be NULL if the caller does not | | * allocated. The attr point can be NULL if the caller does not | |
| * need to be informed of the value passed to cds_lfht_new(). | | * need to be informed of the value passed to cds_lfht_new(). | |
| * | | * | |
| * Return 0 on success, negative error value on error. | | * Return 0 on success, negative error value on error. | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| * cds_lfht_destroy should *not* be called from a RCU read-side critical | | * cds_lfht_destroy should *not* be called from a RCU read-side critical | |
|
| * section. It should *not* be called from call_rcu thread context | | * section. It should *not* be called from a call_rcu thread context | |
| * neither. | | * neither. | |
|
| * In userspace RCU 0.7.x, for QSBR RCU flavor, cds_lfht_destroy() has a | | | |
| * side-effect: it puts the caller thread in "online" state. This will | | | |
| * be fixed in userspace RCU 0.8.x. | | | |
| */ | | */ | |
|
| | | extern | |
| int cds_lfht_destroy(struct cds_lfht *ht, pthread_attr_t **attr); | | int cds_lfht_destroy(struct cds_lfht *ht, pthread_attr_t **attr); | |
| | | | |
| /* | | /* | |
| * cds_lfht_count_nodes - count the number of nodes in the hash table. | | * cds_lfht_count_nodes - count the number of nodes in the hash table. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @split_count_before: sample the node count split-counter before traversa
l. | | * @split_count_before: sample the node count split-counter before traversa
l. | |
| * @count: traverse the hash table, count the number of nodes observed. | | * @count: traverse the hash table, count the number of nodes observed. | |
| * @split_count_after: sample the node count split-counter after traversal. | | * @split_count_after: sample the node count split-counter after traversal. | |
| * | | * | |
| * Call with rcu_read_lock held. | | * Call with rcu_read_lock held. | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| */ | | */ | |
|
| | | extern | |
| void cds_lfht_count_nodes(struct cds_lfht *ht, | | void cds_lfht_count_nodes(struct cds_lfht *ht, | |
| long *split_count_before, | | long *split_count_before, | |
| unsigned long *count, | | unsigned long *count, | |
| long *split_count_after); | | long *split_count_after); | |
| | | | |
| /* | | /* | |
| * cds_lfht_lookup - lookup a node by key. | | * cds_lfht_lookup - lookup a node by key. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @hash: the key hash. | | * @hash: the key hash. | |
| * @match: the key match function. | | * @match: the key match function. | |
| * @key: the current node key. | | * @key: the current node key. | |
| * @iter: node, if found (output). *iter->node set to NULL if not found. | | * @iter: node, if found (output). *iter->node set to NULL if not found. | |
| * | | * | |
| * Call with rcu_read_lock held. | | * Call with rcu_read_lock held. | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| * This function acts as a rcu_dereference() to read the node pointer. | | * This function acts as a rcu_dereference() to read the node pointer. | |
| */ | | */ | |
|
| | | extern | |
| void cds_lfht_lookup(struct cds_lfht *ht, unsigned long hash, | | void cds_lfht_lookup(struct cds_lfht *ht, unsigned long hash, | |
| cds_lfht_match_fct match, const void *key, | | cds_lfht_match_fct match, const void *key, | |
| struct cds_lfht_iter *iter); | | struct cds_lfht_iter *iter); | |
| | | | |
| /* | | /* | |
| * cds_lfht_next_duplicate - get the next item with same key, after iterato
r. | | * cds_lfht_next_duplicate - get the next item with same key, after iterato
r. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @match: the key match function. | | * @match: the key match function. | |
| * @key: the current node key. | | * @key: the current node key. | |
| * @iter: input: current iterator. | | * @iter: input: current iterator. | |
| | | | |
| skipping to change at line 239 | | skipping to change at line 239 | |
| * cds_lfht_next_duplicate. | | * cds_lfht_next_duplicate. | |
| * Sets *iter-node to the following node with same key. | | * Sets *iter-node to the following node with same key. | |
| * Sets *iter->node to NULL if no following node exists with same key. | | * Sets *iter->node to NULL if no following node exists with same key. | |
| * RCU read-side lock must be held across cds_lfht_lookup and | | * RCU read-side lock must be held across cds_lfht_lookup and | |
| * cds_lfht_next calls, and also between cds_lfht_next calls using the | | * cds_lfht_next calls, and also between cds_lfht_next calls using the | |
| * node returned by a previous cds_lfht_next. | | * node returned by a previous cds_lfht_next. | |
| * Call with rcu_read_lock held. | | * Call with rcu_read_lock held. | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| * This function acts as a rcu_dereference() to read the node pointer. | | * This function acts as a rcu_dereference() to read the node pointer. | |
| */ | | */ | |
|
| | | extern | |
| void cds_lfht_next_duplicate(struct cds_lfht *ht, | | void cds_lfht_next_duplicate(struct cds_lfht *ht, | |
| cds_lfht_match_fct match, const void *key, | | cds_lfht_match_fct match, const void *key, | |
| struct cds_lfht_iter *iter); | | struct cds_lfht_iter *iter); | |
| | | | |
| /* | | /* | |
| * cds_lfht_first - get the first node in the table. | | * cds_lfht_first - get the first node in the table. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @iter: First node, if exists (output). *iter->node set to NULL if not fo
und. | | * @iter: First node, if exists (output). *iter->node set to NULL if not fo
und. | |
| * | | * | |
| * Output in "*iter". *iter->node set to NULL if table is empty. | | * Output in "*iter". *iter->node set to NULL if table is empty. | |
| * Call with rcu_read_lock held. | | * Call with rcu_read_lock held. | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| * This function acts as a rcu_dereference() to read the node pointer. | | * This function acts as a rcu_dereference() to read the node pointer. | |
| */ | | */ | |
|
| | | extern | |
| void cds_lfht_first(struct cds_lfht *ht, struct cds_lfht_iter *iter); | | void cds_lfht_first(struct cds_lfht *ht, struct cds_lfht_iter *iter); | |
| | | | |
| /* | | /* | |
| * cds_lfht_next - get the next node in the table. | | * cds_lfht_next - get the next node in the table. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @iter: input: current iterator. | | * @iter: input: current iterator. | |
| * output: next node, if exists. *iter->node set to NULL if not foun
d. | | * output: next node, if exists. *iter->node set to NULL if not foun
d. | |
| * | | * | |
| * Input/Output in "*iter". *iter->node set to NULL if *iter was | | * Input/Output in "*iter". *iter->node set to NULL if *iter was | |
| * pointing to the last table node. | | * pointing to the last table node. | |
| * Call with rcu_read_lock held. | | * Call with rcu_read_lock held. | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| * This function acts as a rcu_dereference() to read the node pointer. | | * This function acts as a rcu_dereference() to read the node pointer. | |
| */ | | */ | |
|
| | | extern | |
| void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter); | | void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter); | |
| | | | |
| /* | | /* | |
| * cds_lfht_add - add a node to the hash table. | | * cds_lfht_add - add a node to the hash table. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @hash: the key hash. | | * @hash: the key hash. | |
| * @node: the node to add. | | * @node: the node to add. | |
| * | | * | |
| * This function supports adding redundant keys into the table. | | * This function supports adding redundant keys into the table. | |
| * Call with rcu_read_lock held. | | * Call with rcu_read_lock held. | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| * This function issues a full memory barrier before and after its | | * This function issues a full memory barrier before and after its | |
| * atomic commit. | | * atomic commit. | |
| */ | | */ | |
|
| | | extern | |
| void cds_lfht_add(struct cds_lfht *ht, unsigned long hash, | | void cds_lfht_add(struct cds_lfht *ht, unsigned long hash, | |
| struct cds_lfht_node *node); | | struct cds_lfht_node *node); | |
| | | | |
| /* | | /* | |
| * cds_lfht_add_unique - add a node to hash table, if key is not present. | | * cds_lfht_add_unique - add a node to hash table, if key is not present. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @hash: the node's hash. | | * @hash: the node's hash. | |
| * @match: the key match function. | | * @match: the key match function. | |
| * @key: the node's key. | | * @key: the node's key. | |
| * @node: the node to try adding. | | * @node: the node to try adding. | |
| | | | |
| skipping to change at line 311 | | skipping to change at line 315 | |
| * to add keys into the table, no duplicated keys should ever be | | * to add keys into the table, no duplicated keys should ever be | |
| * observable in the table. The same guarantee apply for combination of | | * observable in the table. The same guarantee apply for combination of | |
| * add_unique and add_replace (see below). | | * add_unique and add_replace (see below). | |
| * | | * | |
| * Upon success, this function issues a full memory barrier before and | | * Upon success, this function issues a full memory barrier before and | |
| * after its atomic commit. Upon failure, this function acts like a | | * after its atomic commit. Upon failure, this function acts like a | |
| * simple lookup operation: it acts as a rcu_dereference() to read the | | * simple lookup operation: it acts as a rcu_dereference() to read the | |
| * node pointer. The failure case does not guarantee any other memory | | * node pointer. The failure case does not guarantee any other memory | |
| * barrier. | | * barrier. | |
| */ | | */ | |
|
| | | extern | |
| struct cds_lfht_node *cds_lfht_add_unique(struct cds_lfht *ht, | | struct cds_lfht_node *cds_lfht_add_unique(struct cds_lfht *ht, | |
| unsigned long hash, | | unsigned long hash, | |
| cds_lfht_match_fct match, | | cds_lfht_match_fct match, | |
| const void *key, | | const void *key, | |
| struct cds_lfht_node *node); | | struct cds_lfht_node *node); | |
| | | | |
| /* | | /* | |
| * cds_lfht_add_replace - replace or add a node within hash table. | | * cds_lfht_add_replace - replace or add a node within hash table. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @hash: the node's hash. | | * @hash: the node's hash. | |
| | | | |
| skipping to change at line 347 | | skipping to change at line 352 | |
| * replaced concurrently with the lookups. | | * replaced concurrently with the lookups. | |
| * | | * | |
| * Providing this semantic allows us to ensure that replacement-only | | * Providing this semantic allows us to ensure that replacement-only | |
| * schemes will never generate duplicated keys. It also allows us to | | * schemes will never generate duplicated keys. It also allows us to | |
| * guarantee that a combination of add_replace and add_unique updates | | * guarantee that a combination of add_replace and add_unique updates | |
| * will never generate duplicated keys. | | * will never generate duplicated keys. | |
| * | | * | |
| * This function issues a full memory barrier before and after its | | * This function issues a full memory barrier before and after its | |
| * atomic commit. | | * atomic commit. | |
| */ | | */ | |
|
| | | extern | |
| struct cds_lfht_node *cds_lfht_add_replace(struct cds_lfht *ht, | | struct cds_lfht_node *cds_lfht_add_replace(struct cds_lfht *ht, | |
| unsigned long hash, | | unsigned long hash, | |
| cds_lfht_match_fct match, | | cds_lfht_match_fct match, | |
| const void *key, | | const void *key, | |
| struct cds_lfht_node *node); | | struct cds_lfht_node *node); | |
| | | | |
| /* | | /* | |
| * cds_lfht_replace - replace a node pointed to by iter within hash table. | | * cds_lfht_replace - replace a node pointed to by iter within hash table. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @old_iter: the iterator position of the node to replace. | | * @old_iter: the iterator position of the node to replace. | |
| | | | |
| skipping to change at line 382 | | skipping to change at line 388 | |
| * freeing the memory reserved for the old node (which can be accessed | | * freeing the memory reserved for the old node (which can be accessed | |
| * with cds_lfht_iter_get_node). | | * with cds_lfht_iter_get_node). | |
| * | | * | |
| * The semantic of replacement vs lookups is the same as | | * The semantic of replacement vs lookups is the same as | |
| * cds_lfht_add_replace(). | | * cds_lfht_add_replace(). | |
| * | | * | |
| * Upon success, this function issues a full memory barrier before and | | * Upon success, this function issues a full memory barrier before and | |
| * after its atomic commit. Upon failure, this function does not issue | | * after its atomic commit. Upon failure, this function does not issue | |
| * any memory barrier. | | * any memory barrier. | |
| */ | | */ | |
|
| | | extern | |
| int cds_lfht_replace(struct cds_lfht *ht, | | int cds_lfht_replace(struct cds_lfht *ht, | |
| struct cds_lfht_iter *old_iter, | | struct cds_lfht_iter *old_iter, | |
| unsigned long hash, | | unsigned long hash, | |
| cds_lfht_match_fct match, | | cds_lfht_match_fct match, | |
| const void *key, | | const void *key, | |
| struct cds_lfht_node *new_node); | | struct cds_lfht_node *new_node); | |
| | | | |
| /* | | /* | |
| * cds_lfht_del - remove node pointed to by iterator from hash table. | | * cds_lfht_del - remove node pointed to by iterator from hash table. | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| | | | |
| skipping to change at line 410 | | skipping to change at line 417 | |
| * RCU read-side lock must be held between lookup and removal. | | * RCU read-side lock must be held between lookup and removal. | |
| * Call with rcu_read_lock held. | | * Call with rcu_read_lock held. | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| * After successful removal, a grace period must be waited for before | | * After successful removal, a grace period must be waited for before | |
| * freeing the memory reserved for old node (which can be accessed with | | * freeing the memory reserved for old node (which can be accessed with | |
| * cds_lfht_iter_get_node). | | * cds_lfht_iter_get_node). | |
| * Upon success, this function issues a full memory barrier before and | | * Upon success, this function issues a full memory barrier before and | |
| * after its atomic commit. Upon failure, this function does not issue | | * after its atomic commit. Upon failure, this function does not issue | |
| * any memory barrier. | | * any memory barrier. | |
| */ | | */ | |
|
| | | extern | |
| int cds_lfht_del(struct cds_lfht *ht, struct cds_lfht_node *node); | | int cds_lfht_del(struct cds_lfht *ht, struct cds_lfht_node *node); | |
| | | | |
| /* | | /* | |
| * cds_lfht_is_node_deleted - query whether a node is removed from hash tab
le. | | * cds_lfht_is_node_deleted - query whether a node is removed from hash tab
le. | |
| * | | * | |
| * Return non-zero if the node is deleted from the hash table, 0 | | * Return non-zero if the node is deleted from the hash table, 0 | |
| * otherwise. | | * otherwise. | |
| * Node can be looked up with cds_lfht_lookup and cds_lfht_next, | | * Node can be looked up with cds_lfht_lookup and cds_lfht_next, | |
| * followed by use of cds_lfht_iter_get_node. | | * followed by use of cds_lfht_iter_get_node. | |
| * RCU read-side lock must be held between lookup and call to this | | * RCU read-side lock must be held between lookup and call to this | |
| * function. | | * function. | |
| * Call with rcu_read_lock held. | | * Call with rcu_read_lock held. | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| * This function does not issue any memory barrier. | | * This function does not issue any memory barrier. | |
| */ | | */ | |
|
| | | extern | |
| int cds_lfht_is_node_deleted(struct cds_lfht_node *node); | | int cds_lfht_is_node_deleted(struct cds_lfht_node *node); | |
| | | | |
| /* | | /* | |
| * cds_lfht_resize - Force a hash table resize | | * cds_lfht_resize - Force a hash table resize | |
| * @ht: the hash table. | | * @ht: the hash table. | |
| * @new_size: update to this hash table size. | | * @new_size: update to this hash table size. | |
| * | | * | |
| * Threads calling this API need to be registered RCU read-side threads. | | * Threads calling this API need to be registered RCU read-side threads. | |
| * This function does not (necessarily) issue memory barriers. | | * This function does not (necessarily) issue memory barriers. | |
| * cds_lfht_resize should *not* be called from a RCU read-side critical | | * cds_lfht_resize should *not* be called from a RCU read-side critical | |
| * section. | | * section. | |
|
| * In userspace RCU 0.7.x, for QSBR RCU flavor, cds_lfht_resize() has a | | | |
| * side-effect: it puts the caller thread in "online" state. This will | | | |
| * be fixed in userspace RCU 0.8.x. | | | |
| */ | | */ | |
|
| | | extern | |
| void cds_lfht_resize(struct cds_lfht *ht, unsigned long new_size); | | void cds_lfht_resize(struct cds_lfht *ht, unsigned long new_size); | |
| | | | |
| /* | | /* | |
| * Note: it is safe to perform element removal (del), replacement, or | | * Note: it is safe to perform element removal (del), replacement, or | |
| * any hash table update operation during any of the following hash | | * any hash table update operation during any of the following hash | |
| * table traversals. | | * table traversals. | |
| * These functions act as rcu_dereference() to read the node pointers. | | * These functions act as rcu_dereference() to read the node pointers. | |
| */ | | */ | |
| #define cds_lfht_for_each(ht, iter, node) \ | | #define cds_lfht_for_each(ht, iter, node) \ | |
| for (cds_lfht_first(ht, iter), \ | | for (cds_lfht_first(ht, iter), \ | |
| | | | |
| skipping to change at line 466 | | skipping to change at line 473 | |
| for (cds_lfht_lookup(ht, hash, match, key, iter), \ | | for (cds_lfht_lookup(ht, hash, match, key, iter), \ | |
| node = cds_lfht_iter_get_node(iter); \ | | node = cds_lfht_iter_get_node(iter); \ | |
| node != NULL; \ | | node != NULL; \ | |
| cds_lfht_next_duplicate(ht, match, key, iter), \ | | cds_lfht_next_duplicate(ht, match, key, iter), \ | |
| node = cds_lfht_iter_get_node(iter)) | | node = cds_lfht_iter_get_node(iter)) | |
| | | | |
| #define cds_lfht_for_each_entry(ht, iter, pos, member) \ | | #define cds_lfht_for_each_entry(ht, iter, pos, member) \ | |
| for (cds_lfht_first(ht, iter), \ | | for (cds_lfht_first(ht, iter), \ | |
| pos = caa_container_of(cds_lfht_iter_get_node(iter),
\ | | pos = caa_container_of(cds_lfht_iter_get_node(iter),
\ | |
| __typeof__(*(pos)), member); \ | | __typeof__(*(pos)), member); \ | |
|
| cds_lfht_iter_get_node(iter) != NULL; \ | | &(pos)->member != NULL; \ | |
| cds_lfht_next(ht, iter), \ | | cds_lfht_next(ht, iter), \ | |
| pos = caa_container_of(cds_lfht_iter_get_node(iter),
\ | | pos = caa_container_of(cds_lfht_iter_get_node(iter),
\ | |
| __typeof__(*(pos)), member)) | | __typeof__(*(pos)), member)) | |
| | | | |
| #define cds_lfht_for_each_entry_duplicate(ht, hash, match, key,
\ | | #define cds_lfht_for_each_entry_duplicate(ht, hash, match, key,
\ | |
| iter, pos, member) \ | | iter, pos, member) \ | |
| for (cds_lfht_lookup(ht, hash, match, key, iter), \ | | for (cds_lfht_lookup(ht, hash, match, key, iter), \ | |
| pos = caa_container_of(cds_lfht_iter_get_node(iter),
\ | | pos = caa_container_of(cds_lfht_iter_get_node(iter),
\ | |
| __typeof__(*(pos)), member); \ | | __typeof__(*(pos)), member); \ | |
|
| cds_lfht_iter_get_node(iter) != NULL; \ | | &(pos)->member != NULL; \ | |
| cds_lfht_next_duplicate(ht, match, key, iter), \ | | cds_lfht_next_duplicate(ht, match, key, iter), \ | |
| pos = caa_container_of(cds_lfht_iter_get_node(iter),
\ | | pos = caa_container_of(cds_lfht_iter_get_node(iter),
\ | |
| __typeof__(*(pos)), member)) | | __typeof__(*(pos)), member)) | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_RCULFHASH_H */ | | #endif /* _URCU_RCULFHASH_H */ | |
| | | | |
End of changes. 20 change blocks. |
| 11 lines changed or deleted | | 18 lines changed or added | |
|
| tls-compat.h | | tls-compat.h | |
| | | | |
| skipping to change at line 47 | | skipping to change at line 47 | |
| /* | | /* | |
| * Hint: How to define/declare TLS variables of compound types | | * Hint: How to define/declare TLS variables of compound types | |
| * such as array or function pointers? | | * such as array or function pointers? | |
| * | | * | |
| * Answer: Use typedef to assign a type_name to the compound type. | | * Answer: Use typedef to assign a type_name to the compound type. | |
| * Example: Define a TLS variable which is an int array with len=4: | | * Example: Define a TLS variable which is an int array with len=4: | |
| * | | * | |
| * typedef int my_int_array_type[4]; | | * typedef int my_int_array_type[4]; | |
| * DEFINE_URCU_TLS(my_int_array_type, var_name); | | * DEFINE_URCU_TLS(my_int_array_type, var_name); | |
| * | | * | |
|
| * Another exmaple: | | * Another example: | |
| * typedef void (*call_rcu_flavor)(struct rcu_head *, XXXX); | | * typedef void (*call_rcu_flavor)(struct rcu_head *, XXXX); | |
| * DECLARE_URCU_TLS(call_rcu_flavor, p_call_rcu); | | * DECLARE_URCU_TLS(call_rcu_flavor, p_call_rcu); | |
| * | | * | |
| * NOTE: URCU_TLS() is NOT async-signal-safe, you can't use it | | * NOTE: URCU_TLS() is NOT async-signal-safe, you can't use it | |
| * inside any function which can be called from signal handler. | | * inside any function which can be called from signal handler. | |
| * | | * | |
| * But if pthread_getspecific() is async-signal-safe in your | | * But if pthread_getspecific() is async-signal-safe in your | |
| * platform, you can make URCU_TLS() async-signal-safe via: | | * platform, you can make URCU_TLS() async-signal-safe via: | |
| * ensuring the first call to URCU_TLS() of a given TLS variable of | | * ensuring the first call to URCU_TLS() of a given TLS variable of | |
| * all threads is called earliest from a non-signal handler function. | | * all threads is called earliest from a non-signal handler function. | |
| | | | |
| skipping to change at line 73 | | skipping to change at line 73 | |
| * Moreover, URCU_TLS variables should not be touched from signal | | * Moreover, URCU_TLS variables should not be touched from signal | |
| * handlers setup with with sigaltstack(2). | | * handlers setup with with sigaltstack(2). | |
| */ | | */ | |
| | | | |
| # define DECLARE_URCU_TLS(type, name) \ | | # define DECLARE_URCU_TLS(type, name) \ | |
| CONFIG_RCU_TLS type name | | CONFIG_RCU_TLS type name | |
| | | | |
| # define DEFINE_URCU_TLS(type, name) \ | | # define DEFINE_URCU_TLS(type, name) \ | |
| CONFIG_RCU_TLS type name | | CONFIG_RCU_TLS type name | |
| | | | |
|
| # define __DEFINE_URCU_TLS_GLOBAL(type, name) \ | | | |
| CONFIG_RCU_TLS type name | | | |
| | | | |
| # define URCU_TLS(name) (name) | | # define URCU_TLS(name) (name) | |
| | | | |
| #else /* #ifndef CONFIG_RCU_TLS */ | | #else /* #ifndef CONFIG_RCU_TLS */ | |
| | | | |
|
| /* | | | |
| * The *_1() macros ensure macro parameters are expanded. | | | |
| * | | | |
| * __DEFINE_URCU_TLS_GLOBAL and __URCU_TLS_CALL exist for the sole | | | |
| * purpose of notifying applications compiled against non-fixed 0.7 and | | | |
| * 0.8 userspace RCU headers and using multiple flavors concurrently to | | | |
| * recompile against fixed userspace RCU headers. | | | |
| */ | | | |
| | | | |
| # include <pthread.h> | | # include <pthread.h> | |
| | | | |
| struct urcu_tls { | | struct urcu_tls { | |
| pthread_key_t key; | | pthread_key_t key; | |
| pthread_mutex_t init_mutex; | | pthread_mutex_t init_mutex; | |
| int init_done; | | int init_done; | |
| }; | | }; | |
| | | | |
|
| # define DECLARE_URCU_TLS_1(type, name) \ | | | |
| type *__tls_access2_ ## name(void) | | | |
| | | | |
| # define DECLARE_URCU_TLS(type, name) \ | | # define DECLARE_URCU_TLS(type, name) \ | |
|
| DECLARE_URCU_TLS_1(type, name) | | type *__tls_access_ ## name(void) | |
| | | | |
| /* | | /* | |
| * Note: we don't free memory at process exit, since it will be dealt | | * Note: we don't free memory at process exit, since it will be dealt | |
| * with by the OS. | | * with by the OS. | |
| */ | | */ | |
|
| # define __URCU_TLS_CALL_1(name) \ | | # define DEFINE_URCU_TLS(type, name) \ | |
| __tls_access2_ ## name | | type *__tls_access_ ## name(void) \ | |
| | | | |
| # define __URCU_TLS_CALL(name) \ | | | |
| __URCU_TLS_CALL_1(name) | | | |
| | | | |
| # define DEFINE_URCU_TLS_1(type, name) \ | | | |
| type *__tls_access2_ ## name(void) \ | | | |
| { \ | | { \ | |
| static struct urcu_tls __tls_ ## name = { \ | | static struct urcu_tls __tls_ ## name = { \ | |
| .init_mutex = PTHREAD_MUTEX_INITIALIZER,\ | | .init_mutex = PTHREAD_MUTEX_INITIALIZER,\ | |
| .init_done = 0, \ | | .init_done = 0, \ | |
| }; \ | | }; \ | |
| void *__tls_p; \ | | void *__tls_p; \ | |
| if (!__tls_ ## name.init_done) { \ | | if (!__tls_ ## name.init_done) { \ | |
| /* Mutex to protect concurrent init */ \ | | /* Mutex to protect concurrent init */ \ | |
| pthread_mutex_lock(&__tls_ ## name.init_mutex); \ | | pthread_mutex_lock(&__tls_ ## name.init_mutex); \ | |
| if (!__tls_ ## name.init_done) { \ | | if (!__tls_ ## name.init_done) { \ | |
| | | | |
| skipping to change at line 142 | | skipping to change at line 121 | |
| cmm_smp_rmb(); /* read init_done before getting key */ \ | | cmm_smp_rmb(); /* read init_done before getting key */ \ | |
| __tls_p = pthread_getspecific(__tls_ ## name.key); \ | | __tls_p = pthread_getspecific(__tls_ ## name.key); \ | |
| if (caa_unlikely(__tls_p == NULL)) { \ | | if (caa_unlikely(__tls_p == NULL)) { \ | |
| __tls_p = calloc(1, sizeof(type)); \ | | __tls_p = calloc(1, sizeof(type)); \ | |
| (void) pthread_setspecific(__tls_ ## name.key, \ | | (void) pthread_setspecific(__tls_ ## name.key, \ | |
| __tls_p); \ | | __tls_p); \ | |
| } \ | | } \ | |
| return __tls_p; \ | | return __tls_p; \ | |
| } | | } | |
| | | | |
|
| /* | | # define URCU_TLS(name) (*__tls_access_ ## name()) | |
| * Define with and without macro expansion to handle erroneous callers. | | | |
| * Trigger an abort() if the caller application uses the clashing symbol | | | |
| * if a weak symbol is overridden. | | | |
| */ | | | |
| # define __DEFINE_URCU_TLS_GLOBAL(type, name) \ | | | |
| DEFINE_URCU_TLS_1(type, name) \ | | | |
| int __urcu_tls_symbol_refcount_ ## name __attribute__((weak)); \ | | | |
| static __attribute__((constructor)) \ | | | |
| void __urcu_tls_inc_refcount_ ## name(void) \ | | | |
| { \ | | | |
| __urcu_tls_symbol_refcount_ ## name++; \ | | | |
| } \ | | | |
| type *__tls_access_ ## name(void) \ | | | |
| { \ | | | |
| if (__urcu_tls_symbol_refcount_ ## name > 1) { \ | | | |
| fprintf(stderr, "Error: Userspace RCU symbol clash f | | | |
| or multiple concurrent flavors. Please upgrade liburcu libraries and header | | | |
| s, then recompile your application.\n"); \ | | | |
| abort(); \ | | | |
| } \ | | | |
| return __URCU_TLS_CALL(name)(); \ | | | |
| } | | | |
| | | | |
| # define DEFINE_URCU_TLS(type, name) \ | | | |
| DEFINE_URCU_TLS_1(type, name) | | | |
| | | | |
| # define URCU_TLS_1(name) (*__tls_access2_ ## name()) | | | |
| | | | |
| # define URCU_TLS(name) URCU_TLS_1(name) | | | |
| | | | |
| #endif /* #else #ifndef CONFIG_RCU_TLS */ | | #endif /* #else #ifndef CONFIG_RCU_TLS */ | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_TLS_COMPAT_H */ | | #endif /* _URCU_TLS_COMPAT_H */ | |
| | | | |
End of changes. 7 change blocks. |
| 55 lines changed or deleted | | 5 lines changed or added | |
|
| urcu-pointer.h | | urcu-pointer.h | |
| | | | |
| skipping to change at line 37 | | skipping to change at line 37 | |
| */ | | */ | |
| | | | |
| #include <urcu/compiler.h> | | #include <urcu/compiler.h> | |
| #include <urcu/arch.h> | | #include <urcu/arch.h> | |
| #include <urcu/uatomic.h> | | #include <urcu/uatomic.h> | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
|
| #ifdef _LGPL_SOURCE | | #if defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS) | |
| | | | |
| #include <urcu/static/urcu-pointer.h> | | #include <urcu/static/urcu-pointer.h> | |
| | | | |
| /* | | /* | |
| * rcu_dereference(ptr) | | * rcu_dereference(ptr) | |
| * | | * | |
| * Fetch a RCU-protected pointer. Typically used to copy the variable ptr t
o a | | * Fetch a RCU-protected pointer. Typically used to copy the variable ptr t
o a | |
| * local variable. | | * local variable. | |
| */ | | */ | |
| #define rcu_dereference _rcu_dereference | | #define rcu_dereference _rcu_dereference | |
| | | | |
| skipping to change at line 65 | | skipping to change at line 65 | |
| * @ptr: address of the pointer to modify | | * @ptr: address of the pointer to modify | |
| * @new: new pointer value | | * @new: new pointer value | |
| * @old: old pointer value (expected) | | * @old: old pointer value (expected) | |
| * | | * | |
| * return: old pointer value | | * return: old pointer value | |
| */ | | */ | |
| #define rcu_cmpxchg_pointer _rcu_cmpxchg_pointer | | #define rcu_cmpxchg_pointer _rcu_cmpxchg_pointer | |
| #define rcu_xchg_pointer _rcu_xchg_pointer | | #define rcu_xchg_pointer _rcu_xchg_pointer | |
| #define rcu_set_pointer _rcu_set_pointer | | #define rcu_set_pointer _rcu_set_pointer | |
| | | | |
|
| #else /* !_LGPL_SOURCE */ | | #else /* !(defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS)) *
/ | |
| | | | |
| extern void *rcu_dereference_sym(void *p); | | extern void *rcu_dereference_sym(void *p); | |
| #define rcu_dereference(p)
\ | | #define rcu_dereference(p)
\ | |
|
| __extension__
\ | | | |
| ({
\ | | ({
\ | |
| __typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p
), \ | | __typeof__(p) _________p1 = URCU_FORCE_CAST(__typeof__(p
), \ | |
| rcu_dereference_sym(URCU_FORCE_CAST(void *, p)));
\ | | rcu_dereference_sym(URCU_FORCE_CAST(void *, p)));
\ | |
| (_________p1);
\ | | (_________p1);
\ | |
| }) | | }) | |
| | | | |
| extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); | | extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new); | |
| #define rcu_cmpxchg_pointer(p, old, _new)
\ | | #define rcu_cmpxchg_pointer(p, old, _new)
\ | |
|
| __extension__
\ | | | |
| ({
\ | | ({
\ | |
| __typeof__(*(p)) _________pold = (old);
\ | | __typeof__(*(p)) _________pold = (old);
\ | |
| __typeof__(*(p)) _________pnew = (_new);
\ | | __typeof__(*(p)) _________pnew = (_new);
\ | |
| __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(
p)), \ | | __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(
p)), \ | |
| rcu_cmpxchg_pointer_sym(URCU_FORCE_CAST(void **, p),
\ | | rcu_cmpxchg_pointer_sym(URCU_FORCE_CAST(void **, p),
\ | |
| _________pold,
\ | | _________pold,
\ | |
| _________pnew));
\ | | _________pnew));
\ | |
| (_________p1);
\ | | (_________p1);
\ | |
| }) | | }) | |
| | | | |
| extern void *rcu_xchg_pointer_sym(void **p, void *v); | | extern void *rcu_xchg_pointer_sym(void **p, void *v); | |
| #define rcu_xchg_pointer(p, v)
\ | | #define rcu_xchg_pointer(p, v)
\ | |
|
| __extension__
\ | | | |
| ({
\ | | ({
\ | |
| __typeof__(*(p)) _________pv = (v);
\ | | __typeof__(*(p)) _________pv = (v);
\ | |
| __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(
p)), \ | | __typeof__(*(p)) _________p1 = URCU_FORCE_CAST(__typeof__(*(
p)), \ | |
| rcu_xchg_pointer_sym(URCU_FORCE_CAST(void **, p),
\ | | rcu_xchg_pointer_sym(URCU_FORCE_CAST(void **, p),
\ | |
| _________pv));
\ | | _________pv));
\ | |
| (_________p1);
\ | | (_________p1);
\ | |
| }) | | }) | |
| | | | |
| /* | | /* | |
| * Note: rcu_set_pointer_sym returns @v because we don't want to break | | * Note: rcu_set_pointer_sym returns @v because we don't want to break | |
| | | | |
| skipping to change at line 114 | | skipping to change at line 111 | |
| * error. | | * error. | |
| */ | | */ | |
| extern void *rcu_set_pointer_sym(void **p, void *v); | | extern void *rcu_set_pointer_sym(void **p, void *v); | |
| #define rcu_set_pointer(p, v)
\ | | #define rcu_set_pointer(p, v)
\ | |
| do {
\ | | do {
\ | |
| __typeof__(*(p)) _________pv = (v);
\ | | __typeof__(*(p)) _________pv = (v);
\ | |
| (void) rcu_set_pointer_sym(URCU_FORCE_CAST(void **, p),
\ | | (void) rcu_set_pointer_sym(URCU_FORCE_CAST(void **, p),
\ | |
| _________pv);
\ | | _________pv);
\ | |
| } while (0) | | } while (0) | |
| | | | |
|
| #endif /* !_LGPL_SOURCE */ | | #endif /* !(defined(_LGPL_SOURCE) || defined(URCU_INLINE_SMALL_FUNCTIONS))
*/ | |
| | | | |
| /* | | /* | |
| * void rcu_assign_pointer(type *ptr, type *new) | | * void rcu_assign_pointer(type *ptr, type *new) | |
| * | | * | |
| * Same as rcu_set_pointer, but takes the pointer to assign to rather than
its | | * Same as rcu_set_pointer, but takes the pointer to assign to rather than
its | |
| * address as first parameter. Provided for compatibility with the Linux ke
rnel | | * address as first parameter. Provided for compatibility with the Linux ke
rnel | |
| * RCU semantic. | | * RCU semantic. | |
| */ | | */ | |
| #define rcu_assign_pointer(p, v) rcu_set_pointer((&p), (v)) | | #define rcu_assign_pointer(p, v) rcu_set_pointer((&p), (v)) | |
| | | | |
| | | | |
End of changes. 6 change blocks. |
| 6 lines changed or deleted | | 3 lines changed or added | |
|
| wfstack.h | | wfstack.h | |
| #ifndef _URCU_WFSTACK_H | | #ifndef _URCU_WFSTACK_H | |
| #define _URCU_WFSTACK_H | | #define _URCU_WFSTACK_H | |
| | | | |
| /* | | /* | |
|
| * wfstack.h | | * urcu/wfstack.h | |
| * | | * | |
|
| * Userspace RCU library - Stack with Wait-Free push, Blocking pop. | | * Userspace RCU library - Stack with wait-free push, blocking traversal. | |
| * | | * | |
|
| * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | | * Copyright 2010-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
| * | | * | |
| * This library is free software; you can redistribute it and/or | | * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | | * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | | * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | | * version 2.1 of the License, or (at your option) any later version. | |
| * | | * | |
| * This library is distributed in the hope that it will be useful, | | * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | | * Lesser General Public License for more details. | |
| * | | * | |
| * You should have received a copy of the GNU Lesser General Public | | * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | | * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA | |
| */ | | */ | |
| | | | |
| #include <pthread.h> | | #include <pthread.h> | |
| #include <assert.h> | | #include <assert.h> | |
|
| | | #include <stdbool.h> | |
| #include <urcu/compiler.h> | | #include <urcu/compiler.h> | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
|
| | | /* | |
| | | * Stack with wait-free push, blocking traversal. | |
| | | * | |
| | | * Stack implementing push, pop, pop_all operations, as well as iterator | |
| | | * on the stack head returned by pop_all. | |
| | | * | |
| | | * Wait-free operations: cds_wfs_push, __cds_wfs_pop_all, cds_wfs_empty, | |
| | | * cds_wfs_first. | |
| | | * Blocking operations: cds_wfs_pop, cds_wfs_pop_all, cds_wfs_next, | |
| | | * iteration on stack head returned by pop_all. | |
| | | * | |
| | | * Synchronization table: | |
| | | * | |
| | | * External synchronization techniques described in the API below is | |
| | | * required between pairs marked with "X". No external synchronization | |
| | | * required between pairs marked with "-". | |
| | | * | |
| | | * cds_wfs_push __cds_wfs_pop __cds_wfs_pop_all | |
| | | * cds_wfs_push - - - | |
| | | * __cds_wfs_pop - X X | |
| | | * __cds_wfs_pop_all - X - | |
| | | * | |
| | | * cds_wfs_pop and cds_wfs_pop_all use an internal mutex to provide | |
| | | * synchronization. | |
| | | */ | |
| | | | |
| | | #define CDS_WFS_WOULDBLOCK ((void *) -1UL) | |
| | | | |
| | | enum cds_wfs_state { | |
| | | CDS_WFS_STATE_LAST = (1U << 0), | |
| | | }; | |
| | | | |
| | | /* | |
| | | * struct cds_wfs_node is returned by __cds_wfs_pop, and also used as | |
| | | * iterator on stack. It is not safe to dereference the node next | |
| | | * pointer when returned by __cds_wfs_pop_blocking. | |
| | | */ | |
| struct cds_wfs_node { | | struct cds_wfs_node { | |
| struct cds_wfs_node *next; | | struct cds_wfs_node *next; | |
| }; | | }; | |
| | | | |
|
| | | /* | |
| | | * struct cds_wfs_head is returned by __cds_wfs_pop_all, and can be used | |
| | | * to begin iteration on the stack. "node" needs to be the first field of | |
| | | * cds_wfs_head, so the end-of-stack pointer value can be used for both | |
| | | * types. | |
| | | */ | |
| | | struct cds_wfs_head { | |
| | | struct cds_wfs_node node; | |
| | | }; | |
| | | | |
| struct cds_wfs_stack { | | struct cds_wfs_stack { | |
|
| struct cds_wfs_node *head; | | struct cds_wfs_head *head; | |
| pthread_mutex_t lock; | | pthread_mutex_t lock; | |
| }; | | }; | |
| | | | |
| #ifdef _LGPL_SOURCE | | #ifdef _LGPL_SOURCE | |
| | | | |
| #include <urcu/static/wfstack.h> | | #include <urcu/static/wfstack.h> | |
| | | | |
| #define cds_wfs_node_init _cds_wfs_node_init | | #define cds_wfs_node_init _cds_wfs_node_init | |
|
| #define cds_wfs_init _cds_wfs_init | | #define cds_wfs_init _cds_wfs_init | |
| #define cds_wfs_push _cds_wfs_push | | #define cds_wfs_empty _cds_wfs_empty | |
| #define __cds_wfs_pop_blocking ___cds_wfs_pop_blocking | | #define cds_wfs_push _cds_wfs_push | |
| #define cds_wfs_pop_blocking _cds_wfs_pop_blocking | | | |
| | | /* Locking performed internally */ | |
| | | #define cds_wfs_pop_blocking _cds_wfs_pop_blocking | |
| | | #define cds_wfs_pop_with_state_blocking _cds_wfs_pop_with_state_bloc | |
| | | king | |
| | | #define cds_wfs_pop_all_blocking _cds_wfs_pop_all_blocking | |
| | | | |
| | | /* | |
| | | * For iteration on cds_wfs_head returned by __cds_wfs_pop_all or | |
| | | * cds_wfs_pop_all_blocking. | |
| | | */ | |
| | | #define cds_wfs_first _cds_wfs_first | |
| | | #define cds_wfs_next_blocking _cds_wfs_next_blocking | |
| | | #define cds_wfs_next_nonblocking _cds_wfs_next_nonblocking | |
| | | | |
| | | /* Pop locking with internal mutex */ | |
| | | #define cds_wfs_pop_lock _cds_wfs_pop_lock | |
| | | #define cds_wfs_pop_unlock _cds_wfs_pop_unlock | |
| | | | |
| | | /* Synchronization ensured by the caller. See synchronization table. */ | |
| | | #define __cds_wfs_pop_blocking ___cds_wfs_pop_blocking | |
| | | #define __cds_wfs_pop_with_state_blocking \ | |
| | | ___cds_wfs_pop_with_state_blocking | |
| | | #define __cds_wfs_pop_nonblocking ___cds_wfs_pop_nonblocking | |
| | | #define __cds_wfs_pop_with_state_nonblocking \ | |
| | | ___cds_wfs_pop_with_state_nonblockin | |
| | | g | |
| | | #define __cds_wfs_pop_all ___cds_wfs_pop_all | |
| | | | |
| #else /* !_LGPL_SOURCE */ | | #else /* !_LGPL_SOURCE */ | |
| | | | |
|
| | | /* | |
| | | * cds_wfs_node_init: initialize wait-free stack node. | |
| | | */ | |
| extern void cds_wfs_node_init(struct cds_wfs_node *node); | | extern void cds_wfs_node_init(struct cds_wfs_node *node); | |
|
| | | | |
| | | /* | |
| | | * cds_wfs_init: initialize wait-free stack. | |
| | | */ | |
| extern void cds_wfs_init(struct cds_wfs_stack *s); | | extern void cds_wfs_init(struct cds_wfs_stack *s); | |
|
| | | | |
| | | /* | |
| | | * cds_wfs_empty: return whether wait-free stack is empty. | |
| | | * | |
| | | * No memory barrier is issued. No mutual exclusion is required. | |
| | | */ | |
| | | extern bool cds_wfs_empty(struct cds_wfs_stack *s); | |
| | | | |
| | | /* | |
| | | * cds_wfs_push: push a node into the stack. | |
| | | * | |
| | | * Issues a full memory barrier before push. No mutual exclusion is | |
| | | * required. | |
| | | * | |
| | | * Returns 0 if the stack was empty prior to adding the node. | |
| | | * Returns non-zero otherwise. | |
| | | */ | |
| extern int cds_wfs_push(struct cds_wfs_stack *s, struct cds_wfs_node *node)
; | | extern int cds_wfs_push(struct cds_wfs_stack *s, struct cds_wfs_node *node)
; | |
|
| /* __cds_wfs_pop_blocking: caller ensures mutual exclusion between pops */ | | | |
| extern struct cds_wfs_node *__cds_wfs_pop_blocking(struct cds_wfs_stack *s) | | /* | |
| ; | | * cds_wfs_pop_blocking: pop a node from the stack. | |
| | | * | |
| | | * Calls __cds_wfs_pop_blocking with an internal pop mutex held. | |
| | | */ | |
| extern struct cds_wfs_node *cds_wfs_pop_blocking(struct cds_wfs_stack *s); | | extern struct cds_wfs_node *cds_wfs_pop_blocking(struct cds_wfs_stack *s); | |
| | | | |
|
| | | /* | |
| | | * cds_wfs_pop_with_state_blocking: pop a node from the stack, with state. | |
| | | * | |
| | | * Same as cds_wfs_pop_blocking, but stores whether the stack was | |
| | | * empty into state (CDS_WFS_STATE_LAST). | |
| | | */ | |
| | | extern struct cds_wfs_node * | |
| | | cds_wfs_pop_with_state_blocking(struct cds_wfs_stack *s, int *state) | |
| | | ; | |
| | | | |
| | | /* | |
| | | * cds_wfs_pop_all_blocking: pop all nodes from a stack. | |
| | | * | |
| | | * Calls __cds_wfs_pop_all with an internal pop mutex held. | |
| | | */ | |
| | | extern struct cds_wfs_head *cds_wfs_pop_all_blocking(struct cds_wfs_stack * | |
| | | s); | |
| | | | |
| | | /* | |
| | | * cds_wfs_first: get first node of a popped stack. | |
| | | * | |
| | | * Content written into the node before enqueue is guaranteed to be | |
| | | * consistent, but no other memory ordering is ensured. | |
| | | * | |
| | | * Used by for-like iteration macros in urcu/wfstack.h: | |
| | | * cds_wfs_for_each_blocking() | |
| | | * cds_wfs_for_each_blocking_safe() | |
| | | * | |
| | | * Returns NULL if popped stack is empty, top stack node otherwise. | |
| | | */ | |
| | | extern struct cds_wfs_node *cds_wfs_first(struct cds_wfs_head *head); | |
| | | | |
| | | /* | |
| | | * cds_wfs_next_blocking: get next node of a popped stack. | |
| | | * | |
| | | * Content written into the node before enqueue is guaranteed to be | |
| | | * consistent, but no other memory ordering is ensured. | |
| | | * | |
| | | * Used by for-like iteration macros in urcu/wfstack.h: | |
| | | * cds_wfs_for_each_blocking() | |
| | | * cds_wfs_for_each_blocking_safe() | |
| | | * | |
| | | * Returns NULL if reached end of popped stack, non-NULL next stack | |
| | | * node otherwise. | |
| | | */ | |
| | | extern struct cds_wfs_node *cds_wfs_next_blocking(struct cds_wfs_node *node | |
| | | ); | |
| | | | |
| | | /* | |
| | | * cds_wfs_next_nonblocking: get next node of a popped stack. | |
| | | * | |
| | | * Same as cds_wfs_next_blocking, but returns CDS_WFS_WOULDBLOCK if it | |
| | | * needs to block. | |
| | | */ | |
| | | extern struct cds_wfs_node *cds_wfs_next_nonblocking(struct cds_wfs_node *n | |
| | | ode); | |
| | | | |
| | | /* | |
| | | * cds_wfs_pop_lock: lock stack pop-protection mutex. | |
| | | */ | |
| | | extern void cds_wfs_pop_lock(struct cds_wfs_stack *s); | |
| | | | |
| | | /* | |
| | | * cds_wfs_pop_unlock: unlock stack pop-protection mutex. | |
| | | */ | |
| | | extern void cds_wfs_pop_unlock(struct cds_wfs_stack *s); | |
| | | | |
| | | /* | |
| | | * __cds_wfs_pop_blocking: pop a node from the stack. | |
| | | * | |
| | | * Returns NULL if stack is empty. | |
| | | * | |
| | | * __cds_wfs_pop_blocking needs to be synchronized using one of the | |
| | | * following techniques: | |
| | | * | |
| | | * 1) Calling __cds_wfs_pop_blocking under rcu read lock critical | |
| | | * section. The caller must wait for a grace period to pass before | |
| | | * freeing the returned node or modifying the cds_wfs_node structure. | |
| | | * 2) Using mutual exclusion (e.g. mutexes) to protect | |
| | | * __cds_wfs_pop_blocking and __cds_wfs_pop_all callers. | |
| | | * 3) Ensuring that only ONE thread can call __cds_wfs_pop_blocking() | |
| | | * and __cds_wfs_pop_all(). (multi-provider/single-consumer scheme). | |
| | | */ | |
| | | extern struct cds_wfs_node *__cds_wfs_pop_blocking(struct cds_wfs_stack *s) | |
| | | ; | |
| | | | |
| | | /* | |
| | | * __cds_wfs_pop_with_state_blocking: pop a node from the stack, with state | |
| | | . | |
| | | * | |
| | | * Same as __cds_wfs_pop_blocking, but stores whether the stack was | |
| | | * empty into state (CDS_WFS_STATE_LAST). | |
| | | */ | |
| | | extern struct cds_wfs_node * | |
| | | __cds_wfs_pop_with_state_blocking(struct cds_wfs_stack *s, int *stat | |
| | | e); | |
| | | | |
| | | /* | |
| | | * __cds_wfs_pop_nonblocking: pop a node from the stack. | |
| | | * | |
| | | * Same as __cds_wfs_pop_blocking, but returns CDS_WFS_WOULDBLOCK if | |
| | | * it needs to block. | |
| | | */ | |
| | | extern struct cds_wfs_node *__cds_wfs_pop_nonblocking(struct cds_wfs_stack | |
| | | *s); | |
| | | | |
| | | /* | |
| | | * __cds_wfs_pop_with_state_nonblocking: pop a node from the stack, with st | |
| | | ate. | |
| | | * | |
| | | * Same as __cds_wfs_pop_nonblocking, but stores whether the stack was | |
| | | * empty into state (CDS_WFS_STATE_LAST). | |
| | | */ | |
| | | extern struct cds_wfs_node * | |
| | | __cds_wfs_pop_with_state_nonblocking(struct cds_wfs_stack *s, | |
| | | int *state); | |
| | | | |
| | | /* | |
| | | * __cds_wfs_pop_all: pop all nodes from a stack. | |
| | | * | |
| | | * __cds_wfs_pop_all does not require any synchronization with other | |
| | | * push, nor with other __cds_wfs_pop_all, but requires synchronization | |
| | | * matching the technique used to synchronize __cds_wfs_pop_blocking: | |
| | | * | |
| | | * 1) If __cds_wfs_pop_blocking is called under rcu read lock critical | |
| | | * section, both __cds_wfs_pop_blocking and cds_wfs_pop_all callers | |
| | | * must wait for a grace period to pass before freeing the returned | |
| | | * node or modifying the cds_wfs_node structure. However, no RCU | |
| | | * read-side critical section is needed around __cds_wfs_pop_all. | |
| | | * 2) Using mutual exclusion (e.g. mutexes) to protect | |
| | | * __cds_wfs_pop_blocking and __cds_wfs_pop_all callers. | |
| | | * 3) Ensuring that only ONE thread can call __cds_wfs_pop_blocking() | |
| | | * and __cds_wfs_pop_all(). (multi-provider/single-consumer scheme). | |
| | | */ | |
| | | extern struct cds_wfs_head *__cds_wfs_pop_all(struct cds_wfs_stack *s); | |
| | | | |
| #endif /* !_LGPL_SOURCE */ | | #endif /* !_LGPL_SOURCE */ | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
|
| | | /* | |
| | | * cds_wfs_for_each_blocking: Iterate over all nodes returned by | |
| | | * __cds_wfs_pop_all(). | |
| | | * @head: head of the queue (struct cds_wfs_head pointer). | |
| | | * @node: iterator (struct cds_wfs_node pointer). | |
| | | * | |
| | | * Content written into each node before enqueue is guaranteed to be | |
| | | * consistent, but no other memory ordering is ensured. | |
| | | */ | |
| | | #define cds_wfs_for_each_blocking(head, node) \ | |
| | | for (node = cds_wfs_first(head); \ | |
| | | node != NULL; \ | |
| | | node = cds_wfs_next_blocking(node)) | |
| | | | |
| | | /* | |
| | | * cds_wfs_for_each_blocking_safe: Iterate over all nodes returned by | |
| | | * __cds_wfs_pop_all(). Safe against deletion. | |
| | | * @head: head of the queue (struct cds_wfs_head pointer). | |
| | | * @node: iterator (struct cds_wfs_node pointer). | |
| | | * @n: struct cds_wfs_node pointer holding the next pointer (used | |
| | | * internally). | |
| | | * | |
| | | * Content written into each node before enqueue is guaranteed to be | |
| | | * consistent, but no other memory ordering is ensured. | |
| | | */ | |
| | | #define cds_wfs_for_each_blocking_safe(head, node, n) \ | |
| | | for (node = cds_wfs_first(head), \ | |
| | | n = (node ? cds_wfs_next_blocking(node) : NULL); \ | |
| | | node != NULL; \ | |
| | | node = n, n = (node ? cds_wfs_next_blocking(node) : NULL)) | |
| | | | |
| #endif /* _URCU_WFSTACK_H */ | | #endif /* _URCU_WFSTACK_H */ | |
| | | | |
End of changes. 14 change blocks. |
| 11 lines changed or deleted | | 280 lines changed or added | |
|