Blame view

kernel/rcupdate.c 4.99 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * Read-Copy Update mechanism for mutual exclusion
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   *
01c1c660f   Paul E. McKenney   Preempt-RCU: reor...
18
   * Copyright IBM Corporation, 2001
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
   *
   * Authors: Dipankar Sarma <dipankar@in.ibm.com>
   *	    Manfred Spraul <manfred@colorfullife.com>
   * 
   * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
   * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
   * Papers:
   * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
   * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
   *
   * For detailed explanation of Read-Copy Update mechanism see -
   * 		http://lse.sourceforge.net/locking/rcupdate.html
   *
   */
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/spinlock.h>
  #include <linux/smp.h>
  #include <linux/interrupt.h>
  #include <linux/sched.h>
  #include <asm/atomic.h>
  #include <linux/bitops.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
  #include <linux/percpu.h>
  #include <linux/notifier.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  #include <linux/cpu.h>
9331b3157   Ingo Molnar   [PATCH] convert k...
45
  #include <linux/mutex.h>
01c1c660f   Paul E. McKenney   Preempt-RCU: reor...
46
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

70f12f848   Paul E. McKenney   rcu: add rcu_barr...
48
49
50
51
52
  enum rcu_barrier {
  	RCU_BARRIER_STD,
  	RCU_BARRIER_BH,
  	RCU_BARRIER_SCHED,
  };
01c1c660f   Paul E. McKenney   Preempt-RCU: reor...
53
  static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL};
21a1ea9eb   Dipankar Sarma   [PATCH] rcu batch...
54
  static atomic_t rcu_barrier_cpu_count;
9331b3157   Ingo Molnar   [PATCH] convert k...
55
  static DEFINE_MUTEX(rcu_barrier_mutex);
21a1ea9eb   Dipankar Sarma   [PATCH] rcu batch...
56
  static struct completion rcu_barrier_completion;
fbf6bfca7   Paul E. McKenney   rcupdate: fix com...
57
58
59
60
  /*
   * Awaken the corresponding synchronize_rcu() instance now that a
   * grace period has elapsed.
   */
4446a36ff   Paul E. McKenney   rcu: add call_rcu...
61
  void wakeme_after_rcu(struct rcu_head  *head)
21a1ea9eb   Dipankar Sarma   [PATCH] rcu batch...
62
  {
01c1c660f   Paul E. McKenney   Preempt-RCU: reor...
63
64
65
66
  	struct rcu_synchronize *rcu;
  
  	rcu = container_of(head, struct rcu_synchronize, head);
  	complete(&rcu->completion);
21a1ea9eb   Dipankar Sarma   [PATCH] rcu batch...
67
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  
  /**
01c1c660f   Paul E. McKenney   Preempt-RCU: reor...
70
   * synchronize_rcu - wait until a grace period has elapsed.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
   *
01c1c660f   Paul E. McKenney   Preempt-RCU: reor...
72
73
   * Control will return to the caller some time after a full grace
   * period has elapsed, in other words after all currently executing RCU
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
   * read-side critical sections have completed.  RCU read-side critical
   * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
   * and may be nested.
   */
ea7d3fef4   Paul E. McKenney   rcu: eliminate sy...
78
79
80
81
82
83
84
85
86
  void synchronize_rcu(void)
  {
  	struct rcu_synchronize rcu;
  	init_completion(&rcu.completion);
  	/* Will wake me after RCU finished. */
  	call_rcu(&rcu.head, wakeme_after_rcu);
  	/* Wait for it. */
  	wait_for_completion(&rcu.completion);
  }
01c1c660f   Paul E. McKenney   Preempt-RCU: reor...
87
  EXPORT_SYMBOL_GPL(synchronize_rcu);
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
88

ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
89
90
91
92
93
94
95
96
97
  static void rcu_barrier_callback(struct rcu_head *notused)
  {
  	if (atomic_dec_and_test(&rcu_barrier_cpu_count))
  		complete(&rcu_barrier_completion);
  }
  
  /*
   * Called with preemption disabled, and from cross-cpu IRQ context.
   */
70f12f848   Paul E. McKenney   rcu: add rcu_barr...
98
  static void rcu_barrier_func(void *type)
ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
99
100
  {
  	int cpu = smp_processor_id();
01c1c660f   Paul E. McKenney   Preempt-RCU: reor...
101
  	struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu);
ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
102

ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
103
  	atomic_inc(&rcu_barrier_cpu_count);
70f12f848   Paul E. McKenney   rcu: add rcu_barr...
104
105
106
107
108
109
110
111
112
113
114
  	switch ((enum rcu_barrier)type) {
  	case RCU_BARRIER_STD:
  		call_rcu(head, rcu_barrier_callback);
  		break;
  	case RCU_BARRIER_BH:
  		call_rcu_bh(head, rcu_barrier_callback);
  		break;
  	case RCU_BARRIER_SCHED:
  		call_rcu_sched(head, rcu_barrier_callback);
  		break;
  	}
ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
115
  }
70f12f848   Paul E. McKenney   rcu: add rcu_barr...
116
117
118
  /*
   * Orchestrate the specified type of RCU barrier, waiting for all
   * RCU callbacks of the specified type to complete.
ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
119
   */
70f12f848   Paul E. McKenney   rcu: add rcu_barr...
120
  static void _rcu_barrier(enum rcu_barrier type)
ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
121
122
  {
  	BUG_ON(in_interrupt());
9331b3157   Ingo Molnar   [PATCH] convert k...
123
124
  	/* Take cpucontrol mutex to protect against CPU hotplug */
  	mutex_lock(&rcu_barrier_mutex);
ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
125
  	init_completion(&rcu_barrier_completion);
e0ecfa791   Paul E. McKenney   Preempt-RCU: fix ...
126
  	/*
5f8651515   Lai Jiangshan   rcupdate: fix bug...
127
128
129
130
131
132
133
  	 * Initialize rcu_barrier_cpu_count to 1, then invoke
  	 * rcu_barrier_func() on each CPU, so that each CPU also has
  	 * incremented rcu_barrier_cpu_count.  Only then is it safe to
  	 * decrement rcu_barrier_cpu_count -- otherwise the first CPU
  	 * might complete its grace period before all of the other CPUs
  	 * did their increment, causing this function to return too
  	 * early.
e0ecfa791   Paul E. McKenney   Preempt-RCU: fix ...
134
  	 */
5f8651515   Lai Jiangshan   rcupdate: fix bug...
135
  	atomic_set(&rcu_barrier_cpu_count, 1);
59190f421   Linus Torvalds   Merge branch 'gen...
136
  	on_each_cpu(rcu_barrier_func, (void *)type, 1);
5f8651515   Lai Jiangshan   rcupdate: fix bug...
137
138
  	if (atomic_dec_and_test(&rcu_barrier_cpu_count))
  		complete(&rcu_barrier_completion);
ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
139
  	wait_for_completion(&rcu_barrier_completion);
9331b3157   Ingo Molnar   [PATCH] convert k...
140
  	mutex_unlock(&rcu_barrier_mutex);
ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
141
  }
70f12f848   Paul E. McKenney   rcu: add rcu_barr...
142
143
144
145
146
147
148
149
  
  /**
   * rcu_barrier - Wait until all in-flight call_rcu() callbacks complete.
   */
  void rcu_barrier(void)
  {
  	_rcu_barrier(RCU_BARRIER_STD);
  }
ab4720ec7   Dipankar Sarma   [PATCH] add rcu_b...
150
  EXPORT_SYMBOL_GPL(rcu_barrier);
70f12f848   Paul E. McKenney   rcu: add rcu_barr...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  /**
   * rcu_barrier_bh - Wait until all in-flight call_rcu_bh() callbacks complete.
   */
  void rcu_barrier_bh(void)
  {
  	_rcu_barrier(RCU_BARRIER_BH);
  }
  EXPORT_SYMBOL_GPL(rcu_barrier_bh);
  
  /**
   * rcu_barrier_sched - Wait for in-flight call_rcu_sched() callbacks.
   */
  void rcu_barrier_sched(void)
  {
  	_rcu_barrier(RCU_BARRIER_SCHED);
  }
  EXPORT_SYMBOL_GPL(rcu_barrier_sched);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
  void __init rcu_init(void)
  {
01c1c660f   Paul E. McKenney   Preempt-RCU: reor...
170
  	__rcu_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  }