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 20typedef struct QemuSeqLock QemuSeqLock; 21 22struct QemuSeqLock { 23 unsigned sequence; 24}; 25 26static inline void seqlock_init(QemuSeqLock *sl) 27{ 28 sl->sequence = 0; 29} 30 31/* Lock out other writers and update the count. */ 32static 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 40static 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 48static 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 58static 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