diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-05-27 01:14:36 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-09-29 00:36:42 -0400 |
commit | 2c42818e962e2858334bf45bfc56662b3752df34 (patch) | |
tree | 192364123c9aeeab282c53168e51eddece9d8be4 | |
parent | f039d1f1884b2fe9c13d28f59d8330f0b0518fc4 (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.h | 130 | ||||
-rw-r--r-- | include/linux/rcutiny.h | 16 | ||||
-rw-r--r-- | include/linux/rcutree.h | 2 | ||||
-rw-r--r-- | kernel/rcupdate.c | 21 | ||||
-rw-r--r-- | kernel/rcutiny.c | 28 | ||||
-rw-r--r-- | kernel/rcutiny_plugin.h | 14 | ||||
-rw-r--r-- | kernel/rcutree.c | 22 | ||||
-rw-r--r-- | kernel/rcutree_plugin.h | 11 |
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 | */ | ||
85 | extern 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 | */ | ||
113 | extern 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 | */ | ||
69 | extern void call_rcu_sched(struct rcu_head *head, | 132 | extern void call_rcu_sched(struct rcu_head *head, |
70 | void (*func)(struct rcu_head *rcu)); | 133 | void (*func)(struct rcu_head *rcu)); |
134 | |||
71 | extern void synchronize_sched(void); | 135 | extern void synchronize_sched(void); |
72 | extern void rcu_barrier_bh(void); | ||
73 | extern void rcu_barrier_sched(void); | ||
74 | 136 | ||
75 | static inline void __rcu_read_lock_bh(void) | 137 | static 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 | |||
213 | typedef void call_rcu_func_t(struct rcu_head *head, | ||
214 | void (*func)(struct rcu_head *head)); | ||
215 | void 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 | |||
728 | struct rcu_synchronize { | ||
729 | struct rcu_head head; | ||
730 | struct completion completion; | ||
731 | }; | ||
732 | |||
733 | extern 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 | */ | ||
750 | extern 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 | */ | ||
778 | extern 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 | ||
34 | static inline void rcu_barrier_bh(void) | ||
35 | { | ||
36 | wait_rcu_gp(call_rcu_bh); | ||
37 | } | ||
38 | |||
39 | static 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 | ||
36 | static inline void synchronize_rcu_expedited(void) | 46 | static 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 | ||
48 | void rcu_barrier(void); | ||
49 | void synchronize_rcu_expedited(void); | 58 | void synchronize_rcu_expedited(void); |
50 | 59 | ||
60 | static 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 | ||
53 | static inline void synchronize_rcu_bh(void) | 67 | static 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 | ||
69 | extern void rcu_barrier(void); | 69 | extern void rcu_barrier(void); |
70 | extern void rcu_barrier_bh(void); | ||
71 | extern void rcu_barrier_sched(void); | ||
70 | 72 | ||
71 | extern unsigned long rcutorture_testseq; | 73 | extern unsigned long rcutorture_testseq; |
72 | extern unsigned long rcutorture_vernum; | 74 | extern 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 | ||
97 | struct 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 | */ |
101 | void wakeme_after_rcu(struct rcu_head *head) | 106 | static 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 | ||
114 | void 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 | } | ||
126 | EXPORT_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 | } |
282 | EXPORT_SYMBOL_GPL(call_rcu_bh); | 282 | EXPORT_SYMBOL_GPL(call_rcu_bh); |
283 | 283 | ||
284 | void 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 | } | ||
296 | EXPORT_SYMBOL_GPL(rcu_barrier_bh); | ||
297 | |||
298 | void 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 | } | ||
310 | EXPORT_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 | } |
698 | EXPORT_SYMBOL_GPL(call_rcu); | 698 | EXPORT_SYMBOL_GPL(call_rcu); |
699 | 699 | ||
700 | void 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 | } | ||
712 | EXPORT_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 | */ |
1614 | void synchronize_sched(void) | 1614 | void 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 | } |
1629 | EXPORT_SYMBOL_GPL(synchronize_sched); | 1620 | EXPORT_SYMBOL_GPL(synchronize_sched); |
1630 | 1621 | ||
@@ -1639,18 +1630,9 @@ EXPORT_SYMBOL_GPL(synchronize_sched); | |||
1639 | */ | 1630 | */ |
1640 | void synchronize_rcu_bh(void) | 1631 | void 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 | } |
1655 | EXPORT_SYMBOL_GPL(synchronize_rcu_bh); | 1637 | EXPORT_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 | */ |
657 | void synchronize_rcu(void) | 657 | void 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 | } |
672 | EXPORT_SYMBOL_GPL(synchronize_rcu); | 663 | EXPORT_SYMBOL_GPL(synchronize_rcu); |
673 | 664 | ||