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 20 typedef struct QemuSeqLock QemuSeqLock; 21 22 struct QemuSeqLock { 23 unsigned sequence; 24 }; 25 26 static inline void seqlock_init(QemuSeqLock *sl) 27 { 28 sl->sequence = 0; 29 } 30 31 /* Lock out other writers and update the count. */ 32 static inline void seqlock_write_begin(QemuSeqLock *sl) 33 { 34 atomic_set(&sl->sequence, sl->sequence + 1); 35 36 /* Write sequence before updating other fields. */ 37 smp_wmb(); 38 } 39 40 static inline void seqlock_write_end(QemuSeqLock *sl) 41 { 42 /* Write other fields before finalizing sequence. */ 43 smp_wmb(); 44 45 atomic_set(&sl->sequence, sl->sequence + 1); 46 } 47 48 static inline unsigned seqlock_read_begin(QemuSeqLock *sl) 49 { 50 /* Always fail if a write is in progress. */ 51 unsigned ret = atomic_read(&sl->sequence); 52 53 /* Read sequence before reading other fields. */ 54 smp_rmb(); 55 return ret & ~1; 56 } 57 58 static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start) 59 { 60 /* Read other fields before reading final sequence. */ 61 smp_rmb(); 62 return unlikely(atomic_read(&sl->sequence) != start); 63 } 64 65 #endif 66