2002-06-03 14:05:57

by Gregory Giguashvili

[permalink] [raw]
Subject: Atomic operations

Hello,

I wonder if someone can help me to change the behaviour of the atomic
functions available in <asm/atomic.h> include file. The operations I need to
implement are described below:

atomic_t test_and_set (int i, atomic_t* v)
{
atomic_t old = *v;
v->counter = i;
return old;
}

atomic_t test_then_add (int i, atomic_t* v)
{
atomic_t old = *v;
v->counter += i;
return old;
}

Thanks in advance,
Giga


2002-06-03 17:28:08

by H. Peter Anvin

[permalink] [raw]
Subject: Re: Atomic operations

Followup to: <EE83E551E08D1D43AD52D50B9F5110927E7A10@ntserver2>
By author: Gregory Giguashvili <[email protected]>
In newsgroup: linux.dev.kernel
>
> Hello,
>
> I wonder if someone can help me to change the behaviour of the atomic
> functions available in <asm/atomic.h> include file. The operations I need to
> implement are described below:
>
> atomic_t test_and_set (int i, atomic_t* v)
> {
> atomic_t old = *v;
> v->counter = i;
> return old;
> }
>

This is not a test and set operation.

On i386:

atomic_t atomic_exchange (atomic_t i, atomic_t *v)
{
asm volatile("xchgl %0,%1" : "+m" (*v), "+r" (i));
return i;
}

> atomic_t test_then_add (int i, atomic_t* v)
> {
> atomic_t old = *v;
> v->counter += i;
> return old;
> }

There is no way to do this (without waiting and trying again type
code) that I know of on i386. However, you can test for zeroness of
the result, or for <= 0, or a few other options.

int test_and_add (atomic_t i, atomic_t *v)
{
char was_nonzero; /* MUST BE CHAR!!! */

asm volatile("lock; addl %2,%0; setz %1"
: "+m" (*v), "=rm" (was_nonzero)
: "g" (i));

return was_nonzero;
}



--
<[email protected]> at work, <[email protected]> in private!
"Unix gives you enough rope to shoot yourself in the foot."
http://www.zytor.com/~hpa/puzzle.txt <[email protected]>

2002-06-03 18:08:08

by Richard B. Johnson

[permalink] [raw]
Subject: Re: Atomic operations

On Mon, 3 Jun 2002, Gregory Giguashvili wrote:

> Hello,
>
> I wonder if someone can help me to change the behaviour of the atomic
> functions available in <asm/atomic.h> include file. The operations I need to
> implement are described below:
>
> atomic_t test_and_set (int i, atomic_t* v)
> {
> atomic_t old = *v;
> v->counter = i;
> return old;
> }
>

atomic_t test_and_set(int i, atomic_t *v)
{
int ret;

__asm__ __volatile__(LOCK "movl (%1), %ecx\n"
LOCK "orl %0, (%1)\n"
: ecx (ret)
: "r" (i), "m" (v)
: "ecx", "memory" );

return (ret & i);
}

I did not check this to even see if it compiles. It serves only
as an example of a problem with your requirements. You may be
able to use BTS for your problem, but that may not satisfy your
requirements.

In the above example, I lock the bus and move the contents of
your memory location into a register. Then, I lock the bus again
and OR in the bits you require. Later, I see if that bit was set
in the return value. Unfortunately, a lot can change during the
two lock instructions.

To use the BTS instruction, you do something like this:

atomic_t test_and_set(int i, atomic_t *v)
{
int ret;
__asm__ __volatile__("xorl %ecx, %ecx\n"
LOCK "btsl %0, (%1)\n"
"adcl %ecx, ecx\n"
: ecx (ret)
: "r" (i), "m" (v)
: "ecx", "memory" );

return(i && ret); /* Note Logical AND */
// or
return ret;
}

BTS will test a bit then set it. The result of the initial
test will be in the CY flag. I zero a register first, do the stuff,
then add the contents of the CY flag into the previously-zeroed
register. This I how I return the result. Again, this may not
be what you want although you may be able to modify the logic of
your code to accept such.


Cheers,
Dick Johnson

Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips).

Windows-2000/Professional isn't.

2002-06-03 18:39:35

by Brian Gerst

[permalink] [raw]
Subject: Re: Atomic operations

Gregory Giguashvili wrote:
>
> Hello,
>
> I wonder if someone can help me to change the behaviour of the atomic
> functions available in <asm/atomic.h> include file. The operations I need to
> implement are described below:
>
> atomic_t test_and_set (int i, atomic_t* v)
> {
> atomic_t old = *v;
> v->counter = i;
> return old;
> }

What you have coded is really an exchange, not a test. Here is the asm
equivalent of what you coded:

int atomic_xchg(int i, atomic_t *v)
{
int ret;
__asm__("xchgl %1,%0"
: "=m" (v->counter), "=r" (ret)
: "0" (v->counter), "1" (i));
return ret;
}

>
> atomic_t test_then_add (int i, atomic_t* v)
> {
> atomic_t old = *v;
> v->counter += i;
> return old;
> }

int atomic_xadd(int i, atomic_t *v)
{
int ret;
__asm__(LOCK "xaddl %1,%0"
: "=m" (v->counter), "=r" (ret)
: "0" (v->counter), "1" (i));
return ret;
}

This one only works on 486+, but there are practically no real 386 SMP
systems.

--

Brian Gerst

2002-06-03 19:36:32

by Thunder from the hill

[permalink] [raw]
Subject: Re: Atomic operations

Hi,

On Mon, 3 Jun 2002, Richard B. Johnson wrote:
> atomic_t test_and_set(int i, atomic_t *v)
> {
> int ret;
>
> __asm__ __volatile__(LOCK "movl (%1), %ecx\n"
> LOCK "orl %0, (%1)\n"
> : ecx (ret)
> : "r" (i), "m" (v)
> : "ecx", "memory" );
>
> return (ret & i);
> }

I'm not an expert, but shouldn't "exc" be quoted here? I'm just
wondering...

Regards,
Thunder
--
ship is leaving right on time | Thunder from the hill at ngforever
empty harbour, wave goodbye |
evacuation of the isle | free inhabitant not directly
caveman's paintings drowning | belonging anywhere

2002-06-03 19:49:44

by H. Peter Anvin

[permalink] [raw]
Subject: Re: Atomic operations

Followup to: <[email protected]>
By author: Brian Gerst <[email protected]>
In newsgroup: linux.dev.kernel
>
> int atomic_xadd(int i, atomic_t *v)
> {
> int ret;
> __asm__(LOCK "xaddl %1,%0"
> : "=m" (v->counter), "=r" (ret)
> : "0" (v->counter), "1" (i));
> return ret;
> }
>
> This one only works on 486+, but there are practically no real 386 SMP
> systems.
>

<slaps forehead>

Boy do I feel dumb now.

The only nitpick is that it's probably better coded as:

int atomic_xadd(int i, atomic_t *v)
{
asm volatile(LOCK "xaddl %1,%0"
: "+m" (v->counter), "+r" (i));
return i;
}
--
<[email protected]> at work, <[email protected]> in private!
"Unix gives you enough rope to shoot yourself in the foot."
http://www.zytor.com/~hpa/puzzle.txt <[email protected]>

2002-06-03 21:29:04

by Richard B. Johnson

[permalink] [raw]
Subject: Re: Atomic operations

On Mon, 3 Jun 2002, Thunder from the hill wrote:

> Hi,
>
> On Mon, 3 Jun 2002, Richard B. Johnson wrote:
> > atomic_t test_and_set(int i, atomic_t *v)
> > {
> > int ret;
> >
> > __asm__ __volatile__(LOCK "movl (%1), %ecx\n"
> > LOCK "orl %0, (%1)\n"
> > : "ecx" (ret)
> > : "r" (i), "m" (v)
> > : "ecx", "memory" );
> >
> > return (ret & i);
> > }
>
> I'm not an expert, but shouldn't "exc" be quoted here? I'm just
ecx
Yes, we both make typos!
> wondering...



Cheers,
Dick Johnson

Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips).

Windows-2000/Professional isn't.