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
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]>
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.
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
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
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]>
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.