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