Linux设备驱动程序 之 tasklet
多数情况下,为了控制一个寻常的硬件设备,tasklet机制都是实现自己下半部的最佳选择;tasklet可以动态创建,使用方便,执行起来还算快;
声明tasklet
tasklet既可以静态的创建,也可以动态的创建;如果准备静态的创建一个tasklet,可以使用下面的两个宏之一:
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, , ATOMIC_INIT(), func, data } #define DECLARE_TASKLET_DISABLED(name, func, data) \
struct tasklet_struct name = { NULL, , ATOMIC_INIT(), func, data }
两个宏都能根据给定的名称静态的创建一个tasklet_struct结构;当该tasklet被调度以后,给定函数func会被执行,它的参数是data;前面一个宏创建的tasklet的引用计数设置为0,该tasklet处于激活状态;另一个宏引用计数为1,该tasklet处于禁止状态;
tasklet处理程序
tasklet处理程序必须符合以下定义:
void tasklet_handler(ungigned long data)
因为靠软中断实现,所以tasklet不能睡眠;这意味着你不能再tasklet中使用信号量或者其他阻塞式的函数;由于tasklet运行时允许响应中断,所以必须做好预防工作,如果你的tasklet和中断处理程序之间共享了某些数据的话;两个相同的tasklet绝不会同时执行,这点和软中断不同,尽管两个不同的tasklet可以再两个处理器上同时执行;如果tasklet和其他的tasklet或者软中断共享了数据,就必须进行锁保护;
调度tasklet
通过调用tasklet_schedule()函数并传递给它们相应的tasklet_struct指针,该tasklet就会被调度以便执行;
void tasklet_schedule(struct tasklet_struct *t)
在tasklet被调度以后,只要有机会它就会尽可能早的运行。在它还没有得到运行机会之前,如果有一个相同的tasklet又被调度了,那么它只会运行一次;如果这时它已经开始运行了,比如说在另外一个处理器上,那么这个新的tasklet会被调度并再次运行;作为一种优化措施,一个tasklet总在调度它的处理器上执行–这是希望能更好的利用处理器的高速缓存;
禁用启用tasklet
tasklet_disable()用来禁止某个指定的tasklet,如果该tasklet当前正在执行,这个函数会等到它执行完毕再返回;还可以调用tasklet_disable_nosync(),它也用来禁止指定的tasklet,不过它无需等待tasklet执行完毕,这么做通常不安全,因为无法估计tasklet是否仍在执行;调用tasklet_enable()可以激活一个tasklet,如果希望激活DECLARE_TASKLET_DISABLED()宏创建的tasklet,也需要调用这个函数;
void tasklet_disable_nosync(struct tasklet_struct *t)
void tasklet_disable(struct tasklet_struct *t) void tasklet_enable(struct tasklet_struct *t)
删除挂起tasklet
可以通过调用tasklet_kill()从挂起的队列中去掉一个tasklet,该函数的参数一个指向某个tasklet的tasklet_struct指针;在处理一个经常重新调度它自身的tasklet的时候,从挂起的队列中移除已调度的tasklet很有用;这个函数首先等待tasklet执行完毕,然后再将它移除;当然,没什么方法可以阻止其他地方的代码重新调度该tasklet;由于该函数可能引起休眠,所以禁止在中断上下文中使用;
void tasklet_kill(struct tasklet_struct *t)
ksoftirq
每个处理器都有一组辅助处理软中断(和tasklet)的内核线程;当内核中出现大量的软中断的时候,这些内核线程就会辅助处理它们;
每个处理器都有一个处理线程,名字叫做ksoftirqd/n,区别在于n,它对应着处理器的编号;在一个双处理器上就有两个这样的线程,分别叫ksoftirq/0和ksoftirq/1;为了保证只要有空闲的处理器,就会处理软中断,所以每个处理器都会分配一个这样的线程;一旦初始化,就会执行死循环处理中断;只要有待处理的中断,ksoftirq就会调度do_softirq()去处理它们;当所有中断处理完成之后,内核线程将自己设置为TASK_INTERRUPTIBLE状态,以唤起调度程序选择其他可执行线程投入运行;
Linux设备驱动程序 之 tasklet的更多相关文章
- linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)
原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...
- 【转】linux设备驱动程序中的阻塞机制
原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...
- Linux设备驱动程序 第三版 读书笔记(一)
Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...
- Linux设备驱动程序学习之分配内存
内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...
- 教你写Linux设备驱动程序:一个简短的教程
教你写Linux设备驱动程序:一个简短的教程 http://blog.chinaunix.net/uid-20799298-id-99675.html
- linux设备驱动程序_hello word 模块编译各种问题集锦
在看楼经典书籍<linux设备驱动程序>后,第一个程序就是编写一个hello word 模块. 原以为非常easy,真正弄起来,发现问题不少啊.前两天编过一次,因为没有记录,今天看的时候又 ...
- Linux设备驱动程序学习----1.设备驱动程序简介
设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介 Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...
- Linux设备驱动程序学习----2.内核模块与应用程序的对比
内核模块与应用程序的对比 更多内容请参考Linux设备驱动程序学习----目录 1. 内核模块与应用程序的对比 内核模块和应用程序之间的不同之处: 大多数中小规模的应用程序是从头到尾执行单个任务,而模 ...
- Linux设备驱动程序学习----3.模块的编译和装载
模块的编译和装载 更多内容请参考Linux设备驱动程序学习----目录 1. 设置测试系统 第1步,要先从kernel.org的镜像网站上获取一个主线内核,并安装到自己的系统中,因为学习驱动程序的编写 ...
随机推荐
- 【轻松一刻】Java制作字符动画
前言 今晚闲来无事,整理了一下电脑中尘封已久的旧代码,看着那些年自己写过的代码,踩过的坑,顿时老泪纵横.正当在感叹之际,突然发现在“马克思”文件夹下出现了一个好玩的项目,那就是N年前刚学Java时写的 ...
- less学习大纲总结
1.注释的区别 /**/ //2.变量的命名 @+变量名 如:@f_width 引用的时候也要带上@ 符号3.混合 可带参数 默认带值4.匹配模式 相当于js里的if,但不完全是 用于符号条件的匹配 ...
- java注解日志记录到数据库
1. pom添加依赖包 <!--添加aop依赖--><dependency> <groupId>org.springframework.boot</group ...
- 关于微信小程序发布新版本后的提示用户更新的方法详解
当小程序发布新的版本后 ,用户如果之前访问过该小程序,通过已打开的小程序进入(未手动删除),则会检测新版本,提醒用户更新新的版本 话不多说,上代码 App({ onLaunch: function ( ...
- nodejs入门API之path模块
Path模块在各个系统上的差异 Path模块API解析 一.Path模块在各个系统上的差异 path模块提供用于处理文件路径和目录路径的使用工具. let path = require('path') ...
- moment——日期格式化常用示例
<template> <div id="app" style="text-align: center;"> <h1>{{ m ...
- js 面试题一
1.格式化数字,每三位加逗号 // 实现方式一 function formatNum(num){ var _num = num + ""; var result = "& ...
- springboot中使用cache和redis
知识点:springboot中使用cache和redis (1)springboot中,整合了cache,我们只需要,在入口类上加 @EnableCaching 即可开启缓存 例如:在service层 ...
- nginx 普通用户使用80端口启动nginx
方法一: 依次执行如下命令 cd /usr/local/nginx/sbin/ chown root nginx chmod u+s nginx 优点是,方便简单,缺点是,既然sudo权限都不给了.这 ...
- duilib学习领悟(4)
使用duilib创建的主窗口绘制工作全都发生在一个 真实存在的主窗口句柄当中,这个绘制过程稍稍有些复杂,但再复杂也逃不过WM_PAINT消息,所有的绘制工作也都由这个WM_PAINT消息完成.在上几篇 ...