Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */ 2 : : /* rwsem.h: R/W semaphores, public interface 3 : : * 4 : : * Written by David Howells (dhowells@redhat.com). 5 : : * Derived from asm-i386/semaphore.h 6 : : */ 7 : : 8 : : #ifndef _LINUX_RWSEM_H 9 : : #define _LINUX_RWSEM_H 10 : : 11 : : #include <linux/linkage.h> 12 : : 13 : : #include <linux/types.h> 14 : : #include <linux/kernel.h> 15 : : #include <linux/list.h> 16 : : #include <linux/spinlock.h> 17 : : #include <linux/atomic.h> 18 : : #include <linux/err.h> 19 : : #ifdef CONFIG_RWSEM_SPIN_ON_OWNER 20 : : #include <linux/osq_lock.h> 21 : : #endif 22 : : 23 : : /* 24 : : * For an uncontended rwsem, count and owner are the only fields a task 25 : : * needs to touch when acquiring the rwsem. So they are put next to each 26 : : * other to increase the chance that they will share the same cacheline. 27 : : * 28 : : * In a contended rwsem, the owner is likely the most frequently accessed 29 : : * field in the structure as the optimistic waiter that holds the osq lock 30 : : * will spin on owner. For an embedded rwsem, other hot fields in the 31 : : * containing structure should be moved further away from the rwsem to 32 : : * reduce the chance that they will share the same cacheline causing 33 : : * cacheline bouncing problem. 34 : : */ 35 : : struct rw_semaphore { 36 : : atomic_long_t count; 37 : : /* 38 : : * Write owner or one of the read owners as well flags regarding 39 : : * the current state of the rwsem. Can be used as a speculative 40 : : * check to see if the write owner is running on the cpu. 41 : : */ 42 : : atomic_long_t owner; 43 : : #ifdef CONFIG_RWSEM_SPIN_ON_OWNER 44 : : struct optimistic_spin_queue osq; /* spinner MCS lock */ 45 : : #endif 46 : : raw_spinlock_t wait_lock; 47 : : struct list_head wait_list; 48 : : #ifdef CONFIG_DEBUG_RWSEMS 49 : : void *magic; 50 : : #endif 51 : : #ifdef CONFIG_DEBUG_LOCK_ALLOC 52 : : struct lockdep_map dep_map; 53 : : #endif 54 : : }; 55 : : 56 : : /* 57 : : * Setting all bits of the owner field except bit 0 will indicate 58 : : * that the rwsem is writer-owned with an unknown owner. 59 : : */ 60 : : #define RWSEM_OWNER_UNKNOWN (-2L) 61 : : 62 : : /* In all implementations count != 0 means locked */ 63 : : static inline int rwsem_is_locked(struct rw_semaphore *sem) 64 : : { 65 : 2882092 : return atomic_long_read(&sem->count) != 0; 66 : : } 67 : : 68 : : #define RWSEM_UNLOCKED_VALUE 0L 69 : : #define __RWSEM_INIT_COUNT(name) .count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE) 70 : : 71 : : /* Common initializer macros and functions */ 72 : : 73 : : #ifdef CONFIG_DEBUG_LOCK_ALLOC 74 : : # define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } 75 : : #else 76 : : # define __RWSEM_DEP_MAP_INIT(lockname) 77 : : #endif 78 : : 79 : : #ifdef CONFIG_DEBUG_RWSEMS 80 : : # define __DEBUG_RWSEM_INITIALIZER(lockname) , .magic = &lockname 81 : : #else 82 : : # define __DEBUG_RWSEM_INITIALIZER(lockname) 83 : : #endif 84 : : 85 : : #ifdef CONFIG_RWSEM_SPIN_ON_OWNER 86 : : #define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED 87 : : #else 88 : : #define __RWSEM_OPT_INIT(lockname) 89 : : #endif 90 : : 91 : : #define __RWSEM_INITIALIZER(name) \ 92 : : { __RWSEM_INIT_COUNT(name), \ 93 : : .owner = ATOMIC_LONG_INIT(0), \ 94 : : .wait_list = LIST_HEAD_INIT((name).wait_list), \ 95 : : .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \ 96 : : __RWSEM_OPT_INIT(name) \ 97 : : __DEBUG_RWSEM_INITIALIZER(name) \ 98 : : __RWSEM_DEP_MAP_INIT(name) } 99 : : 100 : : #define DECLARE_RWSEM(name) \ 101 : : struct rw_semaphore name = __RWSEM_INITIALIZER(name) 102 : : 103 : : extern void __init_rwsem(struct rw_semaphore *sem, const char *name, 104 : : struct lock_class_key *key); 105 : : 106 : : #define init_rwsem(sem) \ 107 : : do { \ 108 : : static struct lock_class_key __key; \ 109 : : \ 110 : : __init_rwsem((sem), #sem, &__key); \ 111 : : } while (0) 112 : : 113 : : /* 114 : : * This is the same regardless of which rwsem implementation that is being used. 115 : : * It is just a heuristic meant to be called by somebody alreadying holding the 116 : : * rwsem to see if somebody from an incompatible type is wanting access to the 117 : : * lock. 118 : : */ 119 : : static inline int rwsem_is_contended(struct rw_semaphore *sem) 120 : : { 121 : : return !list_empty(&sem->wait_list); 122 : : } 123 : : 124 : : /* 125 : : * lock for reading 126 : : */ 127 : : extern void down_read(struct rw_semaphore *sem); 128 : : extern int __must_check down_read_killable(struct rw_semaphore *sem); 129 : : 130 : : /* 131 : : * trylock for reading -- returns 1 if successful, 0 if contention 132 : : */ 133 : : extern int down_read_trylock(struct rw_semaphore *sem); 134 : : 135 : : /* 136 : : * lock for writing 137 : : */ 138 : : extern void down_write(struct rw_semaphore *sem); 139 : : extern int __must_check down_write_killable(struct rw_semaphore *sem); 140 : : 141 : : /* 142 : : * trylock for writing -- returns 1 if successful, 0 if contention 143 : : */ 144 : : extern int down_write_trylock(struct rw_semaphore *sem); 145 : : 146 : : /* 147 : : * release a read lock 148 : : */ 149 : : extern void up_read(struct rw_semaphore *sem); 150 : : 151 : : /* 152 : : * release a write lock 153 : : */ 154 : : extern void up_write(struct rw_semaphore *sem); 155 : : 156 : : /* 157 : : * downgrade write lock to read lock 158 : : */ 159 : : extern void downgrade_write(struct rw_semaphore *sem); 160 : : 161 : : #ifdef CONFIG_DEBUG_LOCK_ALLOC 162 : : /* 163 : : * nested locking. NOTE: rwsems are not allowed to recurse 164 : : * (which occurs if the same task tries to acquire the same 165 : : * lock instance multiple times), but multiple locks of the 166 : : * same lock class might be taken, if the order of the locks 167 : : * is always the same. This ordering rule can be expressed 168 : : * to lockdep via the _nested() APIs, but enumerating the 169 : : * subclasses that are used. (If the nesting relationship is 170 : : * static then another method for expressing nested locking is 171 : : * the explicit definition of lock class keys and the use of 172 : : * lockdep_set_class() at lock initialization time. 173 : : * See Documentation/locking/lockdep-design.rst for more details.) 174 : : */ 175 : : extern void down_read_nested(struct rw_semaphore *sem, int subclass); 176 : : extern void down_write_nested(struct rw_semaphore *sem, int subclass); 177 : : extern int down_write_killable_nested(struct rw_semaphore *sem, int subclass); 178 : : extern void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest_lock); 179 : : 180 : : # define down_write_nest_lock(sem, nest_lock) \ 181 : : do { \ 182 : : typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \ 183 : : _down_write_nest_lock(sem, &(nest_lock)->dep_map); \ 184 : : } while (0); 185 : : 186 : : /* 187 : : * Take/release a lock when not the owner will release it. 188 : : * 189 : : * [ This API should be avoided as much as possible - the 190 : : * proper abstraction for this case is completions. ] 191 : : */ 192 : : extern void down_read_non_owner(struct rw_semaphore *sem); 193 : : extern void up_read_non_owner(struct rw_semaphore *sem); 194 : : #else 195 : : # define down_read_nested(sem, subclass) down_read(sem) 196 : : # define down_write_nest_lock(sem, nest_lock) down_write(sem) 197 : : # define down_write_nested(sem, subclass) down_write(sem) 198 : : # define down_write_killable_nested(sem, subclass) down_write_killable(sem) 199 : : # define down_read_non_owner(sem) down_read(sem) 200 : : # define up_read_non_owner(sem) up_read(sem) 201 : : #endif 202 : : 203 : : #endif /* _LINUX_RWSEM_H */