Blame view

include/linux/list_nulls.h 3.21 KB
bbaffaca4   Eric Dumazet   rcu: Introduce hl...
1
2
  #ifndef _LINUX_LIST_NULLS_H
  #define _LINUX_LIST_NULLS_H
a3449ded1   Ying Xue   list_nulls: fix m...
3
4
  #include <linux/poison.h>
  #include <linux/const.h>
bbaffaca4   Eric Dumazet   rcu: Introduce hl...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  /*
   * 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;
  };
f89bd6f87   Thomas Graf   rhashtable: Suppo...
25
  #define NULLS_MARKER(value) (1UL | (((long)value) << 1))
bbaffaca4   Eric Dumazet   rcu: Introduce hl...
26
  #define INIT_HLIST_NULLS_HEAD(ptr, nulls) \
f89bd6f87   Thomas Graf   rhashtable: Suppo...
27
  	((ptr)->first = (struct hlist_nulls_node *) NULLS_MARKER(nulls))
bbaffaca4   Eric Dumazet   rcu: Introduce hl...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  
  #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);
  }
d219dce76   Pablo Neira Ayuso   list_nulls: add h...
60
61
62
63
64
65
66
67
68
69
70
  static inline void hlist_nulls_add_head(struct hlist_nulls_node *n,
  					struct hlist_nulls_head *h)
  {
  	struct hlist_nulls_node *first = h->first;
  
  	n->next = first;
  	n->pprev = &h->first;
  	h->first = n;
  	if (!is_a_nulls(first))
  		first->pprev = &n->next;
  }
bbaffaca4   Eric Dumazet   rcu: Introduce hl...
71
72
73
74
  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;
7f5f873c6   Paul E. McKenney   rculist: Use WRIT...
75
76
  
  	WRITE_ONCE(*pprev, next);
bbaffaca4   Eric Dumazet   rcu: Introduce hl...
77
78
79
  	if (!is_a_nulls(next))
  		next->pprev = pprev;
  }
d219dce76   Pablo Neira Ayuso   list_nulls: add h...
80
81
82
83
84
  static inline void hlist_nulls_del(struct hlist_nulls_node *n)
  {
  	__hlist_nulls_del(n);
  	n->pprev = LIST_POISON2;
  }
bbaffaca4   Eric Dumazet   rcu: Introduce hl...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  /**
   * 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