Skip to contentSkip to conversation

gnu asm help...

DISCUSSION Petr Vandrovec 3 participants 3 messages Jun 18, 2001 – Jun 19, 2001

lore
Share & tools
lore
#0 lore raw
Quoted 11 lines · Timur Tabi

You want to return the variable? Try this:

static __inline__ unsigned long atomic_inc(atomic_t *v)

{
    __asm__ __volatile__(
        LOCK "incl %0"
        :"=m" (v->counter)
        :"m" (v->counter));

    return v->counter;
}

No. Another CPU might increment value between LOCK INCL and fetching v->counter. On ia32 architecture you are almost out of luck. You can either try building atomic_inc around CMPXCHG, using it as conditional store (but CMPXCHG is not available on i386), or you can just guard your atomic variable with spinlock - but in that case there is no reason for using atomic_t at all.
Best regards,
Petr Vandrovec [email protected]

P.S.: Why you need to know that value? You can either rewrite your code with atomic_dec_and_test/atomic_inc_and_test, or you overlooked some race, or you have really strange problem.

#1 lore raw

** Reply to message from "Petr Vandrovec" <[email protected]> on Tue, 19 Jun 2001 01:36:26 MET-1

Quoted 7 lines

No. Another CPU might increment value between LOCK INCL and fetching v->counter. On ia32 architecture you are almost out of luck. You can either try building atomic_inc around CMPXCHG, using it as conditional store (but CMPXCHG is not available on i386), or you can just guard your atomic variable with spinlock - but in that case there is no reason for using atomic_t at all.

Oh, I see the problem. You could do something like this:

cli
mov %0, %%eax
inc %%eax
mov %%eax, %0
sti

and then return eax, but that won't work on SMP (whereas the "lock inc" does). Doing a global cli might work, though.

Signature · 2 lines
Timur Tabi - [email protected]
Interactive Silicon - http://www.interactivesi.com
#2 lore raw
Quoted 14 lines · Timur Tabi

** Reply to message from "Petr Vandrovec" <[email protected]> on Tue, 19 Jun 2001 01:36:26 MET-1

Quoted 7 lines

No. Another CPU might increment value between LOCK INCL and fetching v->counter. On ia32 architecture you are almost out of luck. You can either try building atomic_inc around CMPXCHG, using it as conditional store (but CMPXCHG is not available on i386), or you can just guard your atomic variable with spinlock - but in that case there is no reason for using atomic_t at all.

Oh, I see the problem. You could do something like this:

Quoted 8 lines

cli
mov %0, %%eax
inc %%eax
mov %%eax, %0
sti

and then return eax, but that won't work on SMP (whereas the "lock inc" does). Doing a global cli might work, though.

The Intel book(s) state that an interrupt is not acknowledged until so many clocks (don't remember the number) after a stack operation.

Given this, is an 'attack' by another CPU allowed within this time-frame? If not, you can do:

pushl %ebx
movl INPUT_VALUE(%esp), %eax # Get input value
movl INPUT_PTR(%esp), %ebx # Get input pointer
lock
addl %eax,(%ebx) # Add value
pushl (%ebx) # Put result on stack
popl %eax # Return value in EAX
popl %ebx

It may be worth an experiment.

In any event, you can always use a local lock to make these operations atomic.

# Stack offsets
VALUE = 0x08
POINTER = 0x0C

.section .data
__local_lock: .long 0
.section .text

.global add_atom
.type add_atom,@function

add_atom:

	pushf
	cli
	incb	(__local_lock)		# Set the lock
1:	cmpb	$1,(__local_lock)
	jnz	1b
	pushl	%ebx
	movl	VALUE(%esp), %eax
	movl	POINTER(%esp), %ebx
	addl	%eax, (%ebx)
	movl	(%ebx), %eax
	popl	%ebx
	decb	(__local_lock)		# Release the lock
	popf
	ret

The lock can also be done as:

	incb	(__local_lock)
1:	cmpb	$1,(__local_lock)
	jz	2f
	repz
	nop
	jmp	1b

2:

(maybe) the CPU being locked loops in low-power mode.

Cheers,
Dick Johnson

Penguin : Linux version 2.4.1 on an i686 machine (799.53 BogoMips).

"Memory is like gasoline. You use it up when you are running. Of course you get it all back when you reboot..."; Actual explanation obtained from the Micro$oft help desk.