Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+113 -131
+73 -57
include/linux/rcupdate.h
··· 66 66 #define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b)) 67 67 68 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 132 extern void call_rcu_sched(struct rcu_head *head, 70 133 void (*func)(struct rcu_head *rcu)); 134 + 71 135 extern void synchronize_sched(void); 72 - extern void rcu_barrier_bh(void); 73 - extern void rcu_barrier_sched(void); 74 136 75 137 static inline void __rcu_read_lock_bh(void) 76 138 { ··· 204 142 } 205 143 206 144 #endif /* #else #ifdef CONFIG_NO_HZ */ 145 + 146 + /* 147 + * Infrastructure to implement the synchronize_() primitives in 148 + * TREE_RCU and rcu_barrier_() primitives in TINY_RCU. 149 + */ 150 + 151 + typedef void call_rcu_func_t(struct rcu_head *head, 152 + void (*func)(struct rcu_head *head)); 153 + void wait_rcu_gp(call_rcu_func_t crf); 207 154 208 155 #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) 209 156 #include <linux/rcutree.h> ··· 793 722 */ 794 723 #define RCU_INIT_POINTER(p, v) \ 795 724 p = (typeof(*v) __force __rcu *)(v) 796 - 797 - /* Infrastructure to implement the synchronize_() primitives. */ 798 - 799 - struct rcu_synchronize { 800 - struct rcu_head head; 801 - struct completion completion; 802 - }; 803 - 804 - extern void wakeme_after_rcu(struct rcu_head *head); 805 - 806 - #ifdef CONFIG_PREEMPT_RCU 807 - 808 - /** 809 - * call_rcu() - Queue an RCU callback for invocation after a grace period. 810 - * @head: structure to be used for queueing the RCU updates. 811 - * @func: actual callback function to be invoked after the grace period 812 - * 813 - * The callback function will be invoked some time after a full grace 814 - * period elapses, in other words after all pre-existing RCU read-side 815 - * critical sections have completed. However, the callback function 816 - * might well execute concurrently with RCU read-side critical sections 817 - * that started after call_rcu() was invoked. RCU read-side critical 818 - * sections are delimited by rcu_read_lock() and rcu_read_unlock(), 819 - * and may be nested. 820 - */ 821 - extern void call_rcu(struct rcu_head *head, 822 - void (*func)(struct rcu_head *head)); 823 - 824 - #else /* #ifdef CONFIG_PREEMPT_RCU */ 825 - 826 - /* In classic RCU, call_rcu() is just call_rcu_sched(). */ 827 - #define call_rcu call_rcu_sched 828 - 829 - #endif /* #else #ifdef CONFIG_PREEMPT_RCU */ 830 - 831 - /** 832 - * call_rcu_bh() - Queue an RCU for invocation after a quicker grace period. 833 - * @head: structure to be used for queueing the RCU updates. 834 - * @func: actual callback function to be invoked after the grace period 835 - * 836 - * The callback function will be invoked some time after a full grace 837 - * period elapses, in other words after all currently executing RCU 838 - * read-side critical sections have completed. call_rcu_bh() assumes 839 - * that the read-side critical sections end on completion of a softirq 840 - * handler. This means that read-side critical sections in process 841 - * context must not be interrupted by softirqs. This interface is to be 842 - * used when most of the read-side critical sections are in softirq context. 843 - * RCU read-side critical sections are delimited by : 844 - * - rcu_read_lock() and rcu_read_unlock(), if in interrupt context. 845 - * OR 846 - * - rcu_read_lock_bh() and rcu_read_unlock_bh(), if in process context. 847 - * These may be nested. 848 - */ 849 - extern void call_rcu_bh(struct rcu_head *head, 850 - void (*func)(struct rcu_head *head)); 851 725 852 726 /* 853 727 * debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally
+15 -1
include/linux/rcutiny.h
··· 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 44 #ifdef CONFIG_TINY_RCU 35 45 36 46 static inline void synchronize_rcu_expedited(void) ··· 55 45 56 46 #else /* #ifdef CONFIG_TINY_RCU */ 57 47 58 - void rcu_barrier(void); 59 48 void synchronize_rcu_expedited(void); 49 + 50 + static inline void rcu_barrier(void) 51 + { 52 + wait_rcu_gp(call_rcu); 53 + } 60 54 61 55 #endif /* #else #ifdef CONFIG_TINY_RCU */ 62 56
+2
include/linux/rcutree.h
··· 67 67 } 68 68 69 69 extern void rcu_barrier(void); 70 + extern void rcu_barrier_bh(void); 71 + extern void rcu_barrier_sched(void); 70 72 71 73 extern unsigned long rcutorture_testseq; 72 74 extern unsigned long rcutorture_vernum;
+20 -1
kernel/rcupdate.c
··· 94 94 95 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 103 * Awaken the corresponding synchronize_rcu() instance now that a 99 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 108 struct rcu_synchronize *rcu; 104 109 105 110 rcu = container_of(head, struct rcu_synchronize, head); 106 111 complete(&rcu->completion); 107 112 } 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); 108 127 109 128 #ifdef CONFIG_PROVE_RCU 110 129 /*
-28
kernel/rcutiny.c
··· 281 281 } 282 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 285 * Spawn the kthread that invokes RCU callbacks. 314 286 */
-14
kernel/rcutiny_plugin.h
··· 697 697 } 698 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 701 * synchronize_rcu - wait until a grace period has elapsed. 716 702 *
+2 -20
kernel/rcutree.c
··· 1613 1613 */ 1614 1614 void synchronize_sched(void) 1615 1615 { 1616 - struct rcu_synchronize rcu; 1617 - 1618 1616 if (rcu_blocking_is_gp()) 1619 1617 return; 1620 - 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); 1618 + wait_rcu_gp(call_rcu_sched); 1628 1619 } 1629 1620 EXPORT_SYMBOL_GPL(synchronize_sched); 1630 1621 ··· 1630 1639 */ 1631 1640 void synchronize_rcu_bh(void) 1632 1641 { 1633 - struct rcu_synchronize rcu; 1634 - 1635 1642 if (rcu_blocking_is_gp()) 1636 1643 return; 1637 - 1638 - init_rcu_head_on_stack(&rcu.head); 1639 - init_completion(&rcu.completion); 1640 - /* Will wake me after RCU finished. */ 1641 - call_rcu_bh(&rcu.head, wakeme_after_rcu); 1642 - /* Wait for it. */ 1643 - wait_for_completion(&rcu.completion); 1644 - destroy_rcu_head_on_stack(&rcu.head); 1644 + wait_rcu_gp(call_rcu_bh); 1645 1645 } 1646 1646 EXPORT_SYMBOL_GPL(synchronize_rcu_bh); 1647 1647
+1 -10
kernel/rcutree_plugin.h
··· 656 656 */ 657 657 void synchronize_rcu(void) 658 658 { 659 - struct rcu_synchronize rcu; 660 - 661 659 if (!rcu_scheduler_active) 662 660 return; 663 - 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); 661 + wait_rcu_gp(call_rcu); 671 662 } 672 663 EXPORT_SYMBOL_GPL(synchronize_rcu); 673 664