/* * Seqlock implementation for QEMU * * Copyright Red Hat, Inc. 2013 * * Author: * Paolo Bonzini * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. * */ #ifndef QEMU_SEQLOCK_H #define QEMU_SEQLOCK_H 1 #include #include typedef struct QemuSeqLock QemuSeqLock; struct QemuSeqLock { QemuMutex *mutex; unsigned sequence; }; static inline void seqlock_init(QemuSeqLock *sl, QemuMutex *mutex) { sl->mutex = mutex; sl->sequence = 0; } /* Lock out other writers and update the count. */ static inline void seqlock_write_lock(QemuSeqLock *sl) { if (sl->mutex) { qemu_mutex_lock(sl->mutex); } ++sl->sequence; /* Write sequence before updating other fields. */ smp_wmb(); } static inline void seqlock_write_unlock(QemuSeqLock *sl) { /* Write other fields before finalizing sequence. */ smp_wmb(); ++sl->sequence; if (sl->mutex) { qemu_mutex_unlock(sl->mutex); } } static inline unsigned seqlock_read_begin(QemuSeqLock *sl) { /* Always fail if a write is in progress. */ unsigned ret = atomic_read(&sl->sequence); /* Read sequence before reading other fields. */ smp_rmb(); return ret & ~1; } static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start) { /* Read other fields before reading final sequence. */ smp_rmb(); return unlikely(atomic_read(&sl->sequence) != start); } #endif