aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2011-05-27 01:14:36 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2011-09-29 00:36:42 -0400
commit2c42818e962e2858334bf45bfc56662b3752df34 (patch)
tree192364123c9aeeab282c53168e51eddece9d8be4
parentf039d1f1884b2fe9c13d28f59d8330f0b0518fc4 (diff)
rcu: Abstract common code for RCU grace-period-wait primitives
Pull the code that waits for an RCU grace period into a single function, which is then called by synchronize_rcu() and friends in the case of TREE_RCU and TREE_PREEMPT_RCU, and from rcu_barrier() and friends in the case of TINY_RCU and TINY_PREEMPT_RCU. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r--include/linux/rcupdate.h130
-rw-r--r--include/linux/rcutiny.h16
-rw-r--r--include/linux/rcutree.h2
-rw-r--r--kernel/rcupdate.c21
-rw-r--r--kernel/rcutiny.c28
-rw-r--r--kernel/rcutiny_plugin.h14
-rw-r--r--kernel/rcutree.c22
-rw-r--r--kernel/rcutree_plugin.h11
8 files changed, 113 insertions, 131 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 87bd390df73f..ae5327de41aa 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -66,11 +66,73 @@ static inline void rcutorture_record_progress(unsigned long vernum)
66#define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b)) 66#define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b))
67 67
68/* Exported common interfaces */ 68/* Exported common interfaces */
69
70#ifdef CONFIG_PREEMPT_RCU
71
72/**
73 * call_rcu() - Queue an RCU callback for invocation after a grace period.
74 * @head: structure to be used for queueing the RCU updates.
75 * @func: actual callback function to be invoked after the grace period
76 *
77 * The callback function will be invoked some time after a full grace
78 * period elapses, in other words after all pre-existing RCU read-side
79 * critical sections have completed. However, the callback function
80 * might well execute concurrently with RCU read-side critical sections
81 * that started after call_rcu() was invoked. RCU read-side critical
82 * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
83 * and may be nested.
84 */
85extern void call_rcu(struct rcu_head *head,
86 void (*func)(struct rcu_head *head));
87
88#else /* #ifdef CONFIG_PREEMPT_RCU */
89
90/* In classic RCU, call_rcu() is just call_rcu_sched(). */
91#define call_rcu call_rcu_sched
92
93#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
94
95/**
96 * call_rcu_bh() - Queue an RCU for invocation after a quicker grace period.
97 * @head: structure to be used for queueing the RCU updates.
98 * @func: actual callback function to be invoked after the grace period
99 *
100 * The callback function will be invoked some time after a full grace
101 * period elapses, in other words after all currently executing RCU
102 * read-side critical sections have completed. call_rcu_bh() assumes
103 * that the read-side critical sections end on completion of a softirq
104 * handler. This means that read-side critical sections in process
105 * context must not be interrupted by softirqs. This interface is to be
106 * used when most of the read-side critical sections are in softirq context.
107 * RCU read-side critical sections are delimited by :
108 * - rcu_read_lock() and rcu_read_unlock(), if in interrupt context.
109 * OR
110 * - rcu_read_lock_bh() and rcu_read_unlock_bh(), if in process context.
111 * These may be nested.
112 */
113extern void call_rcu_bh(struct rcu_head *head,
114 void (*func)(struct rcu_head *head));
115
116/**
117 * call_rcu_sched() - Queue an RCU for invocation after sched grace period.
118 * @head: structure to be used for queueing the RCU updates.
119 * @func: actual callback function to be invoked after the grace period
120 *
121 * The callback function will be invoked some time after a full grace
122 * period elapses, in other words after all currently executing RCU
123 * read-side critical sections have completed. call_rcu_sched() assumes
124 * that the read-side critical sections end on enabling of preemption
125 * or on voluntary preemption.
126 * RCU read-side critical sections are delimited by :
127 * - rcu_read_lock_sched() and rcu_read_unlock_sched(),
128 * OR
129 * anything that disables preemption.
130 * These may be nested.
131 */
69extern void call_rcu_sched(struct rcu_head *head, 132extern void call_rcu_sched(struct rcu_head *head,
70 void (*func)(struct rcu_head *rcu)); 133 void (*func)(struct rcu_head *rcu));
134
71extern void synchronize_sched(void); 135extern void synchronize_sched(void);
72extern void rcu_barrier_bh(void);
73extern void rcu_barrier_sched(void);
74 136
75static inline void __rcu_read_lock_bh(void) 137static inline void __rcu_read_lock_bh(void)
76{ 138{
@@ -143,6 +205,15 @@ static inline void rcu_exit_nohz(void)
143 205
144#endif /* #else #ifdef CONFIG_NO_HZ */ 206#endif /* #else #ifdef CONFIG_NO_HZ */
145 207
208/*
209 * Infrastructure to implement the synchronize_() primitives in
210 * TREE_RCU and rcu_barrier_() primitives in TINY_RCU.
211 */
212
213typedef void call_rcu_func_t(struct rcu_head *head,
214 void (*func)(struct rcu_head *head));
215void wait_rcu_gp(call_rcu_func_t crf);
216
146#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) 217#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
147#include <linux/rcutree.h> 218#include <linux/rcutree.h>
148#elif defined(CONFIG_TINY_RCU) || defined(CONFIG_TINY_PREEMPT_RCU) 219#elif defined(CONFIG_TINY_RCU) || defined(CONFIG_TINY_PREEMPT_RCU)
@@ -723,61 +794,6 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
723#define RCU_INIT_POINTER(p, v) \ 794#define RCU_INIT_POINTER(p, v) \
724 p = (typeof(*v) __force __rcu *)(v) 795 p = (typeof(*v) __force __rcu *)(v)
725 796
726/* Infrastructure to implement the synchronize_() primitives. */
727
728struct rcu_synchronize {
729 struct rcu_head head;
730 struct completion completion;
731};
732
733extern void wakeme_after_rcu(struct rcu_head *head);
734
735#ifdef CONFIG_PREEMPT_RCU
736
737/**
738 * call_rcu() - Queue an RCU callback for invocation after a grace period.
739 * @head: structure to be used for queueing the RCU updates.
740 * @func: actual callback function to be invoked after the grace period
741 *
742 * The callback function will be invoked some time after a full grace
743 * period elapses, in other words after all pre-existing RCU read-side
744 * critical sections have completed. However, the callback function
745 * might well execute concurrently with RCU read-side critical sections
746 * that started after call_rcu() was invoked. RCU read-side critical
747 * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
748 * and may be nested.
749 */
750extern void call_rcu(struct rcu_head *head,
751 void (*func)(struct rcu_head *head));
752
753#else /* #ifdef CONFIG_PREEMPT_RCU */
754
755/* In classic RCU, call_rcu() is just call_rcu_sched(). */
756#define call_rcu call_rcu_sched
757
758#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
759
760/**
761 * call_rcu_bh() - Queue an RCU for invocation after a quicker grace period.
762 * @head: structure to be used for queueing the RCU updates.
763 * @func: actual callback function to be invoked after the grace period
764 *
765 * The callback function will be invoked some time after a full grace
766 * period elapses, in other words after all currently executing RCU
767 * read-side critical sections have completed. call_rcu_bh() assumes
768 * that the read-side critical sections end on completion of a softirq
769 * handler. This means that read-side critical sections in process
770 * context must not be interrupted by softirqs. This interface is to be
771 * used when most of the read-side critical sections are in softirq context.
772 * RCU read-side critical sections are delimited by :
773 * - rcu_read_lock() and rcu_read_unlock(), if in interrupt context.
774 * OR
775 * - rcu_read_lock_bh() and rcu_read_unlock_bh(), if in process context.
776 * These may be nested.
777 */
778extern void call_rcu_bh(struct rcu_head *head,
779 void (*func)(struct rcu_head *head));
780
781/* 797/*
782 * debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally 798 * debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally
783 * by call_rcu() and rcu callback execution, and are therefore not part of the 799 * by call_rcu() and rcu callback execution, and are therefore not part of the
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
index 52b3e0281fd0..4eab233a00cd 100644
--- a/include/linux/rcutiny.h
+++ b/include/linux/rcutiny.h
@@ -31,6 +31,16 @@ static inline void rcu_init(void)
31{ 31{
32} 32}
33 33
34static inline void rcu_barrier_bh(void)
35{
36 wait_rcu_gp(call_rcu_bh);
37}
38
39static inline void rcu_barrier_sched(void)
40{
41 wait_rcu_gp(call_rcu_sched);
42}
43
34#ifdef CONFIG_TINY_RCU 44#ifdef CONFIG_TINY_RCU
35 45
36static inline void synchronize_rcu_expedited(void) 46static inline void synchronize_rcu_expedited(void)
@@ -45,9 +55,13 @@ static inline void rcu_barrier(void)
45 55
46#else /* #ifdef CONFIG_TINY_RCU */ 56#else /* #ifdef CONFIG_TINY_RCU */
47 57
48void rcu_barrier(void);
49void synchronize_rcu_expedited(void); 58void synchronize_rcu_expedited(void);
50 59
60static inline void rcu_barrier(void)
61{
62 wait_rcu_gp(call_rcu);
63}
64
51#endif /* #else #ifdef CONFIG_TINY_RCU */ 65#endif /* #else #ifdef CONFIG_TINY_RCU */
52 66
53static inline void synchronize_rcu_bh(void) 67static inline void synchronize_rcu_bh(void)
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index e65d06634dd8..67458468f1a8 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -67,6 +67,8 @@ static inline void synchronize_rcu_bh_expedited(void)
67} 67}
68 68
69extern void rcu_barrier(void); 69extern void rcu_barrier(void);
70extern void rcu_barrier_bh(void);
71extern void rcu_barrier_sched(void);
70 72
71extern unsigned long rcutorture_testseq; 73extern unsigned long rcutorture_testseq;
72extern unsigned long rcutorture_vernum; 74extern unsigned long rcutorture_vernum;
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index ddddb320be61..09b3b1b54e02 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -94,11 +94,16 @@ EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held);
94 94
95#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ 95#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
96 96
97struct rcu_synchronize {
98 struct rcu_head head;
99 struct completion completion;
100};
101
97/* 102/*
98 * Awaken the corresponding synchronize_rcu() instance now that a 103 * Awaken the corresponding synchronize_rcu() instance now that a
99 * grace period has elapsed. 104 * grace period has elapsed.
100 */ 105 */
101void wakeme_after_rcu(struct rcu_head *head) 106static void wakeme_after_rcu(struct rcu_head *head)
102{ 107{
103 struct rcu_synchronize *rcu; 108 struct rcu_synchronize *rcu;
104 109
@@ -106,6 +111,20 @@ void wakeme_after_rcu(struct rcu_head *head)
106 complete(&rcu->completion); 111 complete(&rcu->completion);
107} 112}
108 113
114void wait_rcu_gp(call_rcu_func_t crf)
115{
116 struct rcu_synchronize rcu;
117
118 init_rcu_head_on_stack(&rcu.head);
119 init_completion(&rcu.completion);
120 /* Will wake me after RCU finished. */
121 crf(&rcu.head, wakeme_after_rcu);
122 /* Wait for it. */
123 wait_for_completion(&rcu.completion);
124 destroy_rcu_head_on_stack(&rcu.head);
125}
126EXPORT_SYMBOL_GPL(wait_rcu_gp);
127
109#ifdef CONFIG_PROVE_RCU 128#ifdef CONFIG_PROVE_RCU
110/* 129/*
111 * wrapper function to avoid #include problems. 130 * wrapper function to avoid #include problems.
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 7bbac7d0f5ab..f544e343256a 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -281,34 +281,6 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
281} 281}
282EXPORT_SYMBOL_GPL(call_rcu_bh); 282EXPORT_SYMBOL_GPL(call_rcu_bh);
283 283
284void rcu_barrier_bh(void)
285{
286 struct rcu_synchronize rcu;
287
288 init_rcu_head_on_stack(&rcu.head);
289 init_completion(&rcu.completion);
290 /* Will wake me after RCU finished. */
291 call_rcu_bh(&rcu.head, wakeme_after_rcu);
292 /* Wait for it. */
293 wait_for_completion(&rcu.completion);
294 destroy_rcu_head_on_stack(&rcu.head);
295}
296EXPORT_SYMBOL_GPL(rcu_barrier_bh);
297
298void rcu_barrier_sched(void)
299{
300 struct rcu_synchronize rcu;
301
302 init_rcu_head_on_stack(&rcu.head);
303 init_completion(&rcu.completion);
304 /* Will wake me after RCU finished. */
305 call_rcu_sched(&rcu.head, wakeme_after_rcu);
306 /* Wait for it. */
307 wait_for_completion(&rcu.completion);
308 destroy_rcu_head_on_stack(&rcu.head);
309}
310EXPORT_SYMBOL_GPL(rcu_barrier_sched);
311
312/* 284/*
313 * Spawn the kthread that invokes RCU callbacks. 285 * Spawn the kthread that invokes RCU callbacks.
314 */ 286 */
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h
index f259c676195f..6b0cedb383e0 100644
--- a/kernel/rcutiny_plugin.h
+++ b/kernel/rcutiny_plugin.h
@@ -697,20 +697,6 @@ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
697} 697}
698EXPORT_SYMBOL_GPL(call_rcu); 698EXPORT_SYMBOL_GPL(call_rcu);
699 699
700void rcu_barrier(void)
701{
702 struct rcu_synchronize rcu;
703
704 init_rcu_head_on_stack(&rcu.head);
705 init_completion(&rcu.completion);
706 /* Will wake me after RCU finished. */
707 call_rcu(&rcu.head, wakeme_after_rcu);
708 /* Wait for it. */
709 wait_for_completion(&rcu.completion);
710 destroy_rcu_head_on_stack(&rcu.head);
711}
712EXPORT_SYMBOL_GPL(rcu_barrier);
713
714/* 700/*
715 * synchronize_rcu - wait until a grace period has elapsed. 701 * synchronize_rcu - wait until a grace period has elapsed.
716 * 702 *
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index ba06207b1dd3..a7c6bce1af83 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1613,18 +1613,9 @@ EXPORT_SYMBOL_GPL(call_rcu_bh);
1613 */ 1613 */
1614void synchronize_sched(void) 1614void synchronize_sched(void)
1615{ 1615{
1616 struct rcu_synchronize rcu;
1617
1618 if (rcu_blocking_is_gp()) 1616 if (rcu_blocking_is_gp())
1619 return; 1617 return;
1620 1618 wait_rcu_gp(call_rcu_sched);
1621 init_rcu_head_on_stack(&rcu.head);
1622 init_completion(&rcu.completion);
1623 /* Will wake me after RCU finished. */
1624 call_rcu_sched(&rcu.head, wakeme_after_rcu);
1625 /* Wait for it. */
1626 wait_for_completion(&rcu.completion);
1627 destroy_rcu_head_on_stack(&rcu.head);
1628} 1619}
1629EXPORT_SYMBOL_GPL(synchronize_sched); 1620EXPORT_SYMBOL_GPL(synchronize_sched);
1630 1621
@@ -1639,18 +1630,9 @@ EXPORT_SYMBOL_GPL(synchronize_sched);
1639 */ 1630 */
1640void synchronize_rcu_bh(void) 1631void synchronize_rcu_bh(void)
1641{ 1632{
1642 struct rcu_synchronize rcu;
1643
1644 if (rcu_blocking_is_gp()) 1633 if (rcu_blocking_is_gp())
1645 return; 1634 return;
1646 1635 wait_rcu_gp(call_rcu_bh);
1647 init_rcu_head_on_stack(&rcu.head);
1648 init_completion(&rcu.completion);
1649 /* Will wake me after RCU finished. */
1650 call_rcu_bh(&rcu.head, wakeme_after_rcu);
1651 /* Wait for it. */
1652 wait_for_completion(&rcu.completion);
1653 destroy_rcu_head_on_stack(&rcu.head);
1654} 1636}
1655EXPORT_SYMBOL_GPL(synchronize_rcu_bh); 1637EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
1656 1638
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 970329853dc5..43daa46bc6f2 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -656,18 +656,9 @@ EXPORT_SYMBOL_GPL(call_rcu);
656 */ 656 */
657void synchronize_rcu(void) 657void synchronize_rcu(void)
658{ 658{
659 struct rcu_synchronize rcu;
660
661 if (!rcu_scheduler_active) 659 if (!rcu_scheduler_active)
662 return; 660 return;
663 661 wait_rcu_gp(call_rcu);
664 init_rcu_head_on_stack(&rcu.head);
665 init_completion(&rcu.completion);
666 /* Will wake me after RCU finished. */
667 call_rcu(&rcu.head, wakeme_after_rcu);
668 /* Wait for it. */
669 wait_for_completion(&rcu.completion);
670 destroy_rcu_head_on_stack(&rcu.head);
671} 662}
672EXPORT_SYMBOL_GPL(synchronize_rcu); 663EXPORT_SYMBOL_GPL(synchronize_rcu);
673 664