qemu/include/qemu/seqlock.h
<<
>>
Prefs
   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#include "qemu/lockable.h"
  20
  21typedef struct QemuSeqLock QemuSeqLock;
  22
  23struct QemuSeqLock {
  24    unsigned sequence;
  25};
  26
  27static inline void seqlock_init(QemuSeqLock *sl)
  28{
  29    sl->sequence = 0;
  30}
  31
  32/* Lock out other writers and update the count.  */
  33static inline void seqlock_write_begin(QemuSeqLock *sl)
  34{
  35    qatomic_set(&sl->sequence, sl->sequence + 1);
  36
  37    /* Write sequence before updating other fields.  */
  38    smp_wmb();
  39}
  40
  41static inline void seqlock_write_end(QemuSeqLock *sl)
  42{
  43    /* Write other fields before finalizing sequence.  */
  44    smp_wmb();
  45
  46    qatomic_set(&sl->sequence, sl->sequence + 1);
  47}
  48
  49/* Lock out other writers and update the count.  */
  50static inline void seqlock_write_lock_impl(QemuSeqLock *sl, QemuLockable *lock)
  51{
  52    qemu_lockable_lock(lock);
  53    seqlock_write_begin(sl);
  54}
  55#define seqlock_write_lock(sl, lock) \
  56    seqlock_write_lock_impl(sl, QEMU_MAKE_LOCKABLE(lock))
  57
  58/* Update the count and release the lock.  */
  59static inline void seqlock_write_unlock_impl(QemuSeqLock *sl, QemuLockable *lock)
  60{
  61    seqlock_write_end(sl);
  62    qemu_lockable_unlock(lock);
  63}
  64#define seqlock_write_unlock(sl, lock) \
  65    seqlock_write_unlock_impl(sl, QEMU_MAKE_LOCKABLE(lock))
  66
  67
  68static inline unsigned seqlock_read_begin(const QemuSeqLock *sl)
  69{
  70    /* Always fail if a write is in progress.  */
  71    unsigned ret = qatomic_read(&sl->sequence);
  72
  73    /* Read sequence before reading other fields.  */
  74    smp_rmb();
  75    return ret & ~1;
  76}
  77
  78static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start)
  79{
  80    /* Read other fields before reading final sequence.  */
  81    smp_rmb();
  82    return unlikely(qatomic_read(&sl->sequence) != start);
  83}
  84
  85#endif
  86