]>
Commit | Line | Data |
---|---|---|
ea753d81 PB |
1 | /* |
2 | * Seqlock implementation for QEMU | |
3 | * | |
4 | * Copyright Red Hat, Inc. 2013 | |
5 | * | |
6 | * Author: | |
7 | * Paolo Bonzini <pbonzini@redhat.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
10 | * See the COPYING file in the top-level directory. | |
11 | * | |
12 | */ | |
175de524 | 13 | |
ea753d81 | 14 | #ifndef QEMU_SEQLOCK_H |
175de524 | 15 | #define QEMU_SEQLOCK_H |
ea753d81 | 16 | |
a9c94277 MA |
17 | #include "qemu/atomic.h" |
18 | #include "qemu/thread.h" | |
988fcafc | 19 | #include "qemu/lockable.h" |
ea753d81 PB |
20 | |
21 | typedef struct QemuSeqLock QemuSeqLock; | |
22 | ||
23 | struct QemuSeqLock { | |
ea753d81 PB |
24 | unsigned sequence; |
25 | }; | |
26 | ||
ccdb3c1f | 27 | static inline void seqlock_init(QemuSeqLock *sl) |
ea753d81 | 28 | { |
ea753d81 PB |
29 | sl->sequence = 0; |
30 | } | |
31 | ||
32 | /* Lock out other writers and update the count. */ | |
03719e44 | 33 | static inline void seqlock_write_begin(QemuSeqLock *sl) |
ea753d81 | 34 | { |
d73415a3 | 35 | qatomic_set(&sl->sequence, sl->sequence + 1); |
ea753d81 PB |
36 | |
37 | /* Write sequence before updating other fields. */ | |
38 | smp_wmb(); | |
39 | } | |
40 | ||
03719e44 | 41 | static inline void seqlock_write_end(QemuSeqLock *sl) |
ea753d81 PB |
42 | { |
43 | /* Write other fields before finalizing sequence. */ | |
44 | smp_wmb(); | |
45 | ||
d73415a3 | 46 | qatomic_set(&sl->sequence, sl->sequence + 1); |
ea753d81 PB |
47 | } |
48 | ||
988fcafc PB |
49 | /* Lock out other writers and update the count. */ |
50 | static inline void seqlock_write_lock_impl(QemuSeqLock *sl, QemuLockable *lock) | |
51 | { | |
52 | qemu_lockable_lock(lock); | |
53 | seqlock_write_begin(sl); | |
54 | } | |
55 | #define seqlock_write_lock(sl, lock) \ | |
56 | seqlock_write_lock_impl(sl, QEMU_MAKE_LOCKABLE(lock)) | |
57 | ||
e261b368 | 58 | /* Update the count and release the lock. */ |
988fcafc PB |
59 | static inline void seqlock_write_unlock_impl(QemuSeqLock *sl, QemuLockable *lock) |
60 | { | |
e261b368 | 61 | seqlock_write_end(sl); |
988fcafc | 62 | qemu_lockable_unlock(lock); |
988fcafc PB |
63 | } |
64 | #define seqlock_write_unlock(sl, lock) \ | |
65 | seqlock_write_unlock_impl(sl, QEMU_MAKE_LOCKABLE(lock)) | |
66 | ||
67 | ||
c04649ee | 68 | static inline unsigned seqlock_read_begin(const QemuSeqLock *sl) |
ea753d81 PB |
69 | { |
70 | /* Always fail if a write is in progress. */ | |
d73415a3 | 71 | unsigned ret = qatomic_read(&sl->sequence); |
ea753d81 PB |
72 | |
73 | /* Read sequence before reading other fields. */ | |
74 | smp_rmb(); | |
d12f7309 | 75 | return ret & ~1; |
ea753d81 PB |
76 | } |
77 | ||
123fdbac | 78 | static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start) |
ea753d81 PB |
79 | { |
80 | /* Read other fields before reading final sequence. */ | |
81 | smp_rmb(); | |
d73415a3 | 82 | return unlikely(qatomic_read(&sl->sequence) != start); |
ea753d81 PB |
83 | } |
84 | ||
85 | #endif |