Subject: Re: Atomic ops API
To: Johnny Billquist <bqt@softjar.se>
From: Bang Jun-Young <junyoung@netbsd.org>
List: tech-kern
Date: 03/15/2007 09:17:11
On 3/15/07, Johnny Billquist <bqt@softjar.se> wrote:
> Bang Jun-Young wrote:
> > On 3/14/07, Johnny Billquist <bqt@softjar.se> wrote:
> >
> >> Memory barrier or not, I wouldn't expect the above code to work anyway.
> >> The value of the target could very well change between the read and the
> >> actual store.
> >> So you could actually have a situation where old == cmp, but the store
> >> didn't take place, since the value of target changed before the
> >> atomic_compare_and_store. Thus, you might think that you did a write,
> >> but in reality you didn't.
> >> The value of *target can change between the read and the atomic modify.
> >>
> >> Or am I missing something?
> >
> > atomic_compare_and_store() doesn't guarantee that it returns the old
> > value of *target you expect, either. If *target was modified within
> > atomic_compare_and_store() before the actual atomic instruction was
> > executed, the modified value would be returned instead of the expected
> > one.
>
> Isn't the whole point of a function called "atomic_compare_and_store"
> that it would be atomic? Otherwise I would say that it was misnamed.
> So, it should not be possible for *target to be modified withing the
> atomic_compare_and_store by some other entity, or the function isn't atomic.
>

The atomic function means "a function that performs an atomic operation", not
"a funtion that is atomic itself." The actual implementation of atomic_cas_32
on i386 is something like this:

atomic_cas_32:
        mov edx, [esp+4]        // target
        mov eax, [esp+8]        // cmp
        mov ecx, [esp+12]       // new
        lock cmpxchg [edx], ecx
        ret

If *target was modified before cmpxchg, the function would return a unexpected
value.

For comparison, what Jason wants to have in NetBSD would look like:

atomic_cas_32:
        mov edx, [esp+4]        // target
        mov eax, [esp+8]        // cmp
        mov ecx, [esp+12]       // new
        lock cmpxchg [edx], ecx
        setz al
        ret

> And doing tests in a loop outside isn't solving the puzzle. If the
> values can be changed by some other entity in parallell, you'll always
> be in trouble. The only solution is to provide a guaranteed atomic
> operation, or use a mutex to guarantee exclusive access to the data you
> want to manipulate.

Yes, I agree. atomic_cas() should be carefully used.

Jun-Young