xref: /openbmc/qemu/include/qemu/seqlock.h (revision 92d09502)
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  */
13 
14 #ifndef QEMU_SEQLOCK_H
15 #define QEMU_SEQLOCK_H
16 
17 #include "qemu/atomic.h"
18 #include "qemu/thread.h"
19 #include "qemu/lockable.h"
20 
21 typedef struct QemuSeqLock QemuSeqLock;
22 
23 struct QemuSeqLock {
24     unsigned sequence;
25 };
26 
seqlock_init(QemuSeqLock * sl)27 static inline void seqlock_init(QemuSeqLock *sl)
28 {
29     sl->sequence = 0;
30 }
31 
32 /* Lock out other writers and update the count.  */
seqlock_write_begin(QemuSeqLock * sl)33 static inline void seqlock_write_begin(QemuSeqLock *sl)
34 {
35     qatomic_set(&sl->sequence, sl->sequence + 1);
36 
37     /* Write sequence before updating other fields.  */
38     smp_wmb();
39 }
40 
seqlock_write_end(QemuSeqLock * sl)41 static inline void seqlock_write_end(QemuSeqLock *sl)
42 {
43     /* Write other fields before finalizing sequence.  */
44     smp_wmb();
45 
46     qatomic_set(&sl->sequence, sl->sequence + 1);
47 }
48 
49 /* Lock out other writers and update the count.  */
seqlock_write_lock_impl(QemuSeqLock * sl,QemuLockable * lock)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 
58 /* Update the count and release the lock.  */
seqlock_write_unlock_impl(QemuSeqLock * sl,QemuLockable * lock)59 static inline void seqlock_write_unlock_impl(QemuSeqLock *sl, QemuLockable *lock)
60 {
61     seqlock_write_end(sl);
62     qemu_lockable_unlock(lock);
63 }
64 #define seqlock_write_unlock(sl, lock) \
65     seqlock_write_unlock_impl(sl, QEMU_MAKE_LOCKABLE(lock))
66 
67 
seqlock_read_begin(const QemuSeqLock * sl)68 static inline unsigned seqlock_read_begin(const QemuSeqLock *sl)
69 {
70     /* Always fail if a write is in progress.  */
71     unsigned ret = qatomic_read(&sl->sequence);
72 
73     /* Read sequence before reading other fields.  */
74     smp_rmb();
75     return ret & ~1;
76 }
77 
seqlock_read_retry(const QemuSeqLock * sl,unsigned start)78 static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start)
79 {
80     /* Read other fields before reading final sequence.  */
81     smp_rmb();
82     return unlikely(qatomic_read(&sl->sequence) != start);
83 }
84 
85 #endif
86