Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
fc2c504b
Commit
fc2c504b
authored
Jul 28, 2009
by
Thomas Gleixner
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'rt/rcu' into rt/base
parents
aed9cd6a
b526aded
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
110 additions
and
0 deletions
+110
-0
include/linux/srcu.h
include/linux/srcu.h
+22
-0
init/Kconfig
init/Kconfig
+2
-0
kernel/srcu.c
kernel/srcu.c
+86
-0
No files found.
include/linux/srcu.h
View file @
fc2c504b
...
...
@@ -27,6 +27,8 @@
#ifndef _LINUX_SRCU_H
#define _LINUX_SRCU_H
#include <linux/wait.h>
struct
srcu_struct_array
{
int
c
[
2
];
};
...
...
@@ -50,4 +52,24 @@ void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp);
void
synchronize_srcu
(
struct
srcu_struct
*
sp
);
long
srcu_batches_completed
(
struct
srcu_struct
*
sp
);
/*
* fully compatible with srcu, but optimized for writers.
*/
struct
qrcu_struct
{
int
completed
;
atomic_t
ctr
[
2
];
wait_queue_head_t
wq
;
struct
mutex
mutex
;
};
int
init_qrcu_struct
(
struct
qrcu_struct
*
qp
);
int
qrcu_read_lock
(
struct
qrcu_struct
*
qp
);
void
qrcu_read_unlock
(
struct
qrcu_struct
*
qp
,
int
idx
);
void
synchronize_qrcu
(
struct
qrcu_struct
*
qp
);
static
inline
void
cleanup_qrcu_struct
(
struct
qrcu_struct
*
qp
)
{
}
#endif
init/Kconfig
View file @
fc2c504b
...
...
@@ -318,6 +318,7 @@ choice
config CLASSIC_RCU
bool "Classic RCU"
depends on !PREEMPT_RT
help
This option selects the classic RCU implementation that is
designed for best read-side performance on non-realtime
...
...
@@ -327,6 +328,7 @@ config CLASSIC_RCU
config TREE_RCU
bool "Tree-based hierarchical RCU"
depends on !PREEMPT_RT
help
This option selects the RCU implementation that is
designed for very large SMP system with hundreds or
...
...
kernel/srcu.c
View file @
fc2c504b
...
...
@@ -255,3 +255,89 @@ EXPORT_SYMBOL_GPL(srcu_read_lock);
EXPORT_SYMBOL_GPL
(
srcu_read_unlock
);
EXPORT_SYMBOL_GPL
(
synchronize_srcu
);
EXPORT_SYMBOL_GPL
(
srcu_batches_completed
);
int
init_qrcu_struct
(
struct
qrcu_struct
*
qp
)
{
qp
->
completed
=
0
;
atomic_set
(
qp
->
ctr
+
0
,
1
);
atomic_set
(
qp
->
ctr
+
1
,
0
);
init_waitqueue_head
(
&
qp
->
wq
);
mutex_init
(
&
qp
->
mutex
);
return
0
;
}
int
qrcu_read_lock
(
struct
qrcu_struct
*
qp
)
{
for
(;;)
{
int
idx
=
qp
->
completed
&
0x1
;
if
(
likely
(
atomic_inc_not_zero
(
qp
->
ctr
+
idx
)))
return
idx
;
}
}
void
qrcu_read_unlock
(
struct
qrcu_struct
*
qp
,
int
idx
)
{
if
(
atomic_dec_and_test
(
qp
->
ctr
+
idx
))
wake_up
(
&
qp
->
wq
);
}
void
synchronize_qrcu
(
struct
qrcu_struct
*
qp
)
{
int
idx
;
smp_mb
();
/* Force preceding change to happen before fastpath check. */
/*
* Fastpath: If the two counters sum to "1" at a given point in
* time, there are no readers. However, it takes two separate
* loads to sample both counters, which won't occur simultaneously.
* So we might race with a counter switch, so that we might see
* ctr[0]==0, then the counter might switch, then we might see
* ctr[1]==1 (unbeknownst to us because there is a reader still
* there). So we do a read memory barrier and recheck. If the
* same race happens again, there must have been a second counter
* switch. This second counter switch could not have happened
* until all preceding readers finished, so if the condition
* is true both times, we may safely proceed.
*
* This relies critically on the atomic increment and atomic
* decrement being seen as executing in order.
*/
if
(
atomic_read
(
&
qp
->
ctr
[
0
])
+
atomic_read
(
&
qp
->
ctr
[
1
])
<=
1
)
{
smp_rmb
();
/* Keep two checks independent. */
if
(
atomic_read
(
&
qp
->
ctr
[
0
])
+
atomic_read
(
&
qp
->
ctr
[
1
])
<=
1
)
goto
out
;
}
mutex_lock
(
&
qp
->
mutex
);
idx
=
qp
->
completed
&
0x1
;
if
(
atomic_read
(
qp
->
ctr
+
idx
)
==
1
)
goto
out_unlock
;
atomic_inc
(
qp
->
ctr
+
(
idx
^
0x1
));
/*
* Prevent subsequent decrement from being seen before previous
* increment -- such an inversion could cause the fastpath
* above to falsely conclude that there were no readers. Also,
* reduce the likelihood that qrcu_read_lock() will loop.
*/
smp_mb__after_atomic_inc
();
qp
->
completed
++
;
atomic_dec
(
qp
->
ctr
+
idx
);
__wait_event
(
qp
->
wq
,
!
atomic_read
(
qp
->
ctr
+
idx
));
out_unlock:
mutex_unlock
(
&
qp
->
mutex
);
out:
smp_mb
();
/* force subsequent free after qrcu_read_unlock(). */
}
EXPORT_SYMBOL_GPL
(
init_qrcu_struct
);
EXPORT_SYMBOL_GPL
(
qrcu_read_lock
);
EXPORT_SYMBOL_GPL
(
qrcu_read_unlock
);
EXPORT_SYMBOL_GPL
(
synchronize_qrcu
);
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