~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/lockref.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include <linux/export.h>
  3 #include <linux/lockref.h>
  4 
  5 #if USE_CMPXCHG_LOCKREF
  6 
  7 /*
  8  * Note that the "cmpxchg()" reloads the "old" value for the
  9  * failure case.
 10  */
 11 #define CMPXCHG_LOOP(CODE, SUCCESS) do {                                        \
 12         int retry = 100;                                                        \
 13         struct lockref old;                                                     \
 14         BUILD_BUG_ON(sizeof(old) != 8);                                         \
 15         old.lock_count = READ_ONCE(lockref->lock_count);                        \
 16         while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) {     \
 17                 struct lockref new = old;                                       \
 18                 CODE                                                            \
 19                 if (likely(try_cmpxchg64_relaxed(&lockref->lock_count,          \
 20                                                  &old.lock_count,               \
 21                                                  new.lock_count))) {            \
 22                         SUCCESS;                                                \
 23                 }                                                               \
 24                 if (!--retry)                                                   \
 25                         break;                                                  \
 26         }                                                                       \
 27 } while (0)
 28 
 29 #else
 30 
 31 #define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0)
 32 
 33 #endif
 34 
 35 /**
 36  * lockref_get - Increments reference count unconditionally
 37  * @lockref: pointer to lockref structure
 38  *
 39  * This operation is only valid if you already hold a reference
 40  * to the object, so you know the count cannot be zero.
 41  */
 42 void lockref_get(struct lockref *lockref)
 43 {
 44         CMPXCHG_LOOP(
 45                 new.count++;
 46         ,
 47                 return;
 48         );
 49 
 50         spin_lock(&lockref->lock);
 51         lockref->count++;
 52         spin_unlock(&lockref->lock);
 53 }
 54 EXPORT_SYMBOL(lockref_get);
 55 
 56 /**
 57  * lockref_get_not_zero - Increments count unless the count is 0 or dead
 58  * @lockref: pointer to lockref structure
 59  * Return: 1 if count updated successfully or 0 if count was zero
 60  */
 61 int lockref_get_not_zero(struct lockref *lockref)
 62 {
 63         int retval;
 64 
 65         CMPXCHG_LOOP(
 66                 new.count++;
 67                 if (old.count <= 0)
 68                         return 0;
 69         ,
 70                 return 1;
 71         );
 72 
 73         spin_lock(&lockref->lock);
 74         retval = 0;
 75         if (lockref->count > 0) {
 76                 lockref->count++;
 77                 retval = 1;
 78         }
 79         spin_unlock(&lockref->lock);
 80         return retval;
 81 }
 82 EXPORT_SYMBOL(lockref_get_not_zero);
 83 
 84 /**
 85  * lockref_put_not_zero - Decrements count unless count <= 1 before decrement
 86  * @lockref: pointer to lockref structure
 87  * Return: 1 if count updated successfully or 0 if count would become zero
 88  */
 89 int lockref_put_not_zero(struct lockref *lockref)
 90 {
 91         int retval;
 92 
 93         CMPXCHG_LOOP(
 94                 new.count--;
 95                 if (old.count <= 1)
 96                         return 0;
 97         ,
 98                 return 1;
 99         );
100 
101         spin_lock(&lockref->lock);
102         retval = 0;
103         if (lockref->count > 1) {
104                 lockref->count--;
105                 retval = 1;
106         }
107         spin_unlock(&lockref->lock);
108         return retval;
109 }
110 EXPORT_SYMBOL(lockref_put_not_zero);
111 
112 /**
113  * lockref_put_return - Decrement reference count if possible
114  * @lockref: pointer to lockref structure
115  *
116  * Decrement the reference count and return the new value.
117  * If the lockref was dead or locked, return an error.
118  */
119 int lockref_put_return(struct lockref *lockref)
120 {
121         CMPXCHG_LOOP(
122                 new.count--;
123                 if (old.count <= 0)
124                         return -1;
125         ,
126                 return new.count;
127         );
128         return -1;
129 }
130 EXPORT_SYMBOL(lockref_put_return);
131 
132 /**
133  * lockref_put_or_lock - decrements count unless count <= 1 before decrement
134  * @lockref: pointer to lockref structure
135  * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken
136  */
137 int lockref_put_or_lock(struct lockref *lockref)
138 {
139         CMPXCHG_LOOP(
140                 new.count--;
141                 if (old.count <= 1)
142                         break;
143         ,
144                 return 1;
145         );
146 
147         spin_lock(&lockref->lock);
148         if (lockref->count <= 1)
149                 return 0;
150         lockref->count--;
151         spin_unlock(&lockref->lock);
152         return 1;
153 }
154 EXPORT_SYMBOL(lockref_put_or_lock);
155 
156 /**
157  * lockref_mark_dead - mark lockref dead
158  * @lockref: pointer to lockref structure
159  */
160 void lockref_mark_dead(struct lockref *lockref)
161 {
162         assert_spin_locked(&lockref->lock);
163         lockref->count = -128;
164 }
165 EXPORT_SYMBOL(lockref_mark_dead);
166 
167 /**
168  * lockref_get_not_dead - Increments count unless the ref is dead
169  * @lockref: pointer to lockref structure
170  * Return: 1 if count updated successfully or 0 if lockref was dead
171  */
172 int lockref_get_not_dead(struct lockref *lockref)
173 {
174         int retval;
175 
176         CMPXCHG_LOOP(
177                 new.count++;
178                 if (old.count < 0)
179                         return 0;
180         ,
181                 return 1;
182         );
183 
184         spin_lock(&lockref->lock);
185         retval = 0;
186         if (lockref->count >= 0) {
187                 lockref->count++;
188                 retval = 1;
189         }
190         spin_unlock(&lockref->lock);
191         return retval;
192 }
193 EXPORT_SYMBOL(lockref_get_not_dead);
194 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php