1/* 2 * Read-Copy Update mechanism for mutual exclusion (classic version) 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 * Copyright IBM Corporation, 2001 19 * 20 * Author: Dipankar Sarma <dipankar@in.ibm.com> 21 * 22 * Based on the original work by Paul McKenney <paulmck@us.ibm.com> 23 * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. 24 * Papers: 25 * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf 26 * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) 27 * 28 * For detailed explanation of Read-Copy Update mechanism see - 29 * Documentation/RCU 30 * 31 */ 32 33#ifndef __LINUX_RCUCLASSIC_H 34#define __LINUX_RCUCLASSIC_H 35 36#ifdef __KERNEL__ 37 38#include <linux/cache.h> 39#include <linux/spinlock.h> 40#include <linux/threads.h> 41#include <linux/percpu.h> 42#include <linux/cpumask.h> 43#include <linux/seqlock.h> 44 45 46/* Global control variables for rcupdate callback mechanism. */ 47struct rcu_ctrlblk { 48 long cur; /* Current batch number. */ 49 long completed; /* Number of the last completed batch */ 50 int next_pending; /* Is the next batch already waiting? */ 51 52 int signaled; 53 54 spinlock_t lock ____cacheline_internodealigned_in_smp; 55 cpumask_t cpumask; /* CPUs that need to switch in order */ 56 /* for current batch to proceed. */ 57} ____cacheline_internodealigned_in_smp; 58 59/* Is batch a before batch b ? */ 60static inline int rcu_batch_before(long a, long b) 61{ 62 return (a - b) < 0; 63} 64 65/* Is batch a after batch b ? */ 66static inline int rcu_batch_after(long a, long b) 67{ 68 return (a - b) > 0; 69} 70 71/* 72 * Per-CPU data for Read-Copy UPdate. 73 * nxtlist - new callbacks are added here 74 * curlist - current batch for which quiescent cycle started if any 75 */ 76struct rcu_data { 77 /* 1) quiescent state handling : */ 78 long quiescbatch; /* Batch # for grace period */ 79 int passed_quiesc; /* User-mode/idle loop etc. */ 80 int qs_pending; /* core waits for quiesc state */ 81 82 /* 2) batch handling */ 83 long batch; /* Batch # for current RCU batch */ 84 struct rcu_head *nxtlist; 85 struct rcu_head **nxttail; 86 long qlen; /* # of queued callbacks */ 87 struct rcu_head *curlist; 88 struct rcu_head **curtail; 89 struct rcu_head *donelist; 90 struct rcu_head **donetail; 91 long blimit; /* Upper limit on a processed batch */ 92 int cpu; 93 struct rcu_head barrier; 94}; 95 96DECLARE_PER_CPU(struct rcu_data, rcu_data); 97DECLARE_PER_CPU(struct rcu_data, rcu_bh_data); 98 99/* 100 * Increment the quiescent state counter. 101 * The counter is a bit degenerated: We do not need to know 102 * how many quiescent states passed, just if there was at least 103 * one since the start of the grace period. Thus just a flag. 104 */ 105static inline void rcu_qsctr_inc(int cpu) 106{ 107 struct rcu_data *rdp = &per_cpu(rcu_data, cpu); 108 rdp->passed_quiesc = 1; 109} 110static inline void rcu_bh_qsctr_inc(int cpu) 111{ 112 struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu); 113 rdp->passed_quiesc = 1; 114} 115 116extern int rcu_pending(int cpu); 117extern int rcu_needs_cpu(int cpu); 118 119#ifdef CONFIG_DEBUG_LOCK_ALLOC 120extern struct lockdep_map rcu_lock_map; 121# define rcu_read_acquire() \ 122 lock_acquire(&rcu_lock_map, 0, 0, 2, 1, _THIS_IP_) 123# define rcu_read_release() lock_release(&rcu_lock_map, 1, _THIS_IP_) 124#else 125# define rcu_read_acquire() do { } while (0) 126# define rcu_read_release() do { } while (0) 127#endif 128 129#define __rcu_read_lock() \ 130 do { \ 131 preempt_disable(); \ 132 __acquire(RCU); \ 133 rcu_read_acquire(); \ 134 } while (0) 135#define __rcu_read_unlock() \ 136 do { \ 137 rcu_read_release(); \ 138 __release(RCU); \ 139 preempt_enable(); \ 140 } while (0) 141#define __rcu_read_lock_bh() \ 142 do { \ 143 local_bh_disable(); \ 144 __acquire(RCU_BH); \ 145 rcu_read_acquire(); \ 146 } while (0) 147#define __rcu_read_unlock_bh() \ 148 do { \ 149 rcu_read_release(); \ 150 __release(RCU_BH); \ 151 local_bh_enable(); \ 152 } while (0) 153 154#define __synchronize_sched() synchronize_rcu() 155 156extern void __rcu_init(void); 157extern void rcu_check_callbacks(int cpu, int user); 158extern void rcu_restart_cpu(int cpu); 159 160extern long rcu_batches_completed(void); 161extern long rcu_batches_completed_bh(void); 162 163#endif /* __KERNEL__ */ 164#endif /* __LINUX_RCUCLASSIC_H */