day05

5837 단어
답변:
linux中的中断处理
request_irq(irq, 핸들러, 플래그, 이름, dev)
irq, 中断号
핸들러, 处理函数
플래그, IRQF_TRIGGER_RISING
...
IRQF_공유
이름
dev, 调用handler时传递的参数

    free_irq(irq, dev)
        dev, 和注册时保持一致

    裁剪掉内核中自带的按键驱动程序
 中断处理函数的特点:
     1)工作于中断下文
     2)中断处理过程执行速度越快越好,尽快结束
     3)在其中不能调用引起阻塞睡眠的函数
     4)有独立的栈空间,一般为一个内存页
     5)其中不能和用户空间进行数据的交互
 希望中断处理尽快结束,但是有些中断处理起来就是耗时
 为此内核引起了顶半部、底半部的概念
 紧急的工作由顶半部完成,完成就返回被打断的位置继续执行
 耗时的、不紧急的工作放在底半部完成
 如何登记底半部?

1、登记底半部的方式
1.1 软中断的方式

1.2 tasklet的方式
    struct tasklet_struct
    {
        func
        data
        ...
    }    
    1) 定义并初始化变量
       struct tasklet_struct btn_tasklet
       void tasklet_init(&btn_tasklet, func, data)
    2) 登记底半部
       tasklet_schedule(&btn_tasklet); 

    其特点: tasklet机制是基于软中断机制实现的
             tasklet.func工作于中断上下文
             也就是要求func中不能调用引起阻塞睡眠的函数

             极有可能直接导致内核的崩溃

    矛盾: 在底半部中应用需求必须要调用引起睡眠
           或者阻塞的函数,怎么办?

           工作者队列
1.3 工作者队列登记底半部
    struct work_struct
    {
       work_func_t func;//底半部的工作封装在其中
       ...
    }
    struct delayed_work {
            struct work_struct work;
            struct timer_list timer; //延时时间
        };

    如何通过该数据结构完成底半部的登记,操作步骤:
        1)定义变量
           struct work_struct btn_work;
           struct delayed_work btn_dwork;
        2) 初始化变量
           INIT_WORK(&btn_work, btn_work_func)
           INIT_DELAYED_WORK(&btn_dwork, btn_dwork_func)
        3) 登记底半部
           schedule_work(&btn_work)
           int schedule_delayed_work(&btn_dwork,unsigned long delay)
            delay: 延时的时间  
      4) 确保登记的底半部被执行或者取消
         void flush_scheduled_work(void)
           作用:确保默认工作者队列中所有的工作都执行完毕
                 该函数才返回
         bool flush_delayed_work(struct delayed_work *dwork)
            作用: 确保指定的dwork被执行完毕才返回
         flush_work(struct work_struct *work)
         cancel_delayed_work_sync
         cancel_work_sync  
  tasklet和work相比较:
      1)work在其中可以调用引起阻塞睡眠函数
      2)tasklet登记的底半部得到的响应更及时
         tasklet登记的底半部一般会先于
         work登记的底半部被执行到
  work登记的底半部中为什么就可以调用引起阻塞或者睡眠的函数呢?
      work对应的底半部函数是在进程上下文中被调用的

  对于delayed_work,第一次登记的底半部如果未被执行
  第二次登记无效。

  对于tasklet和work的总结:
      如果希望底半部得到更为及时的响应,并且
      底半部中没有调用引起阻塞睡眠的函数,使用tasklet

      如果底半部中需要调用引起阻塞睡眠的函数,使用work

      如果希望底半部延时执行,使用delayed_work

      注意:对于work的flush动作的理解
            1)防止在底半部未执行,而发生模块卸载的动作
            2)用于同步

               内核中有一个逻辑
               {
                  ...
                  ...
                  需要在你的某个work执行完毕后,
                  再去执行后序代码
                  flush_work(&work)
                  。。。
                  。。。

               }

问题: 谈谈你对中断的理解?
中断是异常的一种
中断是计算机中处理异常事件的重要机制

 ARM中中断异常的处理流程
    设置按键按下能触发中断异常
        中断源
        中断控制器
        ARM core
    异常触发硬件干4件事
    异常向量表
    跳转真正中断处理程序
        保护现场
        调用c函数处理中断异常
        恢复现场
 中断处理函数的特点
     1)执行速度越快越好
     2)linux系统中的中断服务程序
        不能调用引起阻塞睡眠的函数
        有独立的栈空间
        不能做和用户空间的数据交互
 linux中可以将中断分为顶半部和底半部
 如何登记底半部
     tasklet work

2, 定时器
5초 : 5*HZ

系统时钟中断:
ARM 코어 会不停的接收系统时钟中断信号
아치/팔/mach-s5p6818/cpu.c
.timer = &nxp_cpu_sys_timer,
处理系统时钟中断信号:
更新墙上时间
判断当前线程的时间片是否耗尽,是否重新做任务调度
....
HZ: 1秒钟产生系统时钟中断的次数
当前版本的内核中HZ=1000
jiffies: 32bit无符号整型变量
记录自开机以来经历的系统时钟中断的次数
每次系统时钟中断到来在中断服务程序中
都会jiffies += 1;

        4294967295
          1s: 1000
          1分钟:60000
          1小时:3600000
          大概不关机50天溢出

진드기: 记录每次系统时钟中断的间隔
틱 = 1/Hz

2.1 内核定时器
软件实现的定时器

  struct timer_list
  {
     ... 
     //定时器的超时时间
     unsigned long expires;
     //定时时间到后要调用的函数
     void (*function)(unsigned long);
     //调用function时传递的参数
             unsigned long data;
  }

  定时器如何使用:
  1)定义一个timer_list变量
    struct timer_list   btn_timer;
  2) 初始化timer_list变量
    init_timer(&btn_timer)
    btn_timer.function = xxx_func
    btn_timer.expires = ...
    btn_timer.data = ...
  3) 启动定时器开始计时
     add_timer(&btn_timer) 
  4) 取消定时器
     del_timer(&btn_timer) 
  5) 重新修改定时器的超时时间
     int mod_timer(struct timer_list *timer, unsigned long expires)
        作用: 
            1)修改处于计时状态的定时器的超时时间
            2)启动定时器
练习1:使用timer_list让LED1 亮1s 灭1s 亮1s ....
练习2:闪烁的时间间隔改成0.5S
                          0.1s
                          0.2s
       在用户空间调整闪烁的时间间隔                   

3、内核的竞态与并发

并发:多任务同时执行
对于单核的CPU来说 宏观上并行 微观上串行
共享资源:文件 硬件设备 共享内存 内核中的全局变量
linux内核中产生竞态的原因:
1)SMP 对称多处理器(多核)
都要操作LCD
2) 进程之间的抢·共享资源
3)进程和中断之间发生共享资源的抢…
LCD
网卡
可见的内存 (文件 共享内存 全局变量)
4)中断和中断之间的资源抢…
中断是有优先级的
linux内核中解决竞争状态的策略(LDD3)
1)中断屏蔽
2) 原子操作
3)자유로운
4)신용량

以串口的用为例:
串口设备同一时刻只能被一个进程所使用

 问:该策略的实现是由应用程序保证还是
     由串口的驱动程序保证? 

回调函数
函数的可重入性
最明显的标志:该函数是否使用了全局变量
최대 정수 = 100;
정수 테스트(정수 값)
{
최대 = 값;
if(최대 >10)
...
또 다른
...
}
test 函数不具有可重入性
同一个进程内的两个线程
답:
...
테스트(5);
线程:
...
테스트(200);

좋은 웹페이지 즐겨찾기