From: "Paul E. McKenney" <paulmck@linux.ibm.com>
To: Junchang Wang <junchangwang@gmail.com>
Cc: akiyks@gmail.com, perfbook@vger.kernel.org
Subject: Re: [PATCH] rcu_nest: fix concurrency issues
Date: Thu, 2 May 2019 07:59:51 -0700 [thread overview]
Message-ID: <20190502145951.GL3923@linux.ibm.com> (raw)
In-Reply-To: <1556596959-11571-1-git-send-email-junchangwang@gmail.com>
On Tue, Apr 30, 2019 at 12:02:39PM +0800, Junchang Wang wrote:
> Variable "rcu_gp_ctr" is incremented by the updater and is fetched by
> readers concurrently. So protect this variable by using READ_ONCE()
> and WRITE_ONCE().
>
> Per-thread variable "rcu_read_gp" is updated by the reader and is read
> by the updater. So protect it by using READ_ONCE() and WRITE_ONCE().
>
> The type of "rcu_gp_ctr" is changed to unsigned long because the behavior
> of the overflow of a signed long integer is not well defined in C yet.
>
> Refine the code snippet in "rcu_read_lock" that allows a reader to start
> over. In this version, we add micro MAX_GP_ADV_DISTANCE which is by
> default set to (RCU_GP_CTR_NEST_MASK << 8). Once a reader notices that
> MAX_GP_ADV_DISTANCE grace-periods have elapsed since fetching the value of
> "rcu_reader_gp", the reader starts over.
>
>
> Signed-off-by: Junchang Wang <junchangwang@gmail.com>
First, thank you for doing this! Lots of good improvements!!!
A few comments below.
Thanx, Paul
> ---
> CodeSamples/defer/rcu_nest.c | 5 +++--
> CodeSamples/defer/rcu_nest.h | 25 +++++++++++++++++--------
> 2 files changed, 20 insertions(+), 10 deletions(-)
>
> diff --git a/CodeSamples/defer/rcu_nest.c b/CodeSamples/defer/rcu_nest.c
> index 64e4087..362f466 100644
> --- a/CodeSamples/defer/rcu_nest.c
> +++ b/CodeSamples/defer/rcu_nest.c
> @@ -35,7 +35,7 @@ void synchronize_rcu(void)
>
> /* Advance to a new grace-period number, enforce ordering. */
>
> - rcu_gp_ctr += RCU_GP_CTR_BOTTOM_BIT;
> + WRITE_ONCE(rcu_gp_ctr, rcu_gp_ctr + RCU_GP_CTR_BOTTOM_BIT);
> smp_mb();
>
> /*
> @@ -45,7 +45,8 @@ void synchronize_rcu(void)
>
> for_each_thread(t) {
> while (rcu_gp_ongoing(t) &&
> - ((per_thread(rcu_reader_gp, t) - rcu_gp_ctr) < 0)) {
> + ((READ_ONCE(per_thread(rcu_reader_gp, t)) -
> + rcu_gp_ctr) < 0)) {
> /*@@@ poll(NULL, 0, 10); */
> barrier();
> }
> diff --git a/CodeSamples/defer/rcu_nest.h b/CodeSamples/defer/rcu_nest.h
> index bcc4cde..65ce203 100644
> --- a/CodeSamples/defer/rcu_nest.h
> +++ b/CodeSamples/defer/rcu_nest.h
> @@ -24,8 +24,9 @@ DEFINE_SPINLOCK(rcu_gp_lock);
> #define RCU_GP_CTR_SHIFT 7
> #define RCU_GP_CTR_BOTTOM_BIT (1 << RCU_GP_CTR_SHIFT)
> #define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_BOTTOM_BIT - 1)
> -long rcu_gp_ctr = 0; /* increment by RCU_GP_CTR_BOTTOM_BIT each gp. */
> -DEFINE_PER_THREAD(long, rcu_reader_gp);
> +#define MAX_GP_ADV_DISTANCE (RCU_GP_CTR_NEST_MASK << 8)
> +unsigned long rcu_gp_ctr = 0; /* increment by RCU_GP_CTR_BOTTOM_BIT each gp. */
> +DEFINE_PER_THREAD(unsigned long, rcu_reader_gp);
>
> static inline int rcu_gp_ongoing(int cpu)
> {
> @@ -39,8 +40,8 @@ static void rcu_init(void)
>
> static void rcu_read_lock(void)
> {
> - long tmp;
> - long *rrgp;
> + unsigned long tmp;
> + unsigned long *rrgp;
>
> /*
> * If this is the outermost RCU read-side critical section,
> @@ -52,13 +53,21 @@ static void rcu_read_lock(void)
> retry:
> tmp = *rrgp;
> if ((tmp & RCU_GP_CTR_NEST_MASK) == 0)
> - tmp = rcu_gp_ctr;
> + tmp = READ_ONCE(rcu_gp_ctr);
> tmp++;
> - *rrgp = tmp;
> + WRITE_ONCE(*rrgp, tmp);
> smp_mb();
> +
> + /*
> + * A reader could be suspended in between fetching the value of *rrgp
> + * and writting the updated value back into *rrgp. During this
s/writting/writing/
> + * time period, the grace-period counter might have advanced very far.
> + * In this case, we force the reader to start over.
> + */
> +
> if (((tmp & RCU_GP_CTR_NEST_MASK) == 1) &&
> - ((rcu_gp_ctr - tmp) > (RCU_GP_CTR_NEST_MASK << 8)) != 0) {
> - (*rrgp)--;
> + (READ_ONCE(rcu_gp_ctr) > tmp + MAX_GP_ADV_DISTANCE)) {
Does this work correctly if the value of tmp is just a bit less than
ULONG_MAX? It looks to me like it does not.
> + WRITE_ONCE(*rrgp, *rrgp - 1);
> goto retry;
> }
> }
> --
> 2.7.4
>
next prev parent reply other threads:[~2019-05-02 15:01 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-30 4:02 [PATCH] rcu_nest: fix concurrency issues Junchang Wang
2019-05-02 14:59 ` Paul E. McKenney [this message]
2019-05-05 13:16 ` Junchang Wang
2019-05-06 18:14 ` Paul E. McKenney
2019-05-08 13:46 ` Junchang Wang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190502145951.GL3923@linux.ibm.com \
--to=paulmck@linux.ibm.com \
--cc=akiyks@gmail.com \
--cc=junchangwang@gmail.com \
--cc=perfbook@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.