驱动: 中断【1】linux中断流程

本文介绍了Linux内核中的中断处理机制,包括中断处理程序如何分为上半部和下半部来确保系统的稳定运行。上半部处理严格时限的任务,而下半部则负责延后的任务。此外,还详细解析了Tasklet的实现方式及其与中断处理的关系。

通常情况下,当一个给定的中断处理程序正在执行时,所有其他的中断都是打开的,所以这些不同中断线上的其他中断都能被处理,但当前中断总是被禁止的。

将中断处理切为两个部分或两半。中断处理程序上半部(top half)---接收到一个中断,它就立即开始开始执行,但只做严格时限的工作,这些工作都是在所有中断被禁止的情况下完成的。同时,能够被允许稍后完成的工作推迟到下半部(bottom half)去,此后,下半部会被执行,通常情况下,下半部都会在中断处理程序返回时立即执行。

当执行一个中断处理程序或下半部时,内核处于中断上下文(interrupt context)中。

对比进程上下文,在进程上下文可以随时休眠,也可以调度程序。但中断上下文却完全不是这样,它不可以休眠。如果一个函数睡眠,就不能在中断处理程序中使用它。

此外,禁止中断还可以禁止内核抢占。然而,不管是禁止中断还是禁止内核抢占,都没有提供任何保护机制来防止来自其他处理器的并发访问。Linux支持多处理器,因此,内核代码一般都需要获取某种锁,防止来自其他处理器对共享数据的并发访问,获取这些锁的同时也伴随着禁止本地中断。锁提供保护机制,防止来自其他处理器的并发访问,而禁止中断提供保护机制,则是防止来自其他中断处理程序的并发访问。

 

下面是内核代码中的atmel-mci.c,正好使用了tasklet_schedule

static int __init atmci_init(void)
{
    return platform_driver_probe(&atmci_driver, atmci_probe);
}

static int __init atmci_probe(struct platform_device *pdev)
{
    struct atmel_mci        *host;
    regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    irq = platform_get_irq(pdev, 0); //platform_get_resource(dev, IORESOURCE_IRQ, num);
    ...
    spin_lock_init(&host->lock);
    tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
    ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
}

static void atmci_tasklet_func(unsigned long priv)
{
    spin_lock(&host->lock);
    do_sth();//
    spin_unlock(&host->lock);
}

static irqreturn_t atmci_interrupt(int irq, void *dev_id)
{
    ...
    tasklet_schedule(&host->tasklet);
    ...
}
//A tasklets can be concurrent with other tasklets, tasklet是参与调度的。
//Tasklets run in software interrupt context with the result that all tasklet code must be atomic. 
void __tasklet_schedule(struct tasklet_struct *t)
{
    unsigned long flags;
    /*
    local_irq_save和 local_irq_disable  http://www.360doc.com/content/14/0605/16/10249440_384022354.shtml

    在2.6内核中,可以通过下面两个函数中的其中任何一个关闭当前处理器上的所有中断处理,这两个函数定义在 <asm/system.h>中:
    void local_irq_save(unsigned long flags);
    void local_irq_disable(void);

    在2.6内核, 没有方法全局禁用整个系统的所有中断。 内核开发者认为关闭所有中断的代价太高,因此没有必要提供这个能力。
    */
    local_irq_save(flags);
    t->next = NULL;
    *__get_cpu_var(tasklet_vec).tail = t;
    __get_cpu_var(tasklet_vec).tail = &(t->next);
    raise_softirq_irqoff(TASKLET_SOFTIRQ);
    local_irq_restore(flags);
}

工作队列(workqueue) http://blog.chinaunix.net/uid-24148050-id-296982.html

  关于工作队列和tasklet的比较,可参考ldd3第7章。

linux中断流程详解 http://blog.chinaunix.net/uid-25622207-id-2897963.html

转载于:https://www.cnblogs.com/mylinux/p/5532295.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值