]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - lib/lockref.c
Merge tag 'tty-3.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[karo-tx-linux.git] / lib / lockref.c
1 #include <linux/export.h>
2 #include <linux/lockref.h>
3
4 #ifdef CONFIG_CMPXCHG_LOCKREF
5
6 /*
7  * Note that the "cmpxchg()" reloads the "old" value for the
8  * failure case.
9  */
10 #define CMPXCHG_LOOP(CODE, SUCCESS) do {                                        \
11         struct lockref old;                                                     \
12         BUILD_BUG_ON(sizeof(old) != 8);                                         \
13         old.lock_count = ACCESS_ONCE(lockref->lock_count);                      \
14         while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) {     \
15                 struct lockref new = old, prev = old;                           \
16                 CODE                                                            \
17                 old.lock_count = cmpxchg(&lockref->lock_count,                  \
18                                          old.lock_count, new.lock_count);       \
19                 if (likely(old.lock_count == prev.lock_count)) {                \
20                         SUCCESS;                                                \
21                 }                                                               \
22         }                                                                       \
23 } while (0)
24
25 #else
26
27 #define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0)
28
29 #endif
30
31 /**
32  * lockref_get - Increments reference count unconditionally
33  * @lockcnt: pointer to lockref structure
34  *
35  * This operation is only valid if you already hold a reference
36  * to the object, so you know the count cannot be zero.
37  */
38 void lockref_get(struct lockref *lockref)
39 {
40         CMPXCHG_LOOP(
41                 new.count++;
42         ,
43                 return;
44         );
45
46         spin_lock(&lockref->lock);
47         lockref->count++;
48         spin_unlock(&lockref->lock);
49 }
50 EXPORT_SYMBOL(lockref_get);
51
52 /**
53  * lockref_get_not_zero - Increments count unless the count is 0
54  * @lockcnt: pointer to lockref structure
55  * Return: 1 if count updated successfully or 0 if count was zero
56  */
57 int lockref_get_not_zero(struct lockref *lockref)
58 {
59         int retval;
60
61         CMPXCHG_LOOP(
62                 new.count++;
63                 if (!old.count)
64                         return 0;
65         ,
66                 return 1;
67         );
68
69         spin_lock(&lockref->lock);
70         retval = 0;
71         if (lockref->count) {
72                 lockref->count++;
73                 retval = 1;
74         }
75         spin_unlock(&lockref->lock);
76         return retval;
77 }
78 EXPORT_SYMBOL(lockref_get_not_zero);
79
80 /**
81  * lockref_get_or_lock - Increments count unless the count is 0
82  * @lockcnt: pointer to lockref structure
83  * Return: 1 if count updated successfully or 0 if count was zero
84  * and we got the lock instead.
85  */
86 int lockref_get_or_lock(struct lockref *lockref)
87 {
88         CMPXCHG_LOOP(
89                 new.count++;
90                 if (!old.count)
91                         break;
92         ,
93                 return 1;
94         );
95
96         spin_lock(&lockref->lock);
97         if (!lockref->count)
98                 return 0;
99         lockref->count++;
100         spin_unlock(&lockref->lock);
101         return 1;
102 }
103 EXPORT_SYMBOL(lockref_get_or_lock);
104
105 /**
106  * lockref_put_or_lock - decrements count unless count <= 1 before decrement
107  * @lockcnt: pointer to lockref structure
108  * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken
109  */
110 int lockref_put_or_lock(struct lockref *lockref)
111 {
112         CMPXCHG_LOOP(
113                 new.count--;
114                 if (old.count <= 1)
115                         break;
116         ,
117                 return 1;
118         );
119
120         spin_lock(&lockref->lock);
121         if (lockref->count <= 1)
122                 return 0;
123         lockref->count--;
124         spin_unlock(&lockref->lock);
125         return 1;
126 }
127 EXPORT_SYMBOL(lockref_put_or_lock);