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