Race Condition

13
1 Race Condition 43 제 : Interrupt(III) Race Condition

description

제 43 강 : Interrupt(III) Race Condition. Race Condition. Race Condition. New IRQ request should guarantee minimum time for previous IRQ processing Interrupt disables further CPU interrupt local_irq_enable() reenables CPU interrupt. ‘. CPU. CPU. CPU. CPU. shared memory. PIC. - PowerPoint PPT Presentation

Transcript of Race Condition

Page 1: Race Condition

1

Race Condition

제 43 강 : Interrupt(III) Race Condition

Page 2: 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

Page 3: Race Condition

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]

Page 4: Race Condition

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

Page 5: Race Condition

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

Page 6: Race Condition

6

for (;;) { irqreturn_t action_ret; spin_unlock(&desc->lock); action_ret = handle_IRQ_event(irq, &regs, 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

Page 7: Race Condition

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

Page 8: Race Condition

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,

&regs, 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

Page 9: Race Condition

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,

&regs, 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

Page 10: Race Condition

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

Page 11: Race Condition

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

Page 12: Race Condition

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

Page 13: Race Condition

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 …