Linux中断分层技术

一、中断嵌套
   当系统正在执行某中断处理函数时,又产生了一个新的中断,这就叫做中断嵌套。当中断为慢速中断时,新的中断会取代当前中断,即当前中断没有执行完就结束
了;当中断为快速中断时,新的终端就不会产生。这两种情况都是我们不愿意看到的情况,所以就有了今天的题目——中断分层。

二、中断分层
  中断分层是将中断处理函数分为上下两个部分。上半部是与硬件相关的,下半部是与硬件无关的。与硬件无关的内容我们就可以将它分离出中断处理函数,交给内核在系统空闲的时候处理,这样就缩短了中断处理的时间,从而减小了中断丢失的几率。
  分层方式:
    1、软中断
    2、tasklet
    3、工作队列
三、工作队列处理方式
  将中断下半部分的工作挂载到工作队列中去,在内核空闲的时候将工作调用。Linux内核使用struct    workqueue_struct来描述一个工作队列,用struct    work_struct来描述一个工作项。

struct workqueue_struct {
    unsigned int        flags;        /* I: WQ_* flags */
    union {
        struct cpu_workqueue_struct __percpu    *pcpu;
        struct cpu_workqueue_struct        *single;
        unsigned long                v;
    } cpu_wq;                /* I: cwq‘s */
    struct list_head    list;        /* W: list of all workqueues */

    struct mutex        flush_mutex;    /* protects wq flushing */
    int            work_color;    /* F: current work color */
    int            flush_color;    /* F: current flush color */
    atomic_t        nr_cwqs_to_flush; /* flush in progress */
    struct wq_flusher    *first_flusher;    /* F: first flusher */
    struct list_head    flusher_queue;    /* F: flush waiters */
    struct list_head    flusher_overflow; /* F: flush overflow list */

    mayday_mask_t        mayday_mask;    /* cpus requesting rescue */
    struct worker        *rescuer;    /* I: rescue worker */

    int            saved_max_active; /* W: saved cwq max_active */
    const char        *name;        /* I: workqueue name */
};

  

struct work_struct {
    atomic_long_t data;
    struct list_head entry;
    work_func_t func;
};

  1、创建工作队列
  create_workqueue(name)
  参数:name为const char *类型,创建工作队列的名字
  返回值:struct    workqueue_struct*型指针
  2、创建工作
  INIT_WORK(_work, _func)
  参数:

    work:创建好工作项变量的地址
    func:工作项中的成员func的名字
  无返回值
  3、提交工作
  即将工作项挂载到工作队列中去。
  int    queue_work(struct workqueue_struct *wq, struct work_struct *work)
  参数:

    wq:工作队列变量的地址
    work:工作项变量的地址

  

  其实Linux内核已创建好了一个默认的工作队列供用户使用,keventd_wq,这样我们就不用再去进行创建工作队列的工作。提交工作项到默认工作队列的函数为
  int    schedule_work(struct work_struct *work)
  参数:要提交工作项的地址

工作队列应用代码:

#include <linux/module.h>
#include <linux/init.h>

struct work_struct *work1,*work2;

void work1_func()
{
    printk("this is work1\n");
}

void work2_func()
{
    printk("this is work2\n");
}

int que_init()
{
    /*创建工作*/
    work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);

    INIT_WORK(work1, work1_func);

    /*挂载工作到工作队列*/
    schedule_work(work1);

    /*创建工作*/
    work2 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);

    INIT_WORK(work2, work2_func);

    /*挂载工作到工作队列*/
    schedule_work(work2);

    return 0;
}

void que_exit()
{

}

MODULE_LICENSE("GPL");
module_init(que_init);
module_exit(que_exit);

将中断分层应用到键盘中断驱动程序中:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/io.h>

#define GPGCON 0x56000060

/*定义工作队列*/
struct work_struct *work1;

void work1_func()
{
    printk("press key down\n");
}
int que_init()
{
    /*创建工作*/
    work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);

    INIT_WORK(work1, work1_func);
}

/*中断处理函数*/
irqreturn_t key_int(int irq, void *dev_id)
{
    /*1、检测设备是否产生中断*/

    /*2、清除中断产生标志*/

    /*3、提交下半部分工作*/
    schedule_work(work1);

    return 0;
}

void key_hw_init()
{
    unsigned int data;
    unsigned int *gpio_config;

    gpio_config = ioremap(GPGCON,4);
    data = readw(gpio_config);
    data &= ((3)|(3<<6)|(3<<10)|(3<<12)|(3<<14)|(3<<22));//~(0b11);
    data |= (2|(2<<6)|(2<<10)|(2<<12)|(2<<14)|(2<<22));//0b10;
    writew(data,gpio_config);
}

int key_open(struct inode *node, struct file *filp)
{
    return 0;
}

struct file_operations key_fops =
{
    .open = key_open,
    //.unlocked_ioctl = key_ioctl,
};

struct miscdevice key_miscdev =
{
    .minor = 200,
    .name = "key",
    .fops = &key_fops,
};

static int key_init()
{
    /*注册设备*/
    misc_register(&key_miscdev);

    /*硬件初始化*/
    key_hw_init();

    /*注册中断*/
    request_irq(IRQ_EINT8,key_int,IRQF_TRIGGER_FALLING ,"key", 0);
    request_irq(IRQ_EINT11,key_int,IRQF_TRIGGER_FALLING ,"key", 0);
    request_irq(IRQ_EINT13,key_int,IRQF_TRIGGER_FALLING ,"key", 0);
    request_irq(IRQ_EINT14,key_int,IRQF_TRIGGER_FALLING ,"key", 0);
    request_irq(IRQ_EINT15,key_int,IRQF_TRIGGER_FALLING ,"key", 0);
    request_irq(IRQ_EINT19,key_int,IRQF_TRIGGER_FALLING ,"key", 0);

    que_init();
    printk("key.ko is ready\n");
    return 0;
}

static void key_exit()
{
    /*注销设备*/
    misc_deregister(&key_miscdev);
    /*注销中断*/
    free_irq(IRQ_EINT8, 0);
}

MODULE_LICENSE("GPL");
module_init(key_init);
module_exit(key_exit);

实现功能:

  当按下一个按键,在串口中打印出对应的信息。

此代码适用mini2440开发板,不同型号开发板IO口和中断号不同。如果有疑问或建议,欢迎指出。

时间: 2024-12-28 12:19:19

Linux中断分层技术的相关文章

中断分层技术

1.Linux中断嵌套( 不同OS对中断的处理方式使不一样的) 慢速中断: 在中断处理的时候,中断的总开关是没有关闭的,允许其他中断的产生. 快速中断:总中断是关闭的. 当一个中断在执行的时候,其他中断出现,会忽略掉. 综上,所以会存在中断丢失. 假如一个中断程序的处理时间为10s,如果在7s的时候有一个中断处理程序出现,那么它就会被忽略而丢失掉,那么能不能提前完成这10s的中断处理程序呢,让它在7s之前结束,那么这样就极大的缩短了又一中断出现而被忽略的可能性. 那么怎么来缩短它呢?仔细分析中断

4.中断分层设计

Linux是如何来处理中断嵌套的: 所谓的中断嵌套就是,当一种中断正在执行的时候,又产生了另外中断.可以是同类型的,也可以是不同类型的. 首先先来分析第一种类型:慢速中断:是指在进行中断处理的时候,中断的总开关是不关闭的.允许其他类型中断产生. 快速中断:当中断产生的时候,控制位的IF为被置1,别的中断被禁止发生.这样就会产生我们不想看到的情况:中断丢失. 这就是中断分层技术解决的问题: 所谓的中断分层就是,把一个中断分为了上部分和下部分.上部分是硬件相关的,必须要执行的.下部分是检查,处理工作

中断分层处理-工作队列

4.中断分层处理a.中断嵌套中断嵌套指的是当一种中断产生的时候,又发现了另一种类型的中断.b.中断分层方式假如一个中断处理程序需要10秒钟,中断处理程序运行到第七秒的时候,出现了另外一种类型的中断,但是另外一种类型的中断丢失掉了,那么如何解决呢?一种方法是将中断处理的时间尽量缩短,减少丢失中断的可能.那么如何缩短处理的时间呢?中断处理的工作分为两种,一种与硬件相关,另一种是程序做的工作,包括中断检测,中断处理(可以将这部分工作放到其他部分来工作),这个就叫中断分层技术.另一种是a.1软中断 a.

Linux中断技术、异常控制技术总结归类

相关学习资料 <深入理解计算机系统(原书第2版)>.pdf http://zh.wikipedia.org/zh/%E4%B8%AD%E6%96%B7 独辟蹊径品内核:Linux内核源代码导读 李云华著 中文 PDF版 https://www.kernel.org/ http://blog.csdn.net/orange_os/article/details/7485069 http://blog.csdn.net/sunnybeike/article/details/6958473 目录 1

Linux内核调试技术——jprobe使用与实现

前一篇博文介绍了kprobes的原理与kprobe的使用与实现方式,本文介绍kprobes中的第二种探测技术jprobe,它基于kprobe实现,不能在函数的任意位置插入探测点,只能在函数的入口处探测,一般用于监测函数的入参值.本文首先通过一个简单的示例介绍jprobe的使用方式,然后通过源码详细分析jprobe的实现流程. 内核源码:Linux-4.1.x 实验环境:Fedora25(x86_64).树莓派1b 1.jprobe使用实例 使用jprobe探测函数的入参值,需要编写内核模块.同k

Linux中断完全分析

学习本文可以对linux中断有全面而深刻的认识.本文对Linux中断所涉及的需求.管理机制.中断实现.中断接口(上半部和下半部).驱动使用进行完全分析. 一.中断需求 软件是需求驱动的,软件的出现是为了解决需求和问题的.先知道需求,那理解代码就是为了验证已知的问题:不知道需求,那理解代码就是揣摩设计者的目的.两者相比,前者自然效率跟高. 中断是为了解决异步的需求.紧急的事情或者更高优先级的事情需要先做,就代表异步.例如,手机需要时刻优先响应用户按键或者触摸这个事件,否则用户体验就变差.信号是软件

Linux中断管理 (3)workqueue工作队列

目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管理 (3)workqueue工作队列> 关键词: 工作队列的原理是把work(需要推迟执行的函数)交由一个内核线程来执行,它总是在进程上下文中执行. 工作队列的优点是利用进程上下文来执行中断下半部操作,因此工作队列允许重新调度和睡眠,是异步执行的进程上下文,它还能解决软中断和tasklet执行时间过长导

嵌入式Linux的调试技术

嵌入式Linux的调试技术对于复杂的Linux驱动以及HAL等程序库,需要使用各种方法对其进行调试.例如,设置断点.逐步跟踪代码.输出调试信息等. Printk函数的用法与printf函数类似,只不过printk函数运行在内核空间,printf函数运行在用户空间.也就是说,像Linux驱动这样的Linux内核程序只能使用printk函数输出调试信息.Printk函数在printk.c文件中实现. 虽然使用printk函数可以很方便的将消息写入日志文件或控制台.但大量使用printk函数频繁操作日

第十章 嵌入式Linux的调试技术

本章的主要内容是嵌入式Linux的调试技术.对于复杂的Linux驱动及HAL等程序库,需要使用各种方法对其进行调试. 一.打印内核调试信息:printk 该函数的用法与printf函数类似,只不过printk函数运行在内核空间,printf函数运行在用户空间.像Linux驱动这样的Linux内核程序只能使用printk函数输出调试信息.Printk函数在printk.c文件中实现,该文件的路径:/root/kernel/linux_kernel_2.6.36/kernel/printk.c. 二