Re: [PATCH] Doc: whatisRCU: Add more Markup

Amol Grover
2019-11-06T09:45:33Z

On Wed, Nov 06, 2019 at 04:42:34AM +0700, Phong Tran wrote:
> o Adding more crossrefs.
> o Bold some words.
> o Add header levels.
>
> Signed-off-by: Phong Tran <tranmanphong@gmail.com>
> ---
> Documentation/RCU/whatisRCU.rst | 67 ++++++++++++++++++++-------------
> 1 file changed, 41 insertions(+), 26 deletions(-)
>
> diff --git a/Documentation/RCU/whatisRCU.rst b/Documentation/RCU/whatisRCU.rst
> index ae40c8bcc56c..3e24e0155a91 100644
> --- a/Documentation/RCU/whatisRCU.rst
> +++ b/Documentation/RCU/whatisRCU.rst
> @@ -150,7 +150,7 @@ later. See the kernel docbook documentation for more info, or look directly
> at the function header comments.
>
> rcu_read_lock()
> -
> +^^^^^^^^^^^^^^^
> void rcu_read_lock(void);
>
> Used by a reader to inform the reclaimer that the reader is
> @@ -164,7 +164,7 @@ rcu_read_lock()
> longer-term references to data structures.
>
> rcu_read_unlock()
> -
> +^^^^^^^^^^^^^^^^^
> void rcu_read_unlock(void);
>
> Used by a reader to inform the reclaimer that the reader is
> @@ -172,13 +172,13 @@ rcu_read_unlock()
> read-side critical sections may be nested and/or overlapping.
>
> synchronize_rcu()
> -
> +^^^^^^^^^^^^^^^^^
> void synchronize_rcu(void);
>
> Marks the end of updater code and the beginning of reclaimer
> code. It does this by blocking until all pre-existing RCU
> read-side critical sections on all CPUs have completed.
> - Note that synchronize_rcu() will -not- necessarily wait for
> + Note that synchronize_rcu() will **not** necessarily wait for
> any subsequent RCU read-side critical sections to complete.
> For example, consider the following sequence of events::
>
> @@ -196,7 +196,7 @@ synchronize_rcu()
> any that begin after synchronize_rcu() is invoked.
>
> Of course, synchronize_rcu() does not necessarily return
> - -immediately- after the last pre-existing RCU read-side critical
> + **immediately** after the last pre-existing RCU read-side critical
> section completes. For one thing, there might well be scheduling
> delays. For another thing, many RCU implementations process
> requests in batches in order to improve efficiencies, which can
> @@ -225,10 +225,10 @@ synchronize_rcu()
> checklist.txt for some approaches to limiting the update rate.
>
> rcu_assign_pointer()
> -
> +^^^^^^^^^^^^^^^^^^^^
> void rcu_assign_pointer(p, typeof(p) v);
>
> - Yes, rcu_assign_pointer() -is- implemented as a macro, though it
> + 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.)
>
> @@ -245,7 +245,7 @@ rcu_assign_pointer()
> the _rcu list-manipulation primitives such as list_add_rcu().
>
> rcu_dereference()
> -
> +^^^^^^^^^^^^^^^^^
> typeof(p) rcu_dereference(p);
>
> Like rcu_assign_pointer(), rcu_dereference() must be implemented
> @@ -280,8 +280,8 @@ rcu_dereference()
> unnecessary overhead on Alpha CPUs.
>
> Note that the value returned by rcu_dereference() is valid
> - only within the enclosing RCU read-side critical section [1].
> - For example, the following is -not- legal::
> + only within the enclosing RCU read-side critical section [1]_.
> + For example, the following is **not** legal::
>
> rcu_read_lock();
> p = rcu_dereference(head.next);
> @@ -304,9 +304,11 @@ rcu_dereference()
> at any time, including immediately after the rcu_dereference().
> And, again like rcu_assign_pointer(), rcu_dereference() is
> typically used indirectly, via the _rcu list-manipulation
> - primitives, such as list_for_each_entry_rcu() [2].
> + primitives, such as list_for_each_entry_rcu() [2]_.
> +
> + .. [1]

Hey Phong,
I just checked the patch but this change doesn't seem quite right.
It just creates an empty footnote. Something on the lines of
.. [1] The variant rcu_dereference_protected()...
should work.

>
> - [1] The variant rcu_dereference_protected() can be used outside
> + The variant rcu_dereference_protected() can be used outside
> of an RCU read-side critical section as long as the usage is
> protected by locks acquired by the update-side code. This variant
> avoids the lockdep warning that would happen when using (for
> @@ -319,7 +321,9 @@ rcu_dereference()
> a lockdep splat is emitted. See Documentation/RCU/Design/Requirements/Requirements.rst
> and the API's code comments for more details and example usage.
>
> - [2] If the list_for_each_entry_rcu() instance might be used by
> + .. [2]

Similarly for this.

> +
> + If the list_for_each_entry_rcu() instance might be used by
> update-side code as well as by RCU readers, then an additional
> lockdep expression can be added to its list of arguments.
> For example, given an additional "lock_is_held(&mylock)" argument,
> @@ -459,22 +463,22 @@ uses of RCU may be found in :ref:`listRCU.rst <list_rcu_doc>`,
>
> So, to sum up:
>
> -o Use rcu_read_lock() and rcu_read_unlock() to guard RCU
> +- Use rcu_read_lock() and rcu_read_unlock() to guard RCU
> read-side critical sections.
>
> -o Within an RCU read-side critical section, use rcu_dereference()
> +- Within an RCU read-side critical section, use rcu_dereference()
> to dereference RCU-protected pointers.
>
> -o Use some solid scheme (such as locks or semaphores) to
> +- Use some solid scheme (such as locks or semaphores) to
> keep concurrent updates from interfering with each other.
>
> -o Use rcu_assign_pointer() to update an RCU-protected pointer.
> +- Use rcu_assign_pointer() to update an RCU-protected pointer.
> This primitive protects concurrent readers from the updater,
> - -not- concurrent updates from each other! You therefore still
> + **not** concurrent updates from each other! You therefore still
> need to use locking (or something similar) to keep concurrent
> rcu_assign_pointer() primitives from interfering with each other.
>
> -o Use synchronize_rcu() -after- removing a data element from an
> +- Use synchronize_rcu() **after** removing a data element from an
> RCU-protected data structure, but -before- reclaiming/freeing

And this -before- is feeling lonely aswell.

Thanks
Amol

> the data element, in order to wait for the completion of all
> RCU read-side critical sections that might be referencing that
> @@ -566,7 +570,7 @@ namely foo_reclaim().
> The summary of advice is the same as for the previous section, except
> that we are now using call_rcu() rather than synchronize_rcu():
>
> -o Use call_rcu() -after- removing a data element from an
> +- Use call_rcu() **after** removing a data element from an
> RCU-protected data structure in order to register a callback
> function that will be invoked after the completion of all RCU
> read-side critical sections that might be referencing that
> @@ -603,7 +607,7 @@ more details on the current implementation as of early 2004.
>
>
> 5A. "TOY" IMPLEMENTATION #1: LOCKING
> -
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> This section presents a "toy" RCU implementation that is based on
> familiar locking primitives. Its overhead makes it a non-starter for
> real-life use, as does its lack of scalability. It is also unsuitable
> @@ -671,6 +675,8 @@ that the only thing that can block rcu_read_lock() is a synchronize_rcu().
> But synchronize_rcu() does not acquire any locks while holding rcu_gp_mutex,
> so there can be no deadlock cycle.
>
> +.. _quiz_1:
> +
> Quick Quiz #1:
> Why is this argument naive? How could a deadlock
> occur when using this algorithm in a real-world Linux
> @@ -679,7 +685,7 @@ Quick Quiz #1:
> :ref:`Answers to Quick Quiz <8_whatisRCU>`
>
> 5B. "TOY" EXAMPLE #2: CLASSIC RCU
> -
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> This section presents a "toy" RCU implementation that is based on
> "classic RCU". It is also short on performance (but only for updates) and
> on features such as hotplug CPU and the ability to run in CONFIG_PREEMPT
> @@ -710,14 +716,14 @@ CPU in turn. The run_on() primitive can be implemented straightforwardly
> in terms of the sched_setaffinity() primitive. Of course, a somewhat less
> "toy" implementation would restore the affinity upon completion rather
> than just leaving all tasks running on the last CPU, but when I said
> -"toy", I meant -toy-!
> +"toy", I meant **toy**!
>
> So how the heck is this supposed to work???
>
> Remember that it is illegal to block while in an RCU read-side critical
> section. Therefore, if a given CPU executes a context switch, we know
> that it must have completed all preceding RCU read-side critical sections.
> -Once -all- CPUs have executed a context switch, then -all- preceding
> +Once **all** CPUs have executed a context switch, then **all** preceding
> RCU read-side critical sections will have completed.
>
> So, suppose that we remove a data item from its structure and then invoke
> @@ -725,12 +731,16 @@ synchronize_rcu(). Once synchronize_rcu() returns, we are guaranteed
> that there are no RCU read-side critical sections holding a reference
> to that data item, so we can safely reclaim it.
>
> +.. _quiz_2:
> +
> Quick Quiz #2:
> Give an example where Classic RCU's read-side
> - overhead is -negative-.
> + overhead is **negative**.
>
> :ref:`Answers to Quick Quiz <8_whatisRCU>`
>
> +.. _quiz_3:
> +
> Quick Quiz #3:
> If it is illegal to block in an RCU read-side
> critical section, what the heck do you do in
> @@ -1076,9 +1086,11 @@ Answer:
> approach where tasks in RCU read-side critical sections
> cannot be blocked by tasks executing synchronize_rcu().
>
> +:ref:`Back to Quick Quiz #1 <quiz_1>`
> +
> Quick Quiz #2:
> Give an example where Classic RCU's read-side
> - overhead is -negative-.
> + overhead is **negative**.
>
> Answer:
> Imagine a single-CPU system with a non-CONFIG_PREEMPT
> @@ -1103,6 +1115,8 @@ Answer:
> even the theoretical possibility of negative overhead for
> a synchronization primitive is a bit unexpected. ;-)
>
> +:ref:`Back to Quick Quiz #2 <quiz_2>`
> +
> Quick Quiz #3:
> If it is illegal to block in an RCU read-side
> critical section, what the heck do you do in
> @@ -1128,6 +1142,7 @@ Answer:
> Besides, how does the computer know what pizza parlor
> the human being went to???
>
> +:ref:`Back to Quick Quiz #3 <quiz_3>`
>
> ACKNOWLEDGEMENTS
>
> --
> 2.20.1
>