rcu: Add a TINY_PREEMPT_RCU
RFC PATCH 1/1 rcu: Add a TINY_PREEMPT_RCU
Hello!
This patch implements a small-memory-footprint uniprocessor-only implementation of preemptible RCU. This implementation uses but a single blocked-tasks list rather than the combinatorial number used per leaf rcu_node by TREE_PREEMPT_RCU, which reduces memory consumption and greatly simplifies processing. This version also takes advantage of uniprocessor execution to accelerate grace periods in the case where there are no readers.
The general design is otherwise broadly similar to that of TREE_PREEMPT_RCU.
This version passes moderate rcutorture testing.
Signed-off-by Paul E. McKenney <[email protected]>
---
include/linux/hardirq.h | 2 include/linux/init_task.h | 10 include/linux/rcupdate.h | 3 include/linux/rcutiny.h | 126 +++++++-- include/linux/rcutree.h | 2 include/linux/sched.h | 10 init/Kconfig | 16 + kernel/Makefile | 1 kernel/rcutiny.c | 33 +- kernel/rcutiny_plugin.h | 582 +++++++++++++++++++++++++++++++++++++++++++++- 10 files changed, 717 insertions(+), 68 deletions(-)
include/linux/hardirq.h +1 -1
@@ -139,7 +139,7 @@ static inline void account_system_vtime(struct task_struct *tsk)#endif #if defined(CONFIG_NO_HZ ) -#if defined(CONFIG_TINY_RCU ) +#if defined(CONFIG_TINY_RCU ) || defined(CONFIG_TINY_PREEMPT_RCU )extern void rcu_enter_nohz (void );extern void rcu_exit_nohz (void );
include/linux/init_task.h +8 -2
@@ -82,11 +82,17 @@ extern struct group_info init_groups;# define CAP_INIT_BSET CAP_FULL_SET#ifdef CONFIG_TREE_PREEMPT_RCU +#define INIT_TASK_RCU_TREE_PREEMPT () \ + .rcu_blocked_node = NULL, +#else +#define INIT_TASK_RCU_TREE_PREEMPT (tsk) +#endif +#ifdef CONFIG_PREEMPT_RCU #define INIT_TASK_RCU_PREEMPT (tsk) \ .rcu_read_lock_nesting = 0, \ .rcu_read_unlock_special = 0, \ - .rcu_blocked_node = NULL, \ - .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), + .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), \ + INIT_TASK_RCU_TREE_PREEMPT()#else #define INIT_TASK_RCU_PREEMPT (tsk)#endif
include/linux/rcupdate.h +1 -2
@@ -58,7 +58,6 @@ struct rcu_head { };/* Exported common interfaces */ -extern void rcu_barrier (void );extern void rcu_barrier_bh (void );extern void rcu_barrier_sched (void );extern void synchronize_sched_expedited (void );
@@ -69,7 +68,7 @@ extern void rcu_init(void);#if defined(CONFIG_TREE_RCU ) || defined(CONFIG_TREE_PREEMPT_RCU )#include <linux/rcutree.h> -#elif defined(CONFIG_TINY_RCU ) +#elif defined(CONFIG_TINY_RCU ) || defined(CONFIG_TINY_PREEMPT_RCU )#include <linux/rcutiny.h> #else #error "Unknown RCU implementation specified to kernel configuration"
include/linux/rcutiny.h +89 -37
170 lines not on this page · raw message
include/linux/rcutree.h +2 -0
@@ -95,6 +95,8 @@ static inline void synchronize_rcu_bh_expedited(void)synchronize_sched_expedited (); } +extern void rcu_barrier (void ); +extern void rcu_check_callbacks (int cpu,int user);extern long rcu_batches_completed (void );
include/linux/sched.h +7 -3
@@ -1211,11 +1211,13 @@ struct task_struct {unsigned int policy;cpumask_t cpus_allowed; -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU int rcu_read_lock_nesting;char rcu_read_unlock_special; -struct rcu_node *rcu_blocked_node;struct list_head rcu_node_entry; +#endif /* #ifdef CONFIG_PREEMPT_RCU */ +#ifdef CONFIG_TREE_PREEMPT_RCU +struct rcu_node *rcu_blocked_node;#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ #if defined(CONFIG_SCHEDSTATS ) || defined(CONFIG_TASK_DELAY_ACCT )
@@ -1748,7 +1750,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *#define tsk_used_math (p) ((p)->flags & PF_USED_MATH)#define used_math () tsk_used_math(current) -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU #define RCU_READ_UNLOCK_BLOCKED (1 << 0)/* blocked while in RCU read-side. */ #define RCU_READ_UNLOCK_NEED_QS (1 << 1)/* RCU core needs CPU response. */
@@ -1757,7 +1759,9 @@ static inline void rcu_copy_process(struct task_struct *p) { p->rcu_read_lock_nesting =0 ; p->rcu_read_unlock_special =0 ; +#ifdef CONFIG_TREE_PREEMPT_RCU p->rcu_blocked_node =NULL ; +#endif INIT_LIST_HEAD (&p->rcu_node_entry); }
init/Kconfig +15 -1
@@ -343,7 +343,7 @@ config TREE_RCU smaller systems. config TREE_PREEMPT_RCU - bool "Preemptable tree-based hierarchical RCU" + bool "Preemptible tree-based hierarchical RCU" depends on PREEMPT help This option selects the RCU implementation that is
@@ -361,8 +361,22 @@ config TINY_RCU is not required. This option greatly reduces the memory footprint of RCU. +config TINY_PREEMPT_RCU + bool "Preemptible UP-only small-memory-footprint RCU" + depends on !SMP && PREEMPT + help + This option selects the RCU implementation that is designed + for real-time UP systems. This option greatly reduces the + memory footprint of RCU. + endchoice +config PREEMPT_RCU + def_bool ( TREE_PREEMPT_RCU || TINY_PREEMPT_RCU ) + help + This option enables preemptible-RCU code that is common between + the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations. + config RCU_TRACE bool "Enable tracing for RCU" depends on TREE_RCU || TREE_PREEMPT_RCU
kernel/Makefile +1 -0
@@ -85,6 +85,7 @@ obj-$(CONFIG_TREE_RCU) += rcutree.o obj-$(CONFIG_TREE_PREEMPT_RCU) += rcutree.o obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o obj-$(CONFIG_TINY_RCU) += rcutiny.o +obj-$(CONFIG_TINY_PREEMPT_RCU) += rcutiny.o obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_SYSCTL) += utsname_sysctl.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
kernel/rcutiny.c +14 -19
@@ -59,6 +59,14 @@ int rcu_scheduler_active __read_mostly;EXPORT_SYMBOL_GPL (rcu_scheduler_active);#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +/* Forward declarations for rcutiny_plugin.h. */ +static void __rcu_process_callbacks (struct rcu_ctrlblk *rcp); +static void __call_rcu (struct rcu_head *head, +void (*func)(struct rcu_head *rcu), +struct rcu_ctrlblk *rcp); + +#include "rcutiny_plugin.h" +#ifdef CONFIG_NO_HZ static long rcu_dynticks_nesting =1 ;
@@ -140,6 +148,7 @@ void rcu_check_callbacks(int cpu, int user)rcu_sched_qs (cpu); else if (!in_softirq()) rcu_bh_qs(cpu); +rcu_preempt_check_callbacks (); }/*
@@ -162,6 +171,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) *rcp->donetail =NULL ;if (rcp->curtail == rcp->donetail) rcp->curtail = &rcp->rcucblist; +rcu_preempt_remove_callbacks (rcp); rcp->donetail = &rcp->rcucblist;local_irq_restore (flags);
@@ -182,6 +192,7 @@ static void rcu_process_callbacks(struct softirq_action *unused) {__rcu_process_callbacks (&rcu_sched_ctrlblk);__rcu_process_callbacks (&rcu_bh_ctrlblk); +rcu_preempt_process_callbacks (); }/*
@@ -223,15 +234,15 @@ static void __call_rcu(struct rcu_head *head, }/* -* Post an RCU callback to be invoked after the end of an RCU grace +* Post an RCU callback to be invoked after the end of an RCU-sched grace * period. But since we have but one CPU, that would be after any * quiescent state. */ -void call_rcu (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) +void call_rcu_sched (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) {__call_rcu (head, func, &rcu_sched_ctrlblk); } -EXPORT_SYMBOL_GPL (call_rcu); +EXPORT_SYMBOL_GPL (call_rcu_sched);/* * Post an RCU bottom-half callback to be invoked after any subsequent
@@ -243,20 +254,6 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) }EXPORT_SYMBOL_GPL (call_rcu_bh); -void rcu_barrier (void ) -{ -struct rcu_synchronize rcu; - -init_rcu_head_on_stack (&rcu.head); -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); -destroy_rcu_head_on_stack (&rcu.head); -} -EXPORT_SYMBOL_GPL (rcu_barrier); -void rcu_barrier_bh (void ) {struct rcu_synchronize rcu;
@@ -289,5 +286,3 @@ void __init rcu_init(void) {open_softirq (RCU_SOFTIRQ , rcu_process_callbacks); } - -#include "rcutiny_plugin.h"
kernel/rcutiny_plugin.h +579 -3
597 lines not on this page · raw message