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#include "qemu/sys_membarrier.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_set(&p_rcu_reader->ctr, ctr);
  84
  85    /* Write p_rcu_reader->ctr before reading RCU-protected pointers.  */
  86    smp_mb_placeholder();
  87}
  88
  89static inline void rcu_read_unlock(void)
  90{
  91    struct rcu_reader_data *p_rcu_reader = &rcu_reader;
  92
  93    assert(p_rcu_reader->depth != 0);
  94    if (--p_rcu_reader->depth > 0) {
  95        return;
  96    }
  97
  98    /* Ensure that the critical section is seen to precede the
  99     * store to p_rcu_reader->ctr.  Together with the following
 100     * smp_mb_placeholder(), this ensures writes to p_rcu_reader->ctr
 101     * are sequentially consistent.
 102     */
 103    atomic_store_release(&p_rcu_reader->ctr, 0);
 104
 105    /* Write p_rcu_reader->ctr before reading p_rcu_reader->waiting.  */
 106    smp_mb_placeholder();
 107    if (unlikely(atomic_read(&p_rcu_reader->waiting))) {
 108        atomic_set(&p_rcu_reader->waiting, false);
 109        qemu_event_set(&rcu_gp_event);
 110    }
 111}
 112
 113extern void synchronize_rcu(void);
 114
 115/*
 116 * Reader thread registration.
 117 */
 118extern void rcu_register_thread(void);
 119extern void rcu_unregister_thread(void);
 120
 121/*
 122 * Support for fork().  fork() support is enabled at startup.
 123 */
 124extern void rcu_enable_atfork(void);
 125extern void rcu_disable_atfork(void);
 126
 127struct rcu_head;
 128typedef void RCUCBFunc(struct rcu_head *head);
 129
 130struct rcu_head {
 131    struct rcu_head *next;
 132    RCUCBFunc *func;
 133};
 134
 135extern void call_rcu1(struct rcu_head *head, RCUCBFunc *func);
 136
 137/* The operands of the minus operator must have the same type,
 138 * which must be the one that we specify in the cast.
 139 */
 140#define call_rcu(head, func, field)                                      \
 141    call_rcu1(({                                                         \
 142         char __attribute__((unused))                                    \
 143            offset_must_be_zero[-offsetof(typeof(*(head)), field)],      \
 144            func_type_invalid = (func) - (void (*)(typeof(head)))(func); \
 145         &(head)->field;                                                 \
 146      }),                                                                \
 147      (RCUCBFunc *)(func))
 148
 149#define g_free_rcu(obj, field) \
 150    call_rcu1(({                                                         \
 151        char __attribute__((unused))                                     \
 152            offset_must_be_zero[-offsetof(typeof(*(obj)), field)];       \
 153        &(obj)->field;                                                   \
 154      }),                                                                \
 155      (RCUCBFunc *)g_free);
 156
 157#ifdef __cplusplus
 158}
 159#endif
 160
 161#endif /* QEMU_RCU_H */
 162