-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 121864 b: refs/heads/master c: bbaffac h: refs/heads/master v: v3
- Loading branch information
Eric Dumazet
authored and
David S. Miller
committed
Nov 17, 2008
1 parent
25867a2
commit bfe0e31
Showing
3 changed files
with
205 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: e8b2dfe9b4501ed0047459b2756ba26e5a940a69 | ||
refs/heads/master: bbaffaca4810de1a25e32ecaf836eeaacc7a3d11 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#ifndef _LINUX_LIST_NULLS_H | ||
#define _LINUX_LIST_NULLS_H | ||
|
||
/* | ||
* Special version of lists, where end of list is not a NULL pointer, | ||
* but a 'nulls' marker, which can have many different values. | ||
* (up to 2^31 different values guaranteed on all platforms) | ||
* | ||
* In the standard hlist, termination of a list is the NULL pointer. | ||
* In this special 'nulls' variant, we use the fact that objects stored in | ||
* a list are aligned on a word (4 or 8 bytes alignment). | ||
* We therefore use the last significant bit of 'ptr' : | ||
* Set to 1 : This is a 'nulls' end-of-list marker (ptr >> 1) | ||
* Set to 0 : This is a pointer to some object (ptr) | ||
*/ | ||
|
||
struct hlist_nulls_head { | ||
struct hlist_nulls_node *first; | ||
}; | ||
|
||
struct hlist_nulls_node { | ||
struct hlist_nulls_node *next, **pprev; | ||
}; | ||
#define INIT_HLIST_NULLS_HEAD(ptr, nulls) \ | ||
((ptr)->first = (struct hlist_nulls_node *) (1UL | (((long)nulls) << 1))) | ||
|
||
#define hlist_nulls_entry(ptr, type, member) container_of(ptr,type,member) | ||
/** | ||
* ptr_is_a_nulls - Test if a ptr is a nulls | ||
* @ptr: ptr to be tested | ||
* | ||
*/ | ||
static inline int is_a_nulls(const struct hlist_nulls_node *ptr) | ||
{ | ||
return ((unsigned long)ptr & 1); | ||
} | ||
|
||
/** | ||
* get_nulls_value - Get the 'nulls' value of the end of chain | ||
* @ptr: end of chain | ||
* | ||
* Should be called only if is_a_nulls(ptr); | ||
*/ | ||
static inline unsigned long get_nulls_value(const struct hlist_nulls_node *ptr) | ||
{ | ||
return ((unsigned long)ptr) >> 1; | ||
} | ||
|
||
static inline int hlist_nulls_unhashed(const struct hlist_nulls_node *h) | ||
{ | ||
return !h->pprev; | ||
} | ||
|
||
static inline int hlist_nulls_empty(const struct hlist_nulls_head *h) | ||
{ | ||
return is_a_nulls(h->first); | ||
} | ||
|
||
static inline void __hlist_nulls_del(struct hlist_nulls_node *n) | ||
{ | ||
struct hlist_nulls_node *next = n->next; | ||
struct hlist_nulls_node **pprev = n->pprev; | ||
*pprev = next; | ||
if (!is_a_nulls(next)) | ||
next->pprev = pprev; | ||
} | ||
|
||
/** | ||
* hlist_nulls_for_each_entry - iterate over list of given type | ||
* @tpos: the type * to use as a loop cursor. | ||
* @pos: the &struct hlist_node to use as a loop cursor. | ||
* @head: the head for your list. | ||
* @member: the name of the hlist_node within the struct. | ||
* | ||
*/ | ||
#define hlist_nulls_for_each_entry(tpos, pos, head, member) \ | ||
for (pos = (head)->first; \ | ||
(!is_a_nulls(pos)) && \ | ||
({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \ | ||
pos = pos->next) | ||
|
||
/** | ||
* hlist_nulls_for_each_entry_from - iterate over a hlist continuing from current point | ||
* @tpos: the type * to use as a loop cursor. | ||
* @pos: the &struct hlist_node to use as a loop cursor. | ||
* @member: the name of the hlist_node within the struct. | ||
* | ||
*/ | ||
#define hlist_nulls_for_each_entry_from(tpos, pos, member) \ | ||
for (; (!is_a_nulls(pos)) && \ | ||
({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \ | ||
pos = pos->next) | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#ifndef _LINUX_RCULIST_NULLS_H | ||
#define _LINUX_RCULIST_NULLS_H | ||
|
||
#ifdef __KERNEL__ | ||
|
||
/* | ||
* RCU-protected list version | ||
*/ | ||
#include <linux/list_nulls.h> | ||
#include <linux/rcupdate.h> | ||
|
||
/** | ||
* hlist_nulls_del_init_rcu - deletes entry from hash list with re-initialization | ||
* @n: the element to delete from the hash list. | ||
* | ||
* Note: hlist_nulls_unhashed() on the node return true after this. It is | ||
* useful for RCU based read lockfree traversal if the writer side | ||
* must know if the list entry is still hashed or already unhashed. | ||
* | ||
* In particular, it means that we can not poison the forward pointers | ||
* that may still be used for walking the hash list and we can only | ||
* zero the pprev pointer so list_unhashed() will return true after | ||
* this. | ||
* | ||
* The caller must take whatever precautions are necessary (such as | ||
* holding appropriate locks) to avoid racing with another | ||
* list-mutation primitive, such as hlist_nulls_add_head_rcu() or | ||
* hlist_nulls_del_rcu(), running on this same list. However, it is | ||
* perfectly legal to run concurrently with the _rcu list-traversal | ||
* primitives, such as hlist_nulls_for_each_entry_rcu(). | ||
*/ | ||
static inline void hlist_nulls_del_init_rcu(struct hlist_nulls_node *n) | ||
{ | ||
if (!hlist_nulls_unhashed(n)) { | ||
__hlist_nulls_del(n); | ||
n->pprev = NULL; | ||
} | ||
} | ||
|
||
/** | ||
* hlist_nulls_del_rcu - deletes entry from hash list without re-initialization | ||
* @n: the element to delete from the hash list. | ||
* | ||
* Note: hlist_nulls_unhashed() on entry does not return true after this, | ||
* the entry is in an undefined state. It is useful for RCU based | ||
* lockfree traversal. | ||
* | ||
* In particular, it means that we can not poison the forward | ||
* pointers that may still be used for walking the hash list. | ||
* | ||
* The caller must take whatever precautions are necessary | ||
* (such as holding appropriate locks) to avoid racing | ||
* with another list-mutation primitive, such as hlist_nulls_add_head_rcu() | ||
* or hlist_nulls_del_rcu(), running on this same list. | ||
* However, it is perfectly legal to run concurrently with | ||
* the _rcu list-traversal primitives, such as | ||
* hlist_nulls_for_each_entry(). | ||
*/ | ||
static inline void hlist_nulls_del_rcu(struct hlist_nulls_node *n) | ||
{ | ||
__hlist_nulls_del(n); | ||
n->pprev = LIST_POISON2; | ||
} | ||
|
||
/** | ||
* hlist_nulls_add_head_rcu | ||
* @n: the element to add to the hash list. | ||
* @h: the list to add to. | ||
* | ||
* Description: | ||
* Adds the specified element to the specified hlist_nulls, | ||
* while permitting racing traversals. | ||
* | ||
* The caller must take whatever precautions are necessary | ||
* (such as holding appropriate locks) to avoid racing | ||
* with another list-mutation primitive, such as hlist_nulls_add_head_rcu() | ||
* or hlist_nulls_del_rcu(), running on this same list. | ||
* However, it is perfectly legal to run concurrently with | ||
* the _rcu list-traversal primitives, such as | ||
* hlist_nulls_for_each_entry_rcu(), used to prevent memory-consistency | ||
* problems on Alpha CPUs. Regardless of the type of CPU, the | ||
* list-traversal primitive must be guarded by rcu_read_lock(). | ||
*/ | ||
static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n, | ||
struct hlist_nulls_head *h) | ||
{ | ||
struct hlist_nulls_node *first = h->first; | ||
|
||
n->next = first; | ||
n->pprev = &h->first; | ||
rcu_assign_pointer(h->first, n); | ||
if (!is_a_nulls(first)) | ||
first->pprev = &n->next; | ||
} | ||
/** | ||
* hlist_nulls_for_each_entry_rcu - iterate over rcu list of given type | ||
* @tpos: the type * to use as a loop cursor. | ||
* @pos: the &struct hlist_nulls_node to use as a loop cursor. | ||
* @head: the head for your list. | ||
* @member: the name of the hlist_nulls_node within the struct. | ||
* | ||
*/ | ||
#define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \ | ||
for (pos = rcu_dereference((head)->first); \ | ||
(!is_a_nulls(pos)) && \ | ||
({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1; }); \ | ||
pos = rcu_dereference(pos->next)) | ||
|
||
#endif | ||
#endif |