Read-Copy Update [new & shiny]
Subsystems (4)
PATCH 1/1 Read-Copy Update [new & shiny]
At OLS, we presented some data on latency and overhead for different approaches to RCU. After some discussions with Andrea and Rusty, it seemed that it is a good idea to use this and come out with a patch. So here is a new patch. The main features are -
1. Based on rcu_poll which is already in production kernels (SuSE) and has low latency of grace period.
2. In order to reduce overheads, I added per-CPU queue support to it.
3. Works in preemptive kernel environment by either requiring the use of rcu_read_lock/unlock or using call_rcu_preempt().
4. synchronize_kernel() uses call_rcu_preempt() which requires no disabling of preemption on read-side making it useful for things like CPU hotplug.
5. Added docbook tags in headers.
Future plans are -
1. More overhead and latency measurements and tweaking around if necessary. But for infrequent things like CPU hotplug, this is not important.
2. Cleanups/bugfixes etc.
Comments, suggestions and even flames are welcome.
Thanks
Signature · 2 lines
Dipankar Sarma <[email protected]> http://lse.sourceforge.net Linux Technology Center, IBM Software Lab, Bangalore, India.
include/linux/init_task.h +1 -0
@@ -79,6 +79,7 @@ blocked: {{0}}, \ alloc_lock: SPIN_LOCK_UNLOCKED, \ journal_info: NULL, \ + cpu_preempt_cntr: NULL, \ }
include/linux/rcupdate.h +85 -0
85 lines not on this page · raw message
include/linux/sched.h +51 -0
81 lines not on this page · raw message
init/main.c +2 -0
@@ -28,6 +28,7 @@#include <linux/bootmem.h> #include <linux/tty.h> #include <linux/percpu.h> +#include <linux/rcupdate.h> #include <asm/io.h> #include <asm/bugs.h>
@@ -346,6 +347,7 @@printk ("Kernel command line: %s\n" , saved_command_line);parse_options (command_line);trap_init (); +rcu_init ();init_IRQ ();sched_init ();softirq_init ();
kernel/Makefile +2 -2
@@ -10,12 +10,12 @@ O_TARGET := kernel.o export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \ - printk.o platform.o suspend.o + printk.o platform.o suspend.o rcupdate.o obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o time.o softirq.o resource.o \ sysctl.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o context.o futex.o platform.o + signal.o sys.o kmod.o context.o futex.o platform.o rcupdate.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o
kernel/exit.c +1 -0
@@ -556,6 +556,7 @@ tsk->exit_code = code;exit_notify (); +rcu_preempt_put ();schedule ();BUG ();/*
kernel/fork.c +1 -0
@@ -118,6 +118,7 @@ tsk->thread_info = ti; ti->task = tsk;atomic_set (&tsk->usage,1 ); + tsk->cpu_preempt_cntr =NULL ;return tsk; }
kernel/rcupdate.c +293 -0
293 lines not on this page · raw message
kernel/sched.c +40 -0
@@ -26,6 +26,7 @@#include <linux/interrupt.h> #include <linux/completion.h> #include <linux/kernel_stat.h> +#include <linux/percpu.h> /* * Convert user-nice values [ -20 ... 0 ... 19 ]
@@ -146,12 +147,30 @@ static struct runqueue runqueues[NR_CPUS] __cacheline_aligned; +long cpu_quiescent __per_cpu_data; +#define cpu_rq (cpu) (runqueues + (cpu))#define this_rq () cpu_rq(smp_processor_id())#define task_rq (p) cpu_rq(task_cpu(p))#define cpu_curr (cpu) (cpu_rq(cpu)->curr)#define rt_task (p) ((p)->prio < MAX_RT_PRIO) +#ifdef CONFIG_PREEMPT +atomic_t rcu_preempt_cntr[2] __per_cpu_data; +atomic_t *curr_preempt_cntr __per_cpu_data; +atomic_t *next_preempt_cntr __per_cpu_data; +static inline void rcu_init_preempt_cntr (int cpu) +{ + +atomic_set (&per_cpu (rcu_preempt_cntr[0 ], cpu),0 ); +atomic_set (&per_cpu (rcu_preempt_cntr[1 ], cpu),0 ); +per_cpu (curr_preempt_cntr, cpu) = + &per_cpu (rcu_preempt_cntr[1 ], cpu); +per_cpu (next_preempt_cntr, cpu) = + &per_cpu (rcu_preempt_cntr[0 ], cpu); +} +#endif +/* * task_rq_lock - lock the runqueue a given task resides on and disable * interrupts. Note the ordering: we can safely lookup the task_rq without
@@ -725,6 +744,10 @@runqueue_t *rq =this_rq ();task_t *p = current; +if (user_tick || + (!in_softirq () &&local_irq_count (cpu) <=1 &&idle_cpu (cpu))) +per_cpu (cpu_quiescent, cpu)++; +if (p == rq->idle) {if (local_bh_count (cpu) ||local_irq_count (cpu) >1 ) kstat.per_cpu_system[cpu] += system;
@@ -826,6 +849,8 @@*/ if (unlikely (preempt_get_count () &PREEMPT_ACTIVE )) goto pick_next_task; +else +rcu_preempt_put ();switch (prev->state) {case TASK_INTERRUPTIBLE :
@@ -868,6 +893,7 @@ switch_tasks:prefetch (next);clear_tsk_need_resched (prev); +per_cpu (cpu_quiescent, prev->thread_info->cpu)++;if (likely (prev != next)) { rq->nr_switches++;
@@ -903,6 +929,7 @@ need_resched: ti->preempt_count =PREEMPT_ACTIVE ; +rcu_preempt_get ();schedule (); ti->preempt_count =0 ;
@@ -1105,6 +1132,18 @@task_rq_unlock (rq, &flags); } +void force_cpu_reschedule (int cpu) +{ +struct runqueue *rq; + + rq =cpu_rq (cpu); +/* Need to save flags if someday called from irq context */ +spin_lock_irq (&rq->lock); +resched_task (rq->curr); +spin_unlock_irq (&rq->lock); +} + +#ifndef __alpha__/*
@@ -1669,6 +1708,7 @@ rq->expired = rq->arrays +1 ;spin_lock_init (&rq->lock);INIT_LIST_HEAD (&rq->migration_queue); +rcu_init_preempt_cntr (i);for (j =0 ; j <2 ; j++) { array = rq->arrays + j;