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 19typedef struct QemuSeqLock QemuSeqLock; 20 21struct QemuSeqLock { 22 QemuMutex *mutex; 23 unsigned sequence; 24}; 25 26static 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. */ 33static 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 44static 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 55static inline unsigned seqlock_read_begin(QemuSeqLock *sl) 56{ 57 /* Always fail if a write is in progress. */ 58 unsigned ret = atomic_read(&sl->sequence); 59 60 /* Read sequence before reading other fields. */ 61 smp_rmb(); 62 return ret & ~1; 63} 64 65static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start) 66{ 67 /* Read other fields before reading final sequence. */ 68 smp_rmb(); 69 return unlikely(atomic_read(&sl->sequence) != start); 70} 71 72#endif 73