aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2009-08-22 16:56:52 -0400
committerIngo Molnar <mingo@elte.hu>2009-08-23 04:32:40 -0400
commitf41d911f8c49a5d65c86504c19e8204bb605c4fd (patch)
tree59bcd3048652ef290b3e19d2904409afd5c90eb3 /include
parenta157229cabd6dd8cfa82525fc9bf730c94cc9ac2 (diff)
rcu: Merge preemptable-RCU functionality into hierarchical RCU
Create a kernel/rcutree_plugin.h file that contains definitions for preemptable RCU (or, under the #else branch of the #ifdef, empty definitions for the classic non-preemptable semantics). These definitions fit into plugins defined in kernel/rcutree.c for this purpose. This variant of preemptable RCU uses a new algorithm whose read-side expense is roughly that of classic hierarchical RCU under CONFIG_PREEMPT. This new algorithm's update-side expense is similar to that of classic hierarchical RCU, and, in absence of read-side preemption or blocking, is exactly that of classic hierarchical RCU. Perhaps more important, this new algorithm has a much simpler implementation, saving well over 1,000 lines of code compared to mainline's implementation of preemptable RCU, which will hopefully be retired in favor of this new algorithm. The simplifications are obtained by maintaining per-task nesting state for running tasks, and using a simple lock-protected algorithm to handle accounting when tasks block within RCU read-side critical sections, making use of lessons learned while creating numerous user-level RCU implementations over the past 18 months. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: josht@linux.vnet.ibm.com Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org LKML-Reference: <12509746134003-git-send-email-> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include')
-rw-r--r--include/linux/init_task.h15
-rw-r--r--include/linux/rcupdate.h2
-rw-r--r--include/linux/rcupreempt.h4
-rw-r--r--include/linux/rcutree.h16
-rw-r--r--include/linux/sched.h37
5 files changed, 73 insertions, 1 deletions
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 7fc01b13be43..971a968831bf 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -94,6 +94,20 @@ extern struct group_info init_groups;
94# define CAP_INIT_BSET CAP_INIT_EFF_SET 94# define CAP_INIT_BSET CAP_INIT_EFF_SET
95#endif 95#endif
96 96
97#ifdef CONFIG_PREEMPT_RCU
98#define INIT_TASK_RCU_PREEMPT(tsk) \
99 .rcu_read_lock_nesting = 0, \
100 .rcu_flipctr_idx = 0,
101#elif defined(CONFIG_TREE_PREEMPT_RCU)
102#define INIT_TASK_RCU_PREEMPT(tsk) \
103 .rcu_read_lock_nesting = 0, \
104 .rcu_read_unlock_special = 0, \
105 .rcu_blocked_cpu = -1, \
106 .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry),
107#else
108#define INIT_TASK_RCU_PREEMPT(tsk)
109#endif
110
97extern struct cred init_cred; 111extern struct cred init_cred;
98 112
99#ifdef CONFIG_PERF_COUNTERS 113#ifdef CONFIG_PERF_COUNTERS
@@ -173,6 +187,7 @@ extern struct cred init_cred;
173 INIT_LOCKDEP \ 187 INIT_LOCKDEP \
174 INIT_FTRACE_GRAPH \ 188 INIT_FTRACE_GRAPH \
175 INIT_TRACE_RECURSION \ 189 INIT_TRACE_RECURSION \
190 INIT_TASK_RCU_PREEMPT(tsk) \
176} 191}
177 192
178 193
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 9d85ee19492a..26892f5e7bd8 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -66,7 +66,7 @@ extern void rcu_scheduler_starting(void);
66extern int rcu_needs_cpu(int cpu); 66extern int rcu_needs_cpu(int cpu);
67extern int rcu_scheduler_active; 67extern int rcu_scheduler_active;
68 68
69#if defined(CONFIG_TREE_RCU) 69#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
70#include <linux/rcutree.h> 70#include <linux/rcutree.h>
71#elif defined(CONFIG_PREEMPT_RCU) 71#elif defined(CONFIG_PREEMPT_RCU)
72#include <linux/rcupreempt.h> 72#include <linux/rcupreempt.h>
diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h
index aff4772fb49e..a42ab88e9210 100644
--- a/include/linux/rcupreempt.h
+++ b/include/linux/rcupreempt.h
@@ -98,6 +98,10 @@ static inline long rcu_batches_completed_bh(void)
98 return rcu_batches_completed(); 98 return rcu_batches_completed();
99} 99}
100 100
101static inline void exit_rcu(void)
102{
103}
104
101#ifdef CONFIG_RCU_TRACE 105#ifdef CONFIG_RCU_TRACE
102struct rcupreempt_trace; 106struct rcupreempt_trace;
103extern long *rcupreempt_flipctr(int cpu); 107extern long *rcupreempt_flipctr(int cpu);
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index c739d90f5e68..a89307717825 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -35,14 +35,30 @@ extern void rcu_bh_qs(int cpu);
35 35
36extern int rcu_needs_cpu(int cpu); 36extern int rcu_needs_cpu(int cpu);
37 37
38#ifdef CONFIG_TREE_PREEMPT_RCU
39
40extern void __rcu_read_lock(void);
41extern void __rcu_read_unlock(void);
42extern void exit_rcu(void);
43
44#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */
45
38static inline void __rcu_read_lock(void) 46static inline void __rcu_read_lock(void)
39{ 47{
40 preempt_disable(); 48 preempt_disable();
41} 49}
50
42static inline void __rcu_read_unlock(void) 51static inline void __rcu_read_unlock(void)
43{ 52{
44 preempt_enable(); 53 preempt_enable();
45} 54}
55
56static inline void exit_rcu(void)
57{
58}
59
60#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */
61
46static inline void __rcu_read_lock_bh(void) 62static inline void __rcu_read_lock_bh(void)
47{ 63{
48 local_bh_disable(); 64 local_bh_disable();
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 3ab08e4bb6b8..d7f98f637a2a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1210,6 +1210,13 @@ struct task_struct {
1210 int rcu_flipctr_idx; 1210 int rcu_flipctr_idx;
1211#endif /* #ifdef CONFIG_PREEMPT_RCU */ 1211#endif /* #ifdef CONFIG_PREEMPT_RCU */
1212 1212
1213#ifdef CONFIG_TREE_PREEMPT_RCU
1214 int rcu_read_lock_nesting;
1215 char rcu_read_unlock_special;
1216 int rcu_blocked_cpu;
1217 struct list_head rcu_node_entry;
1218#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
1219
1213#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) 1220#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
1214 struct sched_info sched_info; 1221 struct sched_info sched_info;
1215#endif 1222#endif
@@ -1723,6 +1730,36 @@ extern cputime_t task_gtime(struct task_struct *p);
1723#define tsk_used_math(p) ((p)->flags & PF_USED_MATH) 1730#define tsk_used_math(p) ((p)->flags & PF_USED_MATH)
1724#define used_math() tsk_used_math(current) 1731#define used_math() tsk_used_math(current)
1725 1732
1733#ifdef CONFIG_TREE_PREEMPT_RCU
1734
1735#define RCU_READ_UNLOCK_BLOCKED (1 << 0) /* blocked while in RCU read-side. */
1736#define RCU_READ_UNLOCK_NEED_QS (1 << 1) /* RCU core needs CPU response. */
1737#define RCU_READ_UNLOCK_GOT_QS (1 << 2) /* CPU has responded to RCU core. */
1738
1739static inline void rcu_copy_process(struct task_struct *p)
1740{
1741 p->rcu_read_lock_nesting = 0;
1742 p->rcu_read_unlock_special = 0;
1743 p->rcu_blocked_cpu = -1;
1744 INIT_LIST_HEAD(&p->rcu_node_entry);
1745}
1746
1747#elif defined(CONFIG_PREEMPT_RCU)
1748
1749static inline void rcu_copy_process(struct task_struct *p)
1750{
1751 p->rcu_read_lock_nesting = 0;
1752 p->rcu_flipctr_idx = 0;
1753}
1754
1755#else
1756
1757static inline void rcu_copy_process(struct task_struct *p)
1758{
1759}
1760
1761#endif
1762
1726#ifdef CONFIG_SMP 1763#ifdef CONFIG_SMP
1727extern int set_cpus_allowed_ptr(struct task_struct *p, 1764extern int set_cpus_allowed_ptr(struct task_struct *p,
1728 const struct cpumask *new_mask); 1765 const struct cpumask *new_mask);