LCOV - code coverage report
Current view: top level - include/linux - list_nulls.h (source / functions) Hit Total Coverage
Test: combined.info Lines: 2 24 8.3 %
Date: 2022-04-01 14:58:12 Functions: 0 0 -
Branches: 3 64 4.7 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: GPL-2.0 */
       2                 :            : #ifndef _LINUX_LIST_NULLS_H
       3                 :            : #define _LINUX_LIST_NULLS_H
       4                 :            : 
       5                 :            : #include <linux/poison.h>
       6                 :            : #include <linux/const.h>
       7                 :            : 
       8                 :            : /*
       9                 :            :  * Special version of lists, where end of list is not a NULL pointer,
      10                 :            :  * but a 'nulls' marker, which can have many different values.
      11                 :            :  * (up to 2^31 different values guaranteed on all platforms)
      12                 :            :  *
      13                 :            :  * In the standard hlist, termination of a list is the NULL pointer.
      14                 :            :  * In this special 'nulls' variant, we use the fact that objects stored in
      15                 :            :  * a list are aligned on a word (4 or 8 bytes alignment).
      16                 :            :  * We therefore use the last significant bit of 'ptr' :
      17                 :            :  * Set to 1 : This is a 'nulls' end-of-list marker (ptr >> 1)
      18                 :            :  * Set to 0 : This is a pointer to some object (ptr)
      19                 :            :  */
      20                 :            : 
      21                 :            : struct hlist_nulls_head {
      22                 :            :         struct hlist_nulls_node *first;
      23                 :            : };
      24                 :            : 
      25                 :            : struct hlist_nulls_node {
      26                 :            :         struct hlist_nulls_node *next, **pprev;
      27                 :            : };
      28                 :            : #define NULLS_MARKER(value) (1UL | (((long)value) << 1))
      29                 :            : #define INIT_HLIST_NULLS_HEAD(ptr, nulls) \
      30                 :            :         ((ptr)->first = (struct hlist_nulls_node *) NULLS_MARKER(nulls))
      31                 :            : 
      32                 :            : #define hlist_nulls_entry(ptr, type, member) container_of(ptr,type,member)
      33                 :            : 
      34                 :            : #define hlist_nulls_entry_safe(ptr, type, member) \
      35                 :            :         ({ typeof(ptr) ____ptr = (ptr); \
      36                 :            :            !is_a_nulls(____ptr) ? hlist_nulls_entry(____ptr, type, member) : NULL; \
      37                 :            :         })
      38                 :            : /**
      39                 :            :  * ptr_is_a_nulls - Test if a ptr is a nulls
      40                 :            :  * @ptr: ptr to be tested
      41                 :            :  *
      42                 :            :  */
      43                 :       4518 : static inline int is_a_nulls(const struct hlist_nulls_node *ptr)
      44                 :            : {
      45   [ -  -  -  -  :       4518 :         return ((unsigned long)ptr & 1);
          +  +  -  +  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  - ]
      46                 :            : }
      47                 :            : 
      48                 :            : /**
      49                 :            :  * get_nulls_value - Get the 'nulls' value of the end of chain
      50                 :            :  * @ptr: end of chain
      51                 :            :  *
      52                 :            :  * Should be called only if is_a_nulls(ptr);
      53                 :            :  */
      54                 :          0 : static inline unsigned long get_nulls_value(const struct hlist_nulls_node *ptr)
      55                 :            : {
      56   [ #  #  #  # ]:          0 :         return ((unsigned long)ptr) >> 1;
      57                 :            : }
      58                 :            : 
      59                 :            : /**
      60                 :            :  * hlist_nulls_unhashed - Has node been removed and reinitialized?
      61                 :            :  * @h: Node to be checked
      62                 :            :  *
      63                 :            :  * Not that not all removal functions will leave a node in unhashed state.
      64                 :            :  * For example, hlist_del_init_rcu() leaves the node in unhashed state,
      65                 :            :  * but hlist_nulls_del() does not.
      66                 :            :  */
      67                 :          0 : static inline int hlist_nulls_unhashed(const struct hlist_nulls_node *h)
      68                 :            : {
      69   [ #  #  #  # ]:          0 :         return !h->pprev;
      70                 :            : }
      71                 :            : 
      72                 :            : /**
      73                 :            :  * hlist_nulls_unhashed_lockless - Has node been removed and reinitialized?
      74                 :            :  * @h: Node to be checked
      75                 :            :  *
      76                 :            :  * Not that not all removal functions will leave a node in unhashed state.
      77                 :            :  * For example, hlist_del_init_rcu() leaves the node in unhashed state,
      78                 :            :  * but hlist_nulls_del() does not.  Unlike hlist_nulls_unhashed(), this
      79                 :            :  * function may be used locklessly.
      80                 :            :  */
      81                 :            : static inline int hlist_nulls_unhashed_lockless(const struct hlist_nulls_node *h)
      82                 :            : {
      83                 :            :         return !READ_ONCE(h->pprev);
      84                 :            : }
      85                 :            : 
      86                 :          0 : static inline int hlist_nulls_empty(const struct hlist_nulls_head *h)
      87                 :            : {
      88   [ #  #  #  # ]:          0 :         return is_a_nulls(READ_ONCE(h->first));
      89                 :            : }
      90                 :            : 
      91                 :          0 : static inline void hlist_nulls_add_head(struct hlist_nulls_node *n,
      92                 :            :                                         struct hlist_nulls_head *h)
      93                 :            : {
      94                 :          0 :         struct hlist_nulls_node *first = h->first;
      95                 :            : 
      96                 :          0 :         n->next = first;
      97   [ #  #  #  # ]:          0 :         WRITE_ONCE(n->pprev, &h->first);
      98                 :          0 :         h->first = n;
      99   [ #  #  #  # ]:          0 :         if (!is_a_nulls(first))
     100                 :          0 :                 WRITE_ONCE(first->pprev, &n->next);
     101                 :            : }
     102                 :            : 
     103                 :          0 : static inline void __hlist_nulls_del(struct hlist_nulls_node *n)
     104                 :            : {
     105                 :          0 :         struct hlist_nulls_node *next = n->next;
     106                 :          0 :         struct hlist_nulls_node **pprev = n->pprev;
     107                 :            : 
     108   [ #  #  #  #  :          0 :         WRITE_ONCE(*pprev, next);
                   #  # ]
     109   [ #  #  #  #  :          0 :         if (!is_a_nulls(next))
             #  #  #  # ]
     110                 :          0 :                 WRITE_ONCE(next->pprev, pprev);
     111                 :            : }
     112                 :            : 
     113                 :          0 : static inline void hlist_nulls_del(struct hlist_nulls_node *n)
     114                 :            : {
     115         [ #  # ]:          0 :         __hlist_nulls_del(n);
     116                 :          0 :         WRITE_ONCE(n->pprev, LIST_POISON2);
     117                 :            : }
     118                 :            : 
     119                 :            : /**
     120                 :            :  * hlist_nulls_for_each_entry   - iterate over list of given type
     121                 :            :  * @tpos:       the type * to use as a loop cursor.
     122                 :            :  * @pos:        the &struct hlist_node to use as a loop cursor.
     123                 :            :  * @head:       the head for your list.
     124                 :            :  * @member:     the name of the hlist_node within the struct.
     125                 :            :  *
     126                 :            :  */
     127                 :            : #define hlist_nulls_for_each_entry(tpos, pos, head, member)                    \
     128                 :            :         for (pos = (head)->first;                                           \
     129                 :            :              (!is_a_nulls(pos)) &&                                             \
     130                 :            :                 ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \
     131                 :            :              pos = pos->next)
     132                 :            : 
     133                 :            : /**
     134                 :            :  * hlist_nulls_for_each_entry_from - iterate over a hlist continuing from current point
     135                 :            :  * @tpos:       the type * to use as a loop cursor.
     136                 :            :  * @pos:        the &struct hlist_node to use as a loop cursor.
     137                 :            :  * @member:     the name of the hlist_node within the struct.
     138                 :            :  *
     139                 :            :  */
     140                 :            : #define hlist_nulls_for_each_entry_from(tpos, pos, member)      \
     141                 :            :         for (; (!is_a_nulls(pos)) &&                            \
     142                 :            :                 ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \
     143                 :            :              pos = pos->next)
     144                 :            : 
     145                 :            : #endif

Generated by: LCOV version 1.14