xref: /openbmc/qemu/include/qemu/seqlock.h (revision 92d09502)
1ea753d81SPaolo Bonzini /*
2ea753d81SPaolo Bonzini  * Seqlock implementation for QEMU
3ea753d81SPaolo Bonzini  *
4ea753d81SPaolo Bonzini  * Copyright Red Hat, Inc. 2013
5ea753d81SPaolo Bonzini  *
6ea753d81SPaolo Bonzini  * Author:
7ea753d81SPaolo Bonzini  *  Paolo Bonzini <pbonzini@redhat.com>
8ea753d81SPaolo Bonzini  *
9ea753d81SPaolo Bonzini  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10ea753d81SPaolo Bonzini  * See the COPYING file in the top-level directory.
11ea753d81SPaolo Bonzini  *
12ea753d81SPaolo Bonzini  */
13175de524SMarkus Armbruster 
14ea753d81SPaolo Bonzini #ifndef QEMU_SEQLOCK_H
15175de524SMarkus Armbruster #define QEMU_SEQLOCK_H
16ea753d81SPaolo Bonzini 
17a9c94277SMarkus Armbruster #include "qemu/atomic.h"
18a9c94277SMarkus Armbruster #include "qemu/thread.h"
19988fcafcSPaolo Bonzini #include "qemu/lockable.h"
20ea753d81SPaolo Bonzini 
21ea753d81SPaolo Bonzini typedef struct QemuSeqLock QemuSeqLock;
22ea753d81SPaolo Bonzini 
23ea753d81SPaolo Bonzini struct QemuSeqLock {
24ea753d81SPaolo Bonzini     unsigned sequence;
25ea753d81SPaolo Bonzini };
26ea753d81SPaolo Bonzini 
seqlock_init(QemuSeqLock * sl)27ccdb3c1fSEmilio G. Cota static inline void seqlock_init(QemuSeqLock *sl)
28ea753d81SPaolo Bonzini {
29ea753d81SPaolo Bonzini     sl->sequence = 0;
30ea753d81SPaolo Bonzini }
31ea753d81SPaolo Bonzini 
32ea753d81SPaolo Bonzini /* Lock out other writers and update the count.  */
seqlock_write_begin(QemuSeqLock * sl)3303719e44SEmilio G. Cota static inline void seqlock_write_begin(QemuSeqLock *sl)
34ea753d81SPaolo Bonzini {
35*d73415a3SStefan Hajnoczi     qatomic_set(&sl->sequence, sl->sequence + 1);
36ea753d81SPaolo Bonzini 
37ea753d81SPaolo Bonzini     /* Write sequence before updating other fields.  */
38ea753d81SPaolo Bonzini     smp_wmb();
39ea753d81SPaolo Bonzini }
40ea753d81SPaolo Bonzini 
seqlock_write_end(QemuSeqLock * sl)4103719e44SEmilio G. Cota static inline void seqlock_write_end(QemuSeqLock *sl)
42ea753d81SPaolo Bonzini {
43ea753d81SPaolo Bonzini     /* Write other fields before finalizing sequence.  */
44ea753d81SPaolo Bonzini     smp_wmb();
45ea753d81SPaolo Bonzini 
46*d73415a3SStefan Hajnoczi     qatomic_set(&sl->sequence, sl->sequence + 1);
47ea753d81SPaolo Bonzini }
48ea753d81SPaolo Bonzini 
49988fcafcSPaolo Bonzini /* Lock out other writers and update the count.  */
seqlock_write_lock_impl(QemuSeqLock * sl,QemuLockable * lock)50988fcafcSPaolo Bonzini static inline void seqlock_write_lock_impl(QemuSeqLock *sl, QemuLockable *lock)
51988fcafcSPaolo Bonzini {
52988fcafcSPaolo Bonzini     qemu_lockable_lock(lock);
53988fcafcSPaolo Bonzini     seqlock_write_begin(sl);
54988fcafcSPaolo Bonzini }
55988fcafcSPaolo Bonzini #define seqlock_write_lock(sl, lock) \
56988fcafcSPaolo Bonzini     seqlock_write_lock_impl(sl, QEMU_MAKE_LOCKABLE(lock))
57988fcafcSPaolo Bonzini 
58e261b368SLuc Michel /* Update the count and release the lock.  */
seqlock_write_unlock_impl(QemuSeqLock * sl,QemuLockable * lock)59988fcafcSPaolo Bonzini static inline void seqlock_write_unlock_impl(QemuSeqLock *sl, QemuLockable *lock)
60988fcafcSPaolo Bonzini {
61e261b368SLuc Michel     seqlock_write_end(sl);
62988fcafcSPaolo Bonzini     qemu_lockable_unlock(lock);
63988fcafcSPaolo Bonzini }
64988fcafcSPaolo Bonzini #define seqlock_write_unlock(sl, lock) \
65988fcafcSPaolo Bonzini     seqlock_write_unlock_impl(sl, QEMU_MAKE_LOCKABLE(lock))
66988fcafcSPaolo Bonzini 
67988fcafcSPaolo Bonzini 
seqlock_read_begin(const QemuSeqLock * sl)68c04649eeSEmilio G. Cota static inline unsigned seqlock_read_begin(const QemuSeqLock *sl)
69ea753d81SPaolo Bonzini {
70ea753d81SPaolo Bonzini     /* Always fail if a write is in progress.  */
71*d73415a3SStefan Hajnoczi     unsigned ret = qatomic_read(&sl->sequence);
72ea753d81SPaolo Bonzini 
73ea753d81SPaolo Bonzini     /* Read sequence before reading other fields.  */
74ea753d81SPaolo Bonzini     smp_rmb();
75d12f7309SEmilio G. Cota     return ret & ~1;
76ea753d81SPaolo Bonzini }
77ea753d81SPaolo Bonzini 
seqlock_read_retry(const QemuSeqLock * sl,unsigned start)78123fdbacSEmilio G. Cota static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start)
79ea753d81SPaolo Bonzini {
80ea753d81SPaolo Bonzini     /* Read other fields before reading final sequence.  */
81ea753d81SPaolo Bonzini     smp_rmb();
82*d73415a3SStefan Hajnoczi     return unlikely(qatomic_read(&sl->sequence) != start);
83ea753d81SPaolo Bonzini }
84ea753d81SPaolo Bonzini 
85ea753d81SPaolo Bonzini #endif
86