Race Condition
-
Upload
tamara-green -
Category
Documents
-
view
60 -
download
0
description
Transcript of Race Condition
1
Race Condition
제 43 강 : Interrupt(III) Race Condition
2
Race Condition
CPU CPU CPU CPU
PIC
IRQ
shared memory
timer
Network
SCSI
irq_desc[ ]IRQ1
IRQ2
IRQ3
IRQm
g1() g2()
f1() f2()
action
action
ISR
‘
Many CPU’s are competing to access shared variable spin_lock( ) spin_unlock( )
Hard Disk
Floppy Disk
Many IRQ lines are competing for PICInterrupt disables PICack(irq) reenables PIC operation
New IRQ request should guarantee minimum time for previous IRQ processing Interrupt disables further CPU interrupt
local_irq_enable() reenables CPU interrupt
3
do-IRQ() – critical section
irq_desc[IRQm] becomes a shared variable do_IRQ() becomes critical section need mutual exclusion by spinlock() must run atomically should not be preempted in the middle CPU interrupt disabled
CPUi do_IRQ() ack() access selected irq_desc[IRQm]
PIC request CPUk access
released from IRQm selected irq_desc[IRQm]
4
ISR is not a critical section
handle_IRQ_event() is not a critical sectionbecause IRQm requests are serialized at particular CPUk
spin-unlock() before entering handle_IRQ_event() CPU interrupt enabled before entering handle_IRQ_event() Multiple CPU’s compete for irq_desc[IRQm]
irq_desc[IRQm] becomes a shared variable do_IRQ() is a critical section mutual exclusion by spinlock()do_IRQ() must run atomically should not be preempted in the middle CPU interrupt disabled
do_IRQ() handle_IRQ_event()
CPU CPU CPU CPU
PIC
IRQ Hard Disk
CPU
shared memory
timer
Network
SCSI
irq_desc[ ]IRQ1
IRQ2
IRQ3
IRQm
g1() g2()
f1() f2()
action
action
ISR
Floppy Disk
5
asmlinkage unsigned int do_IRQ(struct pt_regs regs){ int irq = regs.orig_eax & 0xff; /* get irq vector on stack, put it into local variable */ irq_desc_t *desc = irq_desc + irq; /* pointer to array */ struct irqaction * action; unsigned int status; irq_enter(); kstat_this_cpu.irqs[irq]++; spin_lock(&desc->lock); /* wait if locked */ desc->handler->ack(irq);
status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); /* dev not waiting any more*/ status |= IRQ_PENDING; /* Ack’ed. Need to handle it. */ action = NULL; /* initial value for action == NULL */ if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { action = desc->action; status &= ~IRQ_PENDING; status |= IRQ_INPROGRESS; } descstatus = status; if (unlikely(!action)) goto out; /* If nothing has been assigned to action, do nothing */
Status
Handler
Lock
action
timer
Network
SCSI
irq_desc[ ]IRQ1
IRQ2
IRQ3
IRQm
g1() g2()
f1() f2()
action
action
ISR
6
for (;;) { irqreturn_t action_ret; spin_unlock(&desc->lock); action_ret = handle_IRQ_event(irq, ®s, action); /* call handler */ spin_lock(&desc->lock); if (!noirqdebug) note_interrupt(irq, desc, action_ret); if (likely(!(desc->status & IRQ_PENDING)))/*Re-check PENDING. I cleared before*/ break; /* It remains in reset state. Exit do_IRQ() */ desc->status &= ~IRQ_PENDING; /* New arrival. I handle it. Still INPROGRESS */} desc->status &= ~IRQ_INPROGRESS; /* No longer INPROGRESS */out: desc->handler->end(irq); spin_unlock(&desc->lock); irq_exit(); return 1;}
Status
Handler
Lock
action
timer
Network
SCSI
irq_desc[ ]IRQ1
IRQ2
IRQ3
IRQm
g1() g2()
f1() f2()
action
action
ISR
7
int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action){ int status = 1; /* Force the "do bottom halves" bit */ int retval = 0;
if (!(action->flags & SA_INTERRUPT)) local_irq_enable();
do { status |= action->flags;
retval |= action->handler(irq, action->dev_id, regs); action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); return retval;}
ISR is device specific operationISR does not share variableISR is not a critical section
ISR execution does not have to be atomic
This CPU may be interrupted while in ISR
PIC can interrupt this CPUwhile it is running ISR
Status
Handler
Lock
action
timer
Network
SCSI
irq_desc[ ]IRQ1
IRQ2
IRQ3
IRQm
g1() g2()
f1() f2()
action
action
ISR
8
asmlinkage unsigned int do_IRQ(struct pt_regs regs)
{ int irq = regs.orig_eax &
0xff; irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status;
irq_enter(); kstat_this_cpu.irqs[irq]++;
spin_lock(&desc->lock);
desc->handler->ack(irq);
status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
status|= IRQ_PENDING; /* signal arrived. Just acked */
action = NULL; if (likely(!(status & (IRQ_DISABLED |
IRQ_INPROGRESS)))) {
action = desc->action; status &= ~IRQ_PENDING; /* we commit to
handling */ status|= IRQ_INPROGRESS;/* we’re
handling it */ } desc->status = status; if (unlikely(!action)) goto out;
for (;;) { irqreturn_t action_ret; spin_unlock(&desc->lock); action_ret = handle_IRQ_event(irq,
®s, action); spin_lock(&desc->lock); if (!noirqdebug) note_interrupt(irq, desc,
action_ret); if (likely(!(desc->status &
IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; } desc->status &= ~IRQ_INPROGRESS;out: desc->handler->end(irq); spin_unlock(&desc->lock); irq_exit(); return 1;}int handle_IRQ_event( ….){ int status = 1;
int retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { status |= actionflags; retval |= actionhandler(irq, action-
>dev_id, regs); action = actionnext; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); return retval;}
Critical Top-Half Interrupt Handler
Non-critical Top-Half
9
asmlinkage unsigned int do_IRQ(struct pt_regs regs)
{ int irq = regs.orig_eax &
0xff; irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status;
irq_enter(); kstat_this_cpu.irqs[irq]++;
spin_lock(&desc->lock);
desc->handler->ack(irq);
status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
status|= IRQ_PENDING; /* signal arrived. Just acked */
action = NULL; if (likely(!(status & (IRQ_DISABLED |
IRQ_INPROGRESS)))) {
action = desc->action; status &= ~IRQ_PENDING; /* we commit to
handling */ status|= IRQ_INPROGRESS;/* we’re
handling it */ } desc->status = status; if (unlikely(!action)) goto out;
for (;;) { irqreturn_t action_ret; spin_unlock(&desc->lock); action_ret = handle_IRQ_event(irq,
®s, action); spin_lock(&desc->lock); if (!noirqdebug) note_interrupt(irq, desc,
action_ret); if (likely(!(desc->status &
IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; } desc->status &= ~IRQ_INPROGRESS;out: desc->handler->end(irq); spin_unlock(&desc->lock); irq_exit(); return 1;}int handle_IRQ_event( ….){ int status = 1;
int retval = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { status |= actionflags; retval |= actionhandler(irq, action-
>dev_id, regs); action = actionnext; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); return retval;}
If this ISR needs too much time to complete work for this devicethis ISR just sets a bit here, meaning
“more work needs to be done for this device (Bottom Half required)”This bit is called “soft-irq pending bit”
Then this interrupt handler terminates.This bit is processed later by do_softirq() function
timer
Network
SCSI
irq_desc[ ]IRQ1
IRQ2
IRQ3
IRQm
g1() g2()
f1() f2()
action
action
ISR
10
When & who calls do_softirq()?
1. Returning hardware interrupt handler– before do_IRQ() returns – it calls irq_exit() do_softirq()
2. kernel thread– low priority kernel thread called ksoftirqd_CPUn – It runs ksoftirq() function, which calls
do_softirq()
3. Any code (such as network subsystem)– checks softirq pending bit and calls do_softirq()
Love, Chapter 7
Bovet, p. 150
11
Urgent/non-urgent work in TCP/IP
CPUi selected
updateirq_desc[IRQm]
do_IRQ()
ack()
move packetfrom NIC to memory
IP
TCP
move packet to socket
ftp
PIC
IRQ NIC
Floppy Disk
12
Which part is done in which moduleTCP/IP
• [Hardware] -- NIC (Network Interface Card)
– receives a packet from network – issues interrupt to CPUN
• [Top Half] -- Interrupt Handler– Critical Top half (do_IRQ()) Ack, assign a CPU for IRQnetwork
– Non-Critical Top half (ISR) Allocates struct sk_buff for packet copy packet from NIC to sk_buff
raise “bottom half required” (set bit)
• [Bottom Half] -- do_softirq()– delivers packet to IP protocol handler
• remote? – forward packet to other host • local? – invoke TCP handler
– delivers packet to TCP handler • delivers packet to the socket associated with the portk
PIC
IRQ NIC
Floppy Disk
13
Top half & Bottom half(TCP/IP example)
(2) Runs interrupt handler
(1) Interrupt CPU (CPU/PIC is interrupt disabled)
(3) Schedule bottom halves (i.e. set bottom half bits)
(5) kernel executes bottom half(if the bit is set)
Top Half Bottom Half
(4) exit I.H.
ack
Assigned CPUruns ISR whichcopies data from NIC to kernel
Assign CPU to IRQ
Device requests interruptPIC select CPU &Sends signal to CPU
IP handlerroutespacket data
TCP handlerAssemblesDataInsert dataInto socketWakeupapplication
do_IRQ() ISR
Later …