From: paulmck@linux.vnet.ibm.com (Paul E. McKenney)
Subject: [ltt-dev] lock-free data structures (was Re: [PATCH 12/12] centralize definition of BITS_PER_LONG)
Date: Fri, 19 Feb 2010 15:51:39 -0800 [thread overview]
Message-ID: <20100219235139.GF6778@linux.vnet.ibm.com> (raw)
In-Reply-To: <4B7EE590.2010807@redhat.com>
On Fri, Feb 19, 2010 at 08:25:04PM +0100, Paolo Bonzini wrote:
>
>>> Some time we should also add double-long compare-and-swap, that's very
>>> useful for lock-free lists.
>>
>> Do you have pointers to papers describing this double-wide CAS
>> linked-list structure ?
>
> I found
> http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.86.8494&rep=rep1&type=pdf
> (page 4) which is a lock-free queue.
>
> The two words are used like this:
>
> struct gen_ptr {
> long gen;
> void *ptr;
> }
>
> where gen is always incremented whenever ptr is changed.
Doesn't the use of RCU prevent the ABA scenario, and doesn't that make
DCAS unnecessary?
Thanx, Paul
>> Yes, good idea! Although this won't be available on all architectures.
>> We might have to think of a mutex-based compatibility layer for these.
>
> You don't need a mutex if you use it for a lock-free queue. You're just
> better off providing two version of the queue, one for double-word CAS and
> a not-really-lock-free one for simple CAS.
>
> The elementary operation in that algorithm are reading a struct gen_ptr in
> a way that can be compared-and-swapped later, and doing a compare-and-swap
> that checks consistency of generation and pointer and increments the
> generation. If you have double-word CAS, everything is very simple because
> consistency is taken care of by the double-word CAS. So with double-word
> CAS the above are
>
> void *atomicRead (struct gen_ptr *val)
> {
> return val->ptr;
> }
>
> and
>
> long atomicCmpXchgIncrGeneration (struct gen_ptr *val, void *old_ptr,
> void *new_ptr)
> {
> int old_gen = val->gen;
> struct gen_ptr read =
> atomicCmpXchgDouble (val, old_gen, old_ptr,
> old_gen + 1, new_ptr)
> return read.gen;
> }
>
> but even without double-word CAS you can do it because if the generations
> match, so will the pointers. So the CAS will be on the generation in this
> case, and you use the low-order bit as a tag bit for "operation in
> progress". It would go something like this (untested):
>
> struct gen_ptr atomicRead (struct gen_ptr *val)
> {
> struct gen_ptr read;
> for (;;) {
> read.gen = val->gen;
> if (read.gen & 1) {
> /* Unlucky. */
> continue;
> } else {
> read.ptr = val->ptr;
> rmb ();
> if (read.gen == val->gen)
> return read;
> }
> }
> }
>
> long
> atomicCmpXchgWithGeneration (struct gen_ptr *val, long old_gen,
> void *new_ptr)
> {
> assert (!(old_gen & 1));
> int read_gen = CAS (&val->gen, old_gen, old_gen + 3);
> if (read_gen == old_gen) {
> /* We are the only ones that have access to val->ptr here.
> Since the low bit is 1, other threads will lock on
> atomicRead and fail the CAS in their
> atomicCmpXchgWithGeneration. Update val->ptr and untag
> the generation number. */
> val->ptr = new_ptr;
> wmb ();
> val->gen--;
> }
> return read_gen;
> }
>
> Now, while the above is certainly fun, I don't think it belongs in liburcu.
> However...
>
>> I wonder if we could use a clever RCU structure
>> to mimick the double-wide CAS.
>
> I don't know, I think lock-free queues and RCU are used for very different
> access patterns (and if you need lock-free, chances are that lock-free will
> kill your cache and not give you _that much_ performance, so maybe you'd
> better rethink everything...). However I'm not expert at all.
>
> Still, related to this, the paper above gives only half of the story. The
> lock-free queue needs a free list traditionally, and the paper mentions
> using a lock-free stack as a free list (BTW the lock-free stack doesn't
> need double-word CAS). But then, the nodes on the freelist can never be
> returned to the OS because you can always race with the operations on the
> lock-free queue.
>
> So, maybe RCU could be used to detect quiescent periods when there is no
> operation being performed on the lock-free queue. *Both enqueue and
> dequeue* would be wrapped in rcu_read_{,un}lock(), unlike normal RCU
> algorithms because this one is lock free. Then, in dequeue you'd replace
> the paper's line D19 with
>
> defer_rcu(free, head);
>
> Hmm...
>
> Paolo
next prev parent reply other threads:[~2010-02-19 23:51 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-02-15 19:04 [ltt-dev] [PATCH 00/12] provide default definition of uatomic builtins Paolo Bonzini
2010-02-15 19:04 ` [ltt-dev] [PATCH 01/12] use kernel style makefile output Paolo Bonzini
2010-02-15 19:04 ` [ltt-dev] [PATCH 02/12] use autoconf symbolic linking Paolo Bonzini
2010-02-15 19:04 ` [ltt-dev] [PATCH 03/12] add urcu/arch_defaults.h Paolo Bonzini
2010-02-18 2:57 ` Mathieu Desnoyers
2010-02-15 19:04 ` [ltt-dev] [PATCH 04/12] define sync_core for x86 PIC Paolo Bonzini
2010-02-15 19:04 ` [ltt-dev] [PATCH 05/12] remove compat_uatomic_cmpxchg #define from non-x86 Paolo Bonzini
2010-02-15 19:04 ` [ltt-dev] [PATCH 06/12] add uatomic_defaults.h, use it for default definitions Paolo Bonzini
2010-02-18 3:10 ` Mathieu Desnoyers
2010-02-15 19:04 ` [ltt-dev] [PATCH 07/12] use uatomic_defaults.h for common fallback implementations Paolo Bonzini
2010-02-15 19:04 ` [ltt-dev] [PATCH 08/12] move whether atomic byte/short exists to uatomic_arch_*.h Paolo Bonzini
2010-02-18 3:12 ` Mathieu Desnoyers
2010-02-15 19:04 ` [ltt-dev] [PATCH 09/12] add Alpha support Paolo Bonzini
2010-02-18 3:21 ` Mathieu Desnoyers
2010-02-15 19:04 ` [ltt-dev] [PATCH 10/12] support compiling on unknown architectures Paolo Bonzini
2010-02-18 3:22 ` Mathieu Desnoyers
2010-02-15 19:04 ` [ltt-dev] [PATCH 11/12] avoid multiple evaluation of STORE_SHARED argument Paolo Bonzini
2010-02-18 3:28 ` Mathieu Desnoyers
2010-02-18 8:45 ` Paolo Bonzini
2010-02-15 19:04 ` [ltt-dev] [PATCH 12/12] centralize definition of BITS_PER_LONG Paolo Bonzini
2010-02-18 3:25 ` Mathieu Desnoyers
2010-02-18 8:45 ` Paolo Bonzini
2010-02-18 13:46 ` Mathieu Desnoyers
2010-02-18 15:27 ` Paolo Bonzini
2010-02-18 16:09 ` Mathieu Desnoyers
2010-02-19 19:25 ` [ltt-dev] lock-free data structures (was Re: [PATCH 12/12] centralize definition of BITS_PER_LONG) Paolo Bonzini
2010-02-19 23:51 ` Paul E. McKenney [this message]
2010-02-20 0:10 ` Paolo Bonzini
2010-02-20 0:44 ` Paul E. McKenney
2010-02-15 19:04 ` [ltt-dev] [PATCH 13/12] test uatomic_defaults.h Paolo Bonzini
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=20100219235139.GF6778@linux.vnet.ibm.com \
--to=paulmck@linux.vnet.ibm.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox