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