Mirror of the lttng-dev mailing list
 help / color / mirror / Atom feed
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




  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