qemu/include/qemu/rcu.h
<<
>>
Prefs
   1#ifndef QEMU_RCU_H
   2#define QEMU_RCU_H
   3
   4/*
   5 * urcu-mb.h
   6 *
   7 * Userspace RCU header with explicit memory barrier.
   8 *
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation; either
  12 * version 2.1 of the License, or (at your option) any later version.
  13 *
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22 *
  23 * IBM's contributions to this file may be relicensed under LGPLv2 or later.
  24 */
  25
  26
  27#include "qemu/thread.h"
  28#include "qemu/queue.h"
  29#include "qemu/atomic.h"
  30
  31#ifdef __cplusplus
  32extern "C" {
  33#endif
  34
  35/*
  36 * Important !
  37 *
  38 * Each thread containing read-side critical sections must be registered
  39 * with rcu_register_thread() before calling rcu_read_lock().
  40 * rcu_unregister_thread() should be called before the thread exits.
  41 */
  42
  43#ifdef DEBUG_RCU
  44#define rcu_assert(args...)    assert(args)
  45#else
  46#define rcu_assert(args...)
  47#endif
  48
  49/*
  50 * Global quiescent period counter with low-order bits unused.
  51 * Using a int rather than a char to eliminate false register dependencies
  52 * causing stalls on some architectures.
  53 */
  54extern unsigned long rcu_gp_ctr;
  55
  56extern QemuEvent rcu_gp_event;
  57
  58struct rcu_reader_data {
  59    /* Data used by both reader and synchronize_rcu() */
  60    unsigned long ctr;
  61    bool waiting;
  62
  63    /* Data used by reader only */
  64    unsigned depth;
  65
  66    /* Data used for registry, protected by rcu_registry_lock */
  67    QLIST_ENTRY(rcu_reader_data) node;
  68};
  69
  70extern __thread struct rcu_reader_data rcu_reader;
  71
  72static inline void rcu_read_lock(void)
  73{
  74    struct rcu_reader_data *p_rcu_reader = &rcu_reader;
  75    unsigned ctr;
  76
  77    if (p_rcu_reader->depth++ > 0) {
  78        return;
  79    }
  80
  81    ctr = atomic_read(&rcu_gp_ctr);
  82    atomic_xchg(&p_rcu_reader->ctr, ctr);
  83}
  84
  85static inline void rcu_read_unlock(void)
  86{
  87    struct rcu_reader_data *p_rcu_reader = &rcu_reader;
  88
  89    assert(p_rcu_reader->depth != 0);
  90    if (--p_rcu_reader->depth > 0) {
  91        return;
  92    }
  93
  94    atomic_xchg(&p_rcu_reader->ctr, 0);
  95    if (unlikely(atomic_read(&p_rcu_reader->waiting))) {
  96        atomic_set(&p_rcu_reader->waiting, false);
  97        qemu_event_set(&rcu_gp_event);
  98    }
  99}
 100
 101extern void synchronize_rcu(void);
 102
 103/*
 104 * Reader thread registration.
 105 */
 106extern void rcu_register_thread(void);
 107extern void rcu_unregister_thread(void);
 108
 109/*
 110 * Support for fork().  fork() support is enabled at startup.
 111 */
 112extern void rcu_enable_atfork(void);
 113extern void rcu_disable_atfork(void);
 114
 115struct rcu_head;
 116typedef void RCUCBFunc(struct rcu_head *head);
 117
 118struct rcu_head {
 119    struct rcu_head *next;
 120    RCUCBFunc *func;
 121};
 122
 123extern void call_rcu1(struct rcu_head *head, RCUCBFunc *func);
 124
 125/* The operands of the minus operator must have the same type,
 126 * which must be the one that we specify in the cast.
 127 */
 128#define call_rcu(head, func, field)                                      \
 129    call_rcu1(({                                                         \
 130         char __attribute__((unused))                                    \
 131            offset_must_be_zero[-offsetof(typeof(*(head)), field)],      \
 132            func_type_invalid = (func) - (void (*)(typeof(head)))(func); \
 133         &(head)->field;                                                 \
 134      }),                                                                \
 135      (RCUCBFunc *)(func))
 136
 137#define g_free_rcu(obj, field) \
 138    call_rcu1(({                                                         \
 139        char __attribute__((unused))                                     \
 140            offset_must_be_zero[-offsetof(typeof(*(obj)), field)];       \
 141        &(obj)->field;                                                   \
 142      }),                                                                \
 143      (RCUCBFunc *)g_free);
 144
 145#ifdef __cplusplus
 146}
 147#endif
 148
 149#endif /* QEMU_RCU_H */
 150