Hello!
This series provides documentation updates:
1. Update Tasks RCU and Tasks Rude RCU description in
Requirements.rst.
2. Clarify rcu_assign_pointer() and rcu_dereference() ordering.
Thanx, Paul
------------------------------------------------------------------------
Design/Requirements/Requirements.rst | 16 ++++++++++++++++
whatisRCU.rst | 30 +++++++++++++++++++-----------
2 files changed, 35 insertions(+), 11 deletions(-)
This commit adds more detail to the Tasks RCU and Tasks Rude RCU
descriptions in Requirements.rst. While in the area, add Tasks Trace
RCU to the Tasks-RCU table of contents.
Reported-by: Sebastian Andrzej Siewior <[email protected]>
Signed-off-by: Paul E. McKenney <[email protected]>
---
.../RCU/Design/Requirements/Requirements.rst | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/Documentation/RCU/Design/Requirements/Requirements.rst b/Documentation/RCU/Design/Requirements/Requirements.rst
index cccafdaa1f849..f511476b45506 100644
--- a/Documentation/RCU/Design/Requirements/Requirements.rst
+++ b/Documentation/RCU/Design/Requirements/Requirements.rst
@@ -2357,6 +2357,7 @@ section.
#. `Sched Flavor (Historical)`_
#. `Sleepable RCU`_
#. `Tasks RCU`_
+#. `Tasks Trace RCU`_
Bottom-Half Flavor (Historical)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2610,6 +2611,16 @@ critical sections that are delimited by voluntary context switches, that
is, calls to schedule(), cond_resched(), and
synchronize_rcu_tasks(). In addition, transitions to and from
userspace execution also delimit tasks-RCU read-side critical sections.
+Idle tasks are ignored by Tasks RCU, and Tasks Rude RCU may be used to
+interact with them.
+
+Note well that involuntary context switches are *not* Tasks-RCU quiescent
+states. After all, in preemptible kernels, a task executing code in a
+trampoline might be preempted. In this case, the Tasks-RCU grace period
+clearly cannot end until that task resumes and its execution leaves that
+trampoline. This means, among other things, that cond_resched() does
+not provide a Tasks RCU quiescent state. (Instead, use rcu_softirq_qs()
+from softirq or rcu_tasks_classic_qs() otherwise.)
The tasks-RCU API is quite compact, consisting only of
call_rcu_tasks(), synchronize_rcu_tasks(), and
@@ -2632,6 +2643,11 @@ moniker. And this operation is considered to be quite rude by real-time
workloads that don't want their ``nohz_full`` CPUs receiving IPIs and
by battery-powered systems that don't want their idle CPUs to be awakened.
+Once kernel entry/exit and deep-idle functions have been properly tagged
+``noinstr``, Tasks RCU can start paying attention to idle tasks (except
+those that are idle from RCU's perspective) and then Tasks Rude RCU can
+be removed from the kernel.
+
The tasks-rude-RCU API is also reader-marking-free and thus quite compact,
consisting of call_rcu_tasks_rude(), synchronize_rcu_tasks_rude(),
and rcu_barrier_tasks_rude().
--
2.40.1
This commit expands on the ordering properties of rcu_assign_pointer()
and rcu_dereference(), outlining their constraints on CPUs and compilers.
Reported-by: Rao Shoaib <[email protected]>
Signed-off-by: Paul E. McKenney <[email protected]>
---
Documentation/RCU/whatisRCU.rst | 30 +++++++++++++++++++-----------
1 file changed, 19 insertions(+), 11 deletions(-)
diff --git a/Documentation/RCU/whatisRCU.rst b/Documentation/RCU/whatisRCU.rst
index 94838c65c7d97..d585a5490aeec 100644
--- a/Documentation/RCU/whatisRCU.rst
+++ b/Documentation/RCU/whatisRCU.rst
@@ -250,21 +250,25 @@ rcu_assign_pointer()
^^^^^^^^^^^^^^^^^^^^
void rcu_assign_pointer(p, typeof(p) v);
- Yes, rcu_assign_pointer() **is** implemented as a macro, though it
- would be cool to be able to declare a function in this manner.
- (Compiler experts will no doubt disagree.)
+ Yes, rcu_assign_pointer() **is** implemented as a macro, though
+ it would be cool to be able to declare a function in this manner.
+ (And there has been some discussion of adding overloaded functions
+ to the C language, so who knows?)
The updater uses this spatial macro to assign a new value to an
RCU-protected pointer, in order to safely communicate the change
in value from the updater to the reader. This is a spatial (as
opposed to temporal) macro. It does not evaluate to an rvalue,
- but it does execute any memory-barrier instructions required
- for a given CPU architecture. Its ordering properties are that
- of a store-release operation.
-
- Perhaps just as important, it serves to document (1) which
- pointers are protected by RCU and (2) the point at which a
- given structure becomes accessible to other CPUs. That said,
+ but it does provide any compiler directives and memory-barrier
+ instructions required for a given compile or CPU architecture.
+ Its ordering properties are that of a store-release operation,
+ that is, any prior loads and stores required to initialize the
+ structure are ordered before the store that publishes the pointer
+ to that structure.
+
+ Perhaps just as important, rcu_assign_pointer() serves to document
+ (1) which pointers are protected by RCU and (2) the point at which
+ a given structure becomes accessible to other CPUs. That said,
rcu_assign_pointer() is most frequently used indirectly, via
the _rcu list-manipulation primitives such as list_add_rcu().
@@ -283,7 +287,11 @@ rcu_dereference()
executes any needed memory-barrier instructions for a given
CPU architecture. Currently, only Alpha needs memory barriers
within rcu_dereference() -- on other CPUs, it compiles to a
- volatile load.
+ volatile load. However, no mainstream C compilers respect
+ address dependencies, so rcu_dereference() uses volatile casts,
+ which, in combination with the coding guidelines listed in
+ rcu_dereference.rst, prevent current compilers from breaking
+ these dependencies.
Common coding practice uses rcu_dereference() to copy an
RCU-protected pointer to a local variable, then dereferences
--
2.40.1
Le Tue, Jun 04, 2024 at 03:21:54PM -0700, Paul E. McKenney a ?crit :
> This commit adds more detail to the Tasks RCU and Tasks Rude RCU
> descriptions in Requirements.rst. While in the area, add Tasks Trace
> RCU to the Tasks-RCU table of contents.
>
> Reported-by: Sebastian Andrzej Siewior <[email protected]>
> Signed-off-by: Paul E. McKenney <[email protected]>
Reviewed-by: Frederic Weisbecker <[email protected]>
Le Tue, Jun 04, 2024 at 03:21:55PM -0700, Paul E. McKenney a ?crit :
> This commit expands on the ordering properties of rcu_assign_pointer()
> and rcu_dereference(), outlining their constraints on CPUs and compilers.
>
> Reported-by: Rao Shoaib <[email protected]>
> Signed-off-by: Paul E. McKenney <[email protected]>
> ---
> Documentation/RCU/whatisRCU.rst | 30 +++++++++++++++++++-----------
> 1 file changed, 19 insertions(+), 11 deletions(-)
>
> diff --git a/Documentation/RCU/whatisRCU.rst b/Documentation/RCU/whatisRCU.rst
> index 94838c65c7d97..d585a5490aeec 100644
> --- a/Documentation/RCU/whatisRCU.rst
> +++ b/Documentation/RCU/whatisRCU.rst
> @@ -250,21 +250,25 @@ rcu_assign_pointer()
> ^^^^^^^^^^^^^^^^^^^^
> void rcu_assign_pointer(p, typeof(p) v);
>
> - Yes, rcu_assign_pointer() **is** implemented as a macro, though it
> - would be cool to be able to declare a function in this manner.
> - (Compiler experts will no doubt disagree.)
> + Yes, rcu_assign_pointer() **is** implemented as a macro, though
> + it would be cool to be able to declare a function in this manner.
> + (And there has been some discussion of adding overloaded functions
> + to the C language, so who knows?)
>
> The updater uses this spatial macro to assign a new value to an
> RCU-protected pointer, in order to safely communicate the change
> in value from the updater to the reader. This is a spatial (as
> opposed to temporal) macro. It does not evaluate to an rvalue,
> - but it does execute any memory-barrier instructions required
> - for a given CPU architecture. Its ordering properties are that
> - of a store-release operation.
> -
> - Perhaps just as important, it serves to document (1) which
> - pointers are protected by RCU and (2) the point at which a
> - given structure becomes accessible to other CPUs. That said,
> + but it does provide any compiler directives and memory-barrier
> + instructions required for a given compile or CPU architecture.
> + Its ordering properties are that of a store-release operation,
> + that is, any prior loads and stores required to initialize the
> + structure are ordered before the store that publishes the pointer
> + to that structure.
About that, why rcu_dereference() isn't a matching load-acquire?
Thanks.
On Wed, Jun 05, 2024 at 01:42:15PM +0200, Frederic Weisbecker wrote:
> Le Tue, Jun 04, 2024 at 03:21:54PM -0700, Paul E. McKenney a ?crit :
> > This commit adds more detail to the Tasks RCU and Tasks Rude RCU
> > descriptions in Requirements.rst. While in the area, add Tasks Trace
> > RCU to the Tasks-RCU table of contents.
> >
> > Reported-by: Sebastian Andrzej Siewior <[email protected]>
> > Signed-off-by: Paul E. McKenney <[email protected]>
>
> Reviewed-by: Frederic Weisbecker <[email protected]>
I will apply this on my next rebase, thank you!
Thanx, Paul
On Wed, Jun 05, 2024 at 01:56:23PM +0200, Frederic Weisbecker wrote:
> Le Tue, Jun 04, 2024 at 03:21:55PM -0700, Paul E. McKenney a ?crit :
> > This commit expands on the ordering properties of rcu_assign_pointer()
> > and rcu_dereference(), outlining their constraints on CPUs and compilers.
> >
> > Reported-by: Rao Shoaib <[email protected]>
> > Signed-off-by: Paul E. McKenney <[email protected]>
> > ---
> > Documentation/RCU/whatisRCU.rst | 30 +++++++++++++++++++-----------
> > 1 file changed, 19 insertions(+), 11 deletions(-)
> >
> > diff --git a/Documentation/RCU/whatisRCU.rst b/Documentation/RCU/whatisRCU.rst
> > index 94838c65c7d97..d585a5490aeec 100644
> > --- a/Documentation/RCU/whatisRCU.rst
> > +++ b/Documentation/RCU/whatisRCU.rst
> > @@ -250,21 +250,25 @@ rcu_assign_pointer()
> > ^^^^^^^^^^^^^^^^^^^^
> > void rcu_assign_pointer(p, typeof(p) v);
> >
> > - Yes, rcu_assign_pointer() **is** implemented as a macro, though it
> > - would be cool to be able to declare a function in this manner.
> > - (Compiler experts will no doubt disagree.)
> > + Yes, rcu_assign_pointer() **is** implemented as a macro, though
> > + it would be cool to be able to declare a function in this manner.
> > + (And there has been some discussion of adding overloaded functions
> > + to the C language, so who knows?)
> >
> > The updater uses this spatial macro to assign a new value to an
> > RCU-protected pointer, in order to safely communicate the change
> > in value from the updater to the reader. This is a spatial (as
> > opposed to temporal) macro. It does not evaluate to an rvalue,
> > - but it does execute any memory-barrier instructions required
> > - for a given CPU architecture. Its ordering properties are that
> > - of a store-release operation.
> > -
> > - Perhaps just as important, it serves to document (1) which
> > - pointers are protected by RCU and (2) the point at which a
> > - given structure becomes accessible to other CPUs. That said,
> > + but it does provide any compiler directives and memory-barrier
> > + instructions required for a given compile or CPU architecture.
> > + Its ordering properties are that of a store-release operation,
> > + that is, any prior loads and stores required to initialize the
> > + structure are ordered before the store that publishes the pointer
> > + to that structure.
>
> About that, why rcu_dereference() isn't a matching load-acquire?
Here is an example showing the difference:
p = rcu_dereference(gp);
r1 = READ_ONCE(x);
r2 = p->a;
The READ_ONCE() is not ordered against the rcu_dereference(), only the
read from p->a. In contrast, if that rcu_dereference() was instead an
smp_load_acquire(), both of the two later statements would be ordered.
Ah. You are suggesting that this be added to the description of
rcu_dereference()?
Or are you asking that this documentation state that an rcu_dereference()
memory-barrier-pairs with an rcu_assign_pointer()?
Or something else completely?
Thanx, Paul