Re: race conditions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jun 10, 2004 at 13:23:50 -0400, Ed L Cashin wrote:
> Can anybody point out a specific problem with the (2.4) code below?
> When I saw it, it made me uneasy because I'd heard somewhat vague
> warnings against doing stuff like this.  I can't see how the x86
> implementation could have a problem, but maybe some other architecture
> would?

Sure I can -- I have looked at actual implementations when I was
answering previous question....

> static struct mylock {
>        spinlock_t lock;
>        unsigned long flags;
> } mylock;
> 
> void lock(struct mylock *p)
> {
>     spin_lock_irqsave(&p->lock, p->flags);
> }

which is (because the #define of spin_lock_irqsave expands to it)
void lock(struct mylock *p) {
    local_irq_save(p->flags);
    spin_lock(&p->lock);
}

> void unlock(struct mylock *p)
> {
>     spin_lock_irqrestore(&p->lock, p->flags);
> }

and this in turn is:
void unlock(struct mylock *p) {
    spin_unlock(&p->lock);
    local_irq_restore(&p->lock);
}

> void demonstration(void)
> {
>     lock(&mylock);
>     /* do stuff that doesn't sleep */
>     unlock(&mylock);
> }

Now things start to happening...

CPU1				CPU2
(interrups enabled here)	(interrupts disabled here)
local_irq_save(p->flags)
=> saved interrupts enabled
				local_irq_save(p->flags)
				=> saved interrupts disabled
spin_lock(&p->lock)
=> locked
				spin_lock(&p->lock)
				...
stuff is done...		...
spin_unlock(&p->lock)		...
=> unlocked			... still spinning
				=> locked
local_irq_restore(p->flags)
=> interrupt STILL DISABLED!
				stuff is done...
				spin_unlock(&p->lock)
				=> unlocked
				local_irq_restore(p->flags)
				=> interrupt disabled

CPU1 will never enable the interrupts...

I am not sure whether the race will happen on UP, but I think it will,
since (IIRC) interrupt handlers run with interrupts DISABLED. So, taking
into account that local_irq_save is pushfl; popl (flags); cli:

On the other hand, if you know the interrupt handler will run with
disabled interrupts, you won't irqsave/irqrestore (but if the function
is sometimes called from interrupt and sometimes not, you will ... and
lock up)

pushfl
popl (p->flags)
=> so now p->flags contain enabled interrupts...
<-- INTERRUPT REQUEST COMES IN
    interrupts are now disabled
pushfl
popl (p->flags)
=> but now p->flags contain DISABLED interrupts...
cli
=> nothing happens...
lock is locked OK, sutuff gets done, lock is released
pushl (p->flags)
popfl
=> interrupts still disabled...
--> INTERRUPT REQUEST FINISHED
    interrupts were enabled, iret
cli
=> interrupts disabled
lock is locked OK, stuff gets done, lock is released
pushl (p->flags)
=> still contains the DISABLED interrupts...
popfl
=> interrupts still disabled...

CPU will never enable interrupts....


-------------------------------------------------------------------------------
						 Jan 'Bulb' Hudec <bulb@ucw.cz>

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux