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);
 108extern void rcu_after_fork(void);
 109
 110struct rcu_head;
 111typedef void RCUCBFunc(struct rcu_head *head);
 112
 113struct rcu_head {
 114    struct rcu_head *next;
 115    RCUCBFunc *func;
 116};
 117
 118extern void call_rcu1(struct rcu_head *head, RCUCBFunc *func);
 119
 120/* The operands of the minus operator must have the same type,
 121 * which must be the one that we specify in the cast.
 122 */
 123#define call_rcu(head, func, field)                                      \
 124    call_rcu1(({                                                         \
 125         char __attribute__((unused))                                    \
 126            offset_must_be_zero[-offsetof(typeof(*(head)), field)],      \
 127            func_type_invalid = (func) - (void (*)(typeof(head)))(func); \
 128         &(head)->field;                                                 \
 129      }),                                                                \
 130      (RCUCBFunc *)(func))
 131
 132#define g_free_rcu(obj, field) \
 133    call_rcu1(({                                                         \
 134        char __attribute__((unused))                                     \
 135            offset_must_be_zero[-offsetof(typeof(*(obj)), field)];       \
 136        &(obj)->field;                                                   \
 137      }),                                                                \
 138      (RCUCBFunc *)g_free);
 139
 140#ifdef __cplusplus
 141}
 142#endif
 143
 144#endif /* QEMU_RCU_H */
 145