diff options
Diffstat (limited to 'include/linux/seqlock.h')
| -rw-r--r-- | include/linux/seqlock.h | 68 |
1 files changed, 63 insertions, 5 deletions
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h index 18299057402f..21a209336e79 100644 --- a/include/linux/seqlock.h +++ b/include/linux/seqlock.h | |||
| @@ -3,15 +3,21 @@ | |||
| 3 | /* | 3 | /* |
| 4 | * Reader/writer consistent mechanism without starving writers. This type of | 4 | * Reader/writer consistent mechanism without starving writers. This type of |
| 5 | * lock for data where the reader wants a consistent set of information | 5 | * lock for data where the reader wants a consistent set of information |
| 6 | * and is willing to retry if the information changes. Readers never | 6 | * and is willing to retry if the information changes. There are two types |
| 7 | * block but they may have to retry if a writer is in | 7 | * of readers: |
| 8 | * progress. Writers do not wait for readers. | 8 | * 1. Sequence readers which never block a writer but they may have to retry |
| 9 | * if a writer is in progress by detecting change in sequence number. | ||
| 10 | * Writers do not wait for a sequence reader. | ||
| 11 | * 2. Locking readers which will wait if a writer or another locking reader | ||
| 12 | * is in progress. A locking reader in progress will also block a writer | ||
| 13 | * from going forward. Unlike the regular rwlock, the read lock here is | ||
| 14 | * exclusive so that only one locking reader can get it. | ||
| 9 | * | 15 | * |
| 10 | * This is not as cache friendly as brlock. Also, this will not work | 16 | * This is not as cache friendly as brlock. Also, this may not work well |
| 11 | * for data that contains pointers, because any writer could | 17 | * for data that contains pointers, because any writer could |
| 12 | * invalidate a pointer that a reader was following. | 18 | * invalidate a pointer that a reader was following. |
| 13 | * | 19 | * |
| 14 | * Expected reader usage: | 20 | * Expected non-blocking reader usage: |
| 15 | * do { | 21 | * do { |
| 16 | * seq = read_seqbegin(&foo); | 22 | * seq = read_seqbegin(&foo); |
| 17 | * ... | 23 | * ... |
| @@ -268,4 +274,56 @@ write_sequnlock_irqrestore(seqlock_t *sl, unsigned long flags) | |||
| 268 | spin_unlock_irqrestore(&sl->lock, flags); | 274 | spin_unlock_irqrestore(&sl->lock, flags); |
| 269 | } | 275 | } |
| 270 | 276 | ||
| 277 | /* | ||
| 278 | * A locking reader exclusively locks out other writers and locking readers, | ||
| 279 | * but doesn't update the sequence number. Acts like a normal spin_lock/unlock. | ||
| 280 | * Don't need preempt_disable() because that is in the spin_lock already. | ||
| 281 | */ | ||
| 282 | static inline void read_seqlock_excl(seqlock_t *sl) | ||
| 283 | { | ||
| 284 | spin_lock(&sl->lock); | ||
| 285 | } | ||
| 286 | |||
| 287 | static inline void read_sequnlock_excl(seqlock_t *sl) | ||
| 288 | { | ||
| 289 | spin_unlock(&sl->lock); | ||
| 290 | } | ||
| 291 | |||
| 292 | static inline void read_seqlock_excl_bh(seqlock_t *sl) | ||
| 293 | { | ||
| 294 | spin_lock_bh(&sl->lock); | ||
| 295 | } | ||
| 296 | |||
| 297 | static inline void read_sequnlock_excl_bh(seqlock_t *sl) | ||
| 298 | { | ||
| 299 | spin_unlock_bh(&sl->lock); | ||
| 300 | } | ||
| 301 | |||
| 302 | static inline void read_seqlock_excl_irq(seqlock_t *sl) | ||
| 303 | { | ||
| 304 | spin_lock_irq(&sl->lock); | ||
| 305 | } | ||
| 306 | |||
| 307 | static inline void read_sequnlock_excl_irq(seqlock_t *sl) | ||
| 308 | { | ||
| 309 | spin_unlock_irq(&sl->lock); | ||
| 310 | } | ||
| 311 | |||
| 312 | static inline unsigned long __read_seqlock_excl_irqsave(seqlock_t *sl) | ||
| 313 | { | ||
| 314 | unsigned long flags; | ||
| 315 | |||
| 316 | spin_lock_irqsave(&sl->lock, flags); | ||
| 317 | return flags; | ||
| 318 | } | ||
| 319 | |||
| 320 | #define read_seqlock_excl_irqsave(lock, flags) \ | ||
| 321 | do { flags = __read_seqlock_excl_irqsave(lock); } while (0) | ||
| 322 | |||
| 323 | static inline void | ||
| 324 | read_sequnlock_excl_irqrestore(seqlock_t *sl, unsigned long flags) | ||
| 325 | { | ||
| 326 | spin_unlock_irqrestore(&sl->lock, flags); | ||
| 327 | } | ||
| 328 | |||
| 271 | #endif /* __LINUX_SEQLOCK_H */ | 329 | #endif /* __LINUX_SEQLOCK_H */ |
