public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Atomic operations
@ 2002-06-03 15:04 Gregory Giguashvili
  2002-06-03 17:27 ` H. Peter Anvin
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Gregory Giguashvili @ 2002-06-03 15:04 UTC (permalink / raw)
  To: Linux Kernel (E-mail)

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


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Atomic operations
@ 2002-06-03 15:58 Gregory Giguashvili
  0 siblings, 0 replies; 11+ messages in thread
From: Gregory Giguashvili @ 2002-06-03 15:58 UTC (permalink / raw)
  To: Linux Kernel (E-mail); +Cc: 'chyang@ah.edu.cn'

Hello,

I forgot to add that I know that it can be implemented using XCHG and LOCK
operations. However, I'm not an expert in ASM, so I was hoping somebody
would help me...

Thanks 
Giga


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Atomic operations
  2002-06-03 15:04 Atomic operations Gregory Giguashvili
@ 2002-06-03 17:27 ` H. Peter Anvin
  2002-06-03 18:08 ` Richard B. Johnson
  2002-06-03 18:39 ` Brian Gerst
  2 siblings, 0 replies; 11+ messages in thread
From: H. Peter Anvin @ 2002-06-03 17:27 UTC (permalink / raw)
  To: linux-kernel

Followup to:  <EE83E551E08D1D43AD52D50B9F5110927E7A10@ntserver2>
By author:    Gregory Giguashvili <Gregoryg@ParadigmGeo.com>
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;
}

  

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Atomic operations
  2002-06-03 15:04 Atomic operations Gregory Giguashvili
  2002-06-03 17:27 ` H. Peter Anvin
@ 2002-06-03 18:08 ` Richard B. Johnson
  2002-06-03 19:36   ` Thunder from the hill
  2002-06-03 18:39 ` Brian Gerst
  2 siblings, 1 reply; 11+ messages in thread
From: Richard B. Johnson @ 2002-06-03 18:08 UTC (permalink / raw)
  To: Gregory Giguashvili; +Cc: Linux Kernel (E-mail)

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.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Atomic operations
  2002-06-03 15:04 Atomic operations Gregory Giguashvili
  2002-06-03 17:27 ` H. Peter Anvin
  2002-06-03 18:08 ` Richard B. Johnson
@ 2002-06-03 18:39 ` Brian Gerst
  2002-06-03 19:49   ` H. Peter Anvin
  2 siblings, 1 reply; 11+ messages in thread
From: Brian Gerst @ 2002-06-03 18:39 UTC (permalink / raw)
  To: Gregory Giguashvili; +Cc: Linux Kernel (E-mail)

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Atomic operations
  2002-06-03 19:09 Gregory Giguashvili
@ 2002-06-03 18:43 ` H. Peter Anvin
  0 siblings, 0 replies; 11+ messages in thread
From: H. Peter Anvin @ 2002-06-03 18:43 UTC (permalink / raw)
  To: linux-kernel

Followup to:  <EE83E551E08D1D43AD52D50B9F5110927E7A15@ntserver2>
By author:    Gregory Giguashvili <Gregoryg@ParadigmGeo.com>
In newsgroup: linux.dev.kernel
> 
> Could you, please, clarify what you meant saying that there was no way of
> doing so. I admit, I'm no expert in i386 assembly, but this operation seems
> so simple to me...
> 

That doesn't mean the hardware is going to provide it atomically.

> 
> Could you, please, suggest some other implementation (with waiting and
> trying again - whatever this means)?
> 

Very simple:

- Set a spinlock (note: you need a spinlock variable)
- Read
- Add
- Clear spinlock

This is called "bootstrapping" -- using a more primitive atomic
operation to get what you need.

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: Atomic operations
@ 2002-06-03 19:09 Gregory Giguashvili
  2002-06-03 18:43 ` H. Peter Anvin
  0 siblings, 1 reply; 11+ messages in thread
From: Gregory Giguashvili @ 2002-06-03 19:09 UTC (permalink / raw)
  To: linux-kernel

Peter,

Thanks a lot for your help. 

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

Could you, please, clarify what you meant saying that there was no way of
doing so. I admit, I'm no expert in i386 assembly, but this operation seems
so simple to me...

Could you, please, suggest some other implementation (with waiting and
trying again - whatever this means)?

test_and_set and test_then_add functions are coming from code written for
IRIX. Solaris has similar functionality. Windows NT also provides these
primitives in Win32 API (possibly implemented not in the most effective way,
according to what you say). The only OS where they are missing is Linux. 

Unfortunately, these primitives became an integral part of our code, which
makes it very painful to change their behavior.

Thanks in advance.
Giga

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Atomic operations
  2002-06-03 18:08 ` Richard B. Johnson
@ 2002-06-03 19:36   ` Thunder from the hill
  2002-06-03 21:30     ` Richard B. Johnson
  0 siblings, 1 reply; 11+ messages in thread
From: Thunder from the hill @ 2002-06-03 19:36 UTC (permalink / raw)
  To: Richard B. Johnson; +Cc: Gregory Giguashvili, Linux Kernel (E-mail)

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


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Atomic operations
  2002-06-03 18:39 ` Brian Gerst
@ 2002-06-03 19:49   ` H. Peter Anvin
  0 siblings, 0 replies; 11+ messages in thread
From: H. Peter Anvin @ 2002-06-03 19:49 UTC (permalink / raw)
  To: linux-kernel

Followup to:  <3CFBB7DB.831BE453@didntduck.org>
By author:    Brian Gerst <bgerst@didntduck.org>
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;
}
-- 
<hpa@transmeta.com> at work, <hpa@zytor.com> in private!
"Unix gives you enough rope to shoot yourself in the foot."
http://www.zytor.com/~hpa/puzzle.txt	<amsp@zytor.com>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Atomic operations
  2002-06-03 19:36   ` Thunder from the hill
@ 2002-06-03 21:30     ` Richard B. Johnson
  0 siblings, 0 replies; 11+ messages in thread
From: Richard B. Johnson @ 2002-06-03 21:30 UTC (permalink / raw)
  To: Thunder from the hill; +Cc: Gregory Giguashvili, Linux Kernel (E-mail)

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.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: Atomic operations
@ 2002-06-04  9:23 Gregory Giguashvili
  0 siblings, 0 replies; 11+ messages in thread
From: Gregory Giguashvili @ 2002-06-04  9:23 UTC (permalink / raw)
  To: Linux Kernel (E-mail)

Hello,

Thanks a lot for your help to all of you...

The last thing, I want to make sure of, is that the following type of code:

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;
}

is less efficient than this one:

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

The reason for it is that the first one is more easy to read (at least for
me as a beginner). 

Thanks again for your precious comments.
Best,
Giga

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2002-06-04  8:25 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-06-03 15:04 Atomic operations Gregory Giguashvili
2002-06-03 17:27 ` H. Peter Anvin
2002-06-03 18:08 ` Richard B. Johnson
2002-06-03 19:36   ` Thunder from the hill
2002-06-03 21:30     ` Richard B. Johnson
2002-06-03 18:39 ` Brian Gerst
2002-06-03 19:49   ` H. Peter Anvin
  -- strict thread matches above, loose matches on Subject: below --
2002-06-03 15:58 Gregory Giguashvili
2002-06-03 19:09 Gregory Giguashvili
2002-06-03 18:43 ` H. Peter Anvin
2002-06-04  9:23 Gregory Giguashvili

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox