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#include <glib.h>
  27
  28#include "qemu/thread.h"
  29#include "qemu/queue.h"
  30#include "qemu/atomic.h"
  31
  32#ifdef __cplusplus
  33extern "C" {
  34#endif
  35
  36/*
  37 * Important !
  38 *
  39 * Each thread containing read-side critical sections must be registered
  40 * with rcu_register_thread() before calling rcu_read_lock().
  41 * rcu_unregister_thread() should be called before the thread exits.
  42 */
  43
  44#ifdef DEBUG_RCU
  45#define rcu_assert(args...)    assert(args)
  46#else
  47#define rcu_assert(args...)
  48#endif
  49
  50/*
  51 * Global quiescent period counter with low-order bits unused.
  52 * Using a int rather than a char to eliminate false register dependencies
  53 * causing stalls on some architectures.
  54 */
  55extern unsigned long rcu_gp_ctr;
  56
  57extern QemuEvent rcu_gp_event;
  58
  59struct rcu_reader_data {
  60    /* Data used by both reader and synchronize_rcu() */
  61    unsigned long ctr;
  62    bool waiting;
  63
  64    /* Data used by reader only */
  65    unsigned depth;
  66
  67    /* Data used for registry, protected by rcu_registry_lock */
  68    QLIST_ENTRY(rcu_reader_data) node;
  69};
  70
  71extern __thread struct rcu_reader_data rcu_reader;
  72
  73static inline void rcu_read_lock(void)
  74{
  75    struct rcu_reader_data *p_rcu_reader = &rcu_reader;
  76    unsigned ctr;
  77
  78    if (p_rcu_reader->depth++ > 0) {
  79        return;
  80    }
  81
  82    ctr = atomic_read(&rcu_gp_ctr);
  83    atomic_xchg(&p_rcu_reader->ctr, ctr);
  84}
  85
  86static inline void rcu_read_unlock(void)
  87{
  88    struct rcu_reader_data *p_rcu_reader = &rcu_reader;
  89
  90    assert(p_rcu_reader->depth != 0);
  91    if (--p_rcu_reader->depth > 0) {
  92        return;
  93    }
  94
  95    atomic_xchg(&p_rcu_reader->ctr, 0);
  96    if (unlikely(atomic_read(&p_rcu_reader->waiting))) {
  97        atomic_set(&p_rcu_reader->waiting, false);
  98        qemu_event_set(&rcu_gp_event);
  99    }
 100}
 101
 102extern void synchronize_rcu(void);
 103
 104/*
 105 * Reader thread registration.
 106 */
 107extern void rcu_register_thread(void);
 108extern void rcu_unregister_thread(void);
 109extern void rcu_after_fork(void);
 110
 111struct rcu_head;
 112typedef void RCUCBFunc(struct rcu_head *head);
 113
 114struct rcu_head {
 115    struct rcu_head *next;
 116    RCUCBFunc *func;
 117};
 118
 119extern void call_rcu1(struct rcu_head *head, RCUCBFunc *func);
 120
 121/* The operands of the minus operator must have the same type,
 122 * which must be the one that we specify in the cast.
 123 */
 124#define call_rcu(head, func, field)                                      \
 125    call_rcu1(({                                                         \
 126         char __attribute__((unused))                                    \
 127            offset_must_be_zero[-offsetof(typeof(*(head)), field)],      \
 128            func_type_invalid = (func) - (void (*)(typeof(head)))(func); \
 129         &(head)->field;                                                 \
 130      }),                                                                \
 131      (RCUCBFunc *)(func))
 132
 133#define g_free_rcu(obj, field) \
 134    call_rcu1(({                                                         \
 135        char __attribute__((unused))                                     \
 136            offset_must_be_zero[-offsetof(typeof(*(obj)), field)];       \
 137        &(obj)->field;                                                   \
 138      }),                                                                \
 139      (RCUCBFunc *)g_free);
 140
 141#ifdef __cplusplus
 142}
 143#endif
 144
 145#endif /* QEMU_RCU_H */
 146