<<On Tue, 12 Dec 2000 17:59:37 -0800, Alfred Perlstein <[EMAIL PROTECTED]> said:

> Actually, in truth I think you can get the code right like so:

> long x = _mmm->m_ext.ref_cnt->refcnt;
> while (!atomic_cmpset_long(&_mmm->m_ext.ref_cnt->refcnt, x - 1, x))
>       ;

Cool!  You've just (almost) reinvented non-blocking parallel
reference-counts.  Of course, what you really need is:

long
atomic_decrement_long(long *where)
{
        long oldval;

        do {
                oldval = *where;
        } while (compare_exchange(where, &oldval, oldval - 1) != FAILURE);

        return (oldval);
        /*
         * Five instructions in-line on i486.
         * 1:   movl (%ebx), %eax
         *      movl %eax, %edx
         *      subl $1, %edx
         *      cmpxchg (%ebx), %eax, %edx      ; IIRC -- might be backwards
         *      jc 1
         */
}

...except that on some architectures, the right way to write it would
be:

long
atomic_decrement_long(long *where)
{
        long oldval;

        do {
                oldval = load_linked_long(where);
        } while (store_conditional(where, oldval - 1) != FAILURE);

        return (oldval);
        /*
         * Compiles to four or five instructions on an Alpha.
         */
}

In this particular instance, you know that you just deleted the last
reference if atomic_decrement_long returns an `old value' of 

> But that's just gross, expensive and shouldn't be needed.

Nothing gross about it -- just ask any parallel algorithms geek.  (Of
which I am emphatically not one, I should point out.)

-GAWollman



To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-net" in the body of the message

Reply via email to