Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
2a4a59c1
Commit
2a4a59c1
authored
Oct 15, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge RCU / oprofile clashes
parents
246f38c2
1477a825
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
386 additions
and
2 deletions
+386
-2
include/linux/rcupdate.h
include/linux/rcupdate.h
+134
-0
init/main.c
init/main.c
+2
-0
kernel/Makefile
kernel/Makefile
+3
-2
kernel/rcupdate.c
kernel/rcupdate.c
+242
-0
kernel/sched.c
kernel/sched.c
+5
-0
No files found.
include/linux/rcupdate.h
0 → 100644
View file @
2a4a59c1
/*
* Read-Copy Update mechanism for mutual exclusion
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (c) IBM Corporation, 2001
*
* Author: Dipankar Sarma <dipankar@in.ibm.com>
*
* Based on the original work by Paul McKenney <paul.mckenney@us.ibm.com>
* and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
* Papers:
* http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
* http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
*
* For detailed explanation of Read-Copy Update mechanism see -
* http://lse.sourceforge.net/locking/rcupdate.html
*
*/
#ifndef __LINUX_RCUPDATE_H
#define __LINUX_RCUPDATE_H
#ifdef __KERNEL__
#include <linux/cache.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/threads.h>
/**
* struct rcu_head - callback structure for use with RCU
* @list: list_head to queue the update requests
* @func: actual update function to call after the grace period.
* @arg: argument to be passed to the actual update function.
*/
struct
rcu_head
{
struct
list_head
list
;
void
(
*
func
)(
void
*
obj
);
void
*
arg
;
};
#define RCU_HEAD_INIT(head) \
{ list: LIST_HEAD_INIT(head.list), func: NULL, arg: NULL }
#define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT(head)
#define INIT_RCU_HEAD(ptr) do { \
INIT_LIST_HEAD(&(ptr)->list); (ptr)->func = NULL; (ptr)->arg = NULL; \
} while (0)
/* Control variables for rcupdate callback mechanism. */
struct
rcu_ctrlblk
{
spinlock_t
mutex
;
/* Guard this struct */
long
curbatch
;
/* Current batch number. */
long
maxbatch
;
/* Max requested batch number. */
unsigned
long
rcu_cpu_mask
;
/* CPUs that need to switch in order */
/* for current batch to proceed. */
};
/* Is batch a before batch b ? */
static
inline
int
rcu_batch_before
(
long
a
,
long
b
)
{
return
(
a
-
b
)
<
0
;
}
/* Is batch a after batch b ? */
static
inline
int
rcu_batch_after
(
long
a
,
long
b
)
{
return
(
a
-
b
)
>
0
;
}
/*
* Per-CPU data for Read-Copy UPdate.
* nxtlist - new callbacks are added here
* curlist - current batch for which quiescent cycle started if any
*/
struct
rcu_data
{
long
qsctr
;
/* User-mode/idle loop etc. */
long
last_qsctr
;
/* value of qsctr at beginning */
/* of rcu grace period */
long
batch
;
/* Batch # for current RCU batch */
struct
list_head
nxtlist
;
struct
list_head
curlist
;
}
____cacheline_aligned_in_smp
;
extern
struct
rcu_data
rcu_data
[
NR_CPUS
];
extern
struct
rcu_ctrlblk
rcu_ctrlblk
;
#define RCU_qsctr(cpu) (rcu_data[(cpu)].qsctr)
#define RCU_last_qsctr(cpu) (rcu_data[(cpu)].last_qsctr)
#define RCU_batch(cpu) (rcu_data[(cpu)].batch)
#define RCU_nxtlist(cpu) (rcu_data[(cpu)].nxtlist)
#define RCU_curlist(cpu) (rcu_data[(cpu)].curlist)
#define RCU_QSCTR_INVALID 0
static
inline
int
rcu_pending
(
int
cpu
)
{
if
((
!
list_empty
(
&
RCU_curlist
(
cpu
))
&&
rcu_batch_before
(
RCU_batch
(
cpu
),
rcu_ctrlblk
.
curbatch
))
||
(
list_empty
(
&
RCU_curlist
(
cpu
))
&&
!
list_empty
(
&
RCU_nxtlist
(
cpu
)))
||
test_bit
(
cpu
,
&
rcu_ctrlblk
.
rcu_cpu_mask
))
return
1
;
else
return
0
;
}
#define rcu_read_lock() preempt_disable()
#define rcu_read_unlock() preempt_enable()
extern
void
rcu_init
(
void
);
extern
void
rcu_check_callbacks
(
int
cpu
,
int
user
);
/* Exported interfaces */
extern
void
FASTCALL
(
call_rcu
(
struct
rcu_head
*
head
,
void
(
*
func
)(
void
*
arg
),
void
*
arg
));
extern
void
synchronize_kernel
(
void
);
#endif
/* __KERNEL__ */
#endif
/* __LINUX_RCUPDATE_H */
init/main.c
View file @
2a4a59c1
...
...
@@ -31,6 +31,7 @@
#include <linux/security.h>
#include <linux/workqueue.h>
#include <linux/profile.h>
#include <linux/rcupdate.h>
#include <asm/io.h>
#include <asm/bugs.h>
...
...
@@ -390,6 +391,7 @@ asmlinkage void __init start_kernel(void)
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
View file @
2a4a59c1
...
...
@@ -4,12 +4,13 @@
export-objs
=
signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o
\
printk.o platform.o suspend.o dma.o module.o cpufreq.o
\
profile.o
profile.o
rcupdate.o
obj-y
=
sched.o fork.o exec_domain.o panic.o printk.o profile.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 workqueue.o futex.o platform.o pid.o
signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o
\
rcupdate.o
obj-$(CONFIG_GENERIC_ISA_DMA)
+=
dma.o
obj-$(CONFIG_SMP)
+=
cpu.o
...
...
kernel/rcupdate.c
0 → 100644
View file @
2a4a59c1
/*
* Read-Copy Update mechanism for mutual exclusion
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (c) IBM Corporation, 2001
*
* Author: Dipankar Sarma <dipankar@in.ibm.com>
*
* Based on the original work by Paul McKenney <paul.mckenney@us.ibm.com>
* and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
* Papers:
* http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
* http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
*
* For detailed explanation of Read-Copy Update mechanism see -
* http://lse.sourceforge.net/locking/rcupdate.html
*
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/atomic.h>
#include <asm/bitops.h>
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/percpu.h>
#include <linux/rcupdate.h>
/* Definition for rcupdate control block. */
struct
rcu_ctrlblk
rcu_ctrlblk
=
{
.
mutex
=
SPIN_LOCK_UNLOCKED
,
.
curbatch
=
1
,
.
maxbatch
=
1
,
.
rcu_cpu_mask
=
0
};
struct
rcu_data
rcu_data
[
NR_CPUS
]
__cacheline_aligned
;
/* Fake initialization required by compiler */
static
DEFINE_PER_CPU
(
struct
tasklet_struct
,
rcu_tasklet
)
=
{
NULL
};
#define RCU_tasklet(cpu) (per_cpu(rcu_tasklet, cpu))
/**
* call_rcu - Queue an RCU update request.
* @head: structure to be used for queueing the RCU updates.
* @func: actual update function to be invoked after the grace period
* @arg: argument to be passed to the update function
*
* The update function will be invoked as soon as all CPUs have performed
* a context switch or been seen in the idle loop or in a user process.
* The read-side of critical section that use call_rcu() for updation must
* be protected by rcu_read_lock()/rcu_read_unlock().
*/
void
call_rcu
(
struct
rcu_head
*
head
,
void
(
*
func
)(
void
*
arg
),
void
*
arg
)
{
int
cpu
;
unsigned
long
flags
;
head
->
func
=
func
;
head
->
arg
=
arg
;
local_irq_save
(
flags
);
cpu
=
smp_processor_id
();
list_add_tail
(
&
head
->
list
,
&
RCU_nxtlist
(
cpu
));
local_irq_restore
(
flags
);
}
/*
* Invoke the completed RCU callbacks. They are expected to be in
* a per-cpu list.
*/
static
void
rcu_do_batch
(
struct
list_head
*
list
)
{
struct
list_head
*
entry
;
struct
rcu_head
*
head
;
while
(
!
list_empty
(
list
))
{
entry
=
list
->
next
;
list_del
(
entry
);
head
=
list_entry
(
entry
,
struct
rcu_head
,
list
);
head
->
func
(
head
->
arg
);
}
}
/*
* Register a new batch of callbacks, and start it up if there is currently no
* active batch and the batch to be registered has not already occurred.
* Caller must hold the rcu_ctrlblk lock.
*/
static
void
rcu_start_batch
(
long
newbatch
)
{
if
(
rcu_batch_before
(
rcu_ctrlblk
.
maxbatch
,
newbatch
))
{
rcu_ctrlblk
.
maxbatch
=
newbatch
;
}
if
(
rcu_batch_before
(
rcu_ctrlblk
.
maxbatch
,
rcu_ctrlblk
.
curbatch
)
||
(
rcu_ctrlblk
.
rcu_cpu_mask
!=
0
))
{
return
;
}
rcu_ctrlblk
.
rcu_cpu_mask
=
cpu_online_map
;
}
/*
* Check if the cpu has gone through a quiescent state (say context
* switch). If so and if it already hasn't done so in this RCU
* quiescent cycle, then indicate that it has done so.
*/
static
void
rcu_check_quiescent_state
(
void
)
{
int
cpu
=
smp_processor_id
();
if
(
!
test_bit
(
cpu
,
&
rcu_ctrlblk
.
rcu_cpu_mask
))
{
return
;
}
/*
* Races with local timer interrupt - in the worst case
* we may miss one quiescent state of that CPU. That is
* tolerable. So no need to disable interrupts.
*/
if
(
RCU_last_qsctr
(
cpu
)
==
RCU_QSCTR_INVALID
)
{
RCU_last_qsctr
(
cpu
)
=
RCU_qsctr
(
cpu
);
return
;
}
if
(
RCU_qsctr
(
cpu
)
==
RCU_last_qsctr
(
cpu
))
{
return
;
}
spin_lock
(
&
rcu_ctrlblk
.
mutex
);
if
(
!
test_bit
(
cpu
,
&
rcu_ctrlblk
.
rcu_cpu_mask
))
{
spin_unlock
(
&
rcu_ctrlblk
.
mutex
);
return
;
}
clear_bit
(
cpu
,
&
rcu_ctrlblk
.
rcu_cpu_mask
);
RCU_last_qsctr
(
cpu
)
=
RCU_QSCTR_INVALID
;
if
(
rcu_ctrlblk
.
rcu_cpu_mask
!=
0
)
{
spin_unlock
(
&
rcu_ctrlblk
.
mutex
);
return
;
}
rcu_ctrlblk
.
curbatch
++
;
rcu_start_batch
(
rcu_ctrlblk
.
maxbatch
);
spin_unlock
(
&
rcu_ctrlblk
.
mutex
);
}
/*
* This does the RCU processing work from tasklet context.
*/
static
void
rcu_process_callbacks
(
unsigned
long
unused
)
{
int
cpu
=
smp_processor_id
();
LIST_HEAD
(
list
);
if
(
!
list_empty
(
&
RCU_curlist
(
cpu
))
&&
rcu_batch_after
(
rcu_ctrlblk
.
curbatch
,
RCU_batch
(
cpu
)))
{
list_splice
(
&
RCU_curlist
(
cpu
),
&
list
);
INIT_LIST_HEAD
(
&
RCU_curlist
(
cpu
));
}
local_irq_disable
();
if
(
!
list_empty
(
&
RCU_nxtlist
(
cpu
))
&&
list_empty
(
&
RCU_curlist
(
cpu
)))
{
list_splice
(
&
RCU_nxtlist
(
cpu
),
&
RCU_curlist
(
cpu
));
INIT_LIST_HEAD
(
&
RCU_nxtlist
(
cpu
));
local_irq_enable
();
/*
* start the next batch of callbacks
*/
spin_lock
(
&
rcu_ctrlblk
.
mutex
);
RCU_batch
(
cpu
)
=
rcu_ctrlblk
.
curbatch
+
1
;
rcu_start_batch
(
RCU_batch
(
cpu
));
spin_unlock
(
&
rcu_ctrlblk
.
mutex
);
}
else
{
local_irq_enable
();
}
rcu_check_quiescent_state
();
if
(
!
list_empty
(
&
list
))
rcu_do_batch
(
&
list
);
}
void
rcu_check_callbacks
(
int
cpu
,
int
user
)
{
if
(
user
||
(
idle_cpu
(
cpu
)
&&
!
in_softirq
()
&&
hardirq_count
()
<=
1
))
RCU_qsctr
(
cpu
)
++
;
tasklet_schedule
(
&
RCU_tasklet
(
cpu
));
}
/*
* Initializes rcu mechanism. Assumed to be called early.
* That is before local timer(SMP) or jiffie timer (uniproc) is setup.
* Note that rcu_qsctr and friends are implicitly
* initialized due to the choice of ``0'' for RCU_CTR_INVALID.
*/
void
__init
rcu_init
(
void
)
{
int
i
;
memset
(
&
rcu_data
[
0
],
0
,
sizeof
(
rcu_data
));
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
tasklet_init
(
&
RCU_tasklet
(
i
),
rcu_process_callbacks
,
0UL
);
INIT_LIST_HEAD
(
&
RCU_nxtlist
(
i
));
INIT_LIST_HEAD
(
&
RCU_curlist
(
i
));
}
}
/* Because of FASTCALL declaration of complete, we use this wrapper */
static
void
wakeme_after_rcu
(
void
*
completion
)
{
complete
(
completion
);
}
/**
* synchronize-kernel - wait until all the CPUs have gone
* through a "quiescent" state. It may sleep.
*/
void
synchronize_kernel
(
void
)
{
struct
rcu_head
rcu
;
DECLARE_COMPLETION
(
completion
);
/* Will wake me after RCU finished */
call_rcu
(
&
rcu
,
wakeme_after_rcu
,
&
completion
);
/* Wait for it */
wait_for_completion
(
&
completion
);
}
EXPORT_SYMBOL
(
call_rcu
);
EXPORT_SYMBOL
(
synchronize_kernel
);
kernel/sched.c
View file @
2a4a59c1
...
...
@@ -31,6 +31,7 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/rcupdate.h>
/*
* Convert user-nice values [ -20 ... 0 ... 19 ]
...
...
@@ -865,6 +866,9 @@ void scheduler_tick(int user_ticks, int sys_ticks)
runqueue_t
*
rq
=
this_rq
();
task_t
*
p
=
current
;
if
(
rcu_pending
(
cpu
))
rcu_check_callbacks
(
cpu
,
user_ticks
);
if
(
p
==
rq
->
idle
)
{
/* note: this timer irq context must be accounted for as well */
if
(
irq_count
()
-
HARDIRQ_OFFSET
>=
SOFTIRQ_OFFSET
)
...
...
@@ -1023,6 +1027,7 @@ asmlinkage void schedule(void)
switch_tasks:
prefetch
(
next
);
clear_tsk_need_resched
(
prev
);
RCU_qsctr
(
prev
->
thread_info
->
cpu
)
++
;
if
(
likely
(
prev
!=
next
))
{
rq
->
nr_switches
++
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment