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