linux驱动之内核多线程(四)
本文摘自
http://www.cnblogs.com/zhuyp1015/archive/2012/06/13/2548494.html
自己创建的内核线程,当把模块加载到内核之后,可以通过:ps –ef 命令来查看线程运行的情况。通过该命令可以看到该线程的pid和ppid等。也可以通过使用kill –s 9 pid 来杀死对应pid的线程。如果要支持kill命令自己创建的线程里面需要能接受kill信号。这里我们就来举一个例,支持kill命令,同时rmmod的时候也能杀死线程。
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/param.h>
#include <linux/jiffies.h>
#include <asm/system.h>
#include <asm/processor.h>
#include <asm/signal.h>
#include <linux/completion.h> // for DECLARE_COMPLETION()
#include <linux/sched.h>
#include <linux/delay.h> // mdelay()
#include <linux/kthread.h>
MODULE_LICENSE("GPL");
static DECLARE_COMPLETION(my_completion);
static struct task_struct *task;
int flag = ;
int my_fuction(void *arg)
{
printk(" in %s()\n", __FUNCTION__);
allow_signal(SIGKILL); //使得线程可以接收SIGKILL信号
mdelay();
printk(" my_function complete()\n");
printk("should stop: %d\n",kthread_should_stop());
while (!signal_pending(current) && !kthread_should_stop()) {//使得线程可以可以被杀死,也可以再rmmod的时候结束
printk(" jiffies is %lu\n", jiffies);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ * );
printk("should stop: %d\n",kthread_should_stop());
}
printk("Leaving my_function\n");
flag = ; //flag很关键!
return ;
}
static int __init init(void)
{
task = kthread_run(my_fuction,NULL,"my_function");
printk("<1> init wait_for_completion()\n");
return ;
}
static void __exit finish(void)
{
int ret;
if(!flag)
{
if (!IS_ERR(task))
{
int ret = kthread_stop(task);
printk(KERN_INFO "First thread function has stopped ,return %d\n", ret);
}
}
printk("task_struct: 0x%x",task);
printk(" Goodbye\n");
}
module_init(init);
module_exit(finish);
运行结果(执行kill之后):

运行结果(rmmod之后):

说明:程序运行后线程循环执行每隔5个内核 ticks 就答应一次当前的jiffies值。可以通过kthread_stop()来结束,也可以通过kill命令来结束。
程序中使用了flag 变量来控制是否使用 kthread_stop()函数有两个原因:首先,当线程创建成功之后IS_ERR()不能检测出线程是否还在运行,因为此时task是一个正常的地址而不是错误码(后面会说明IS_ERR的原理);其次,线程不能被杀次两次,如果使用kill命令之后线程已经被杀死,但是在此使用kthread_stop()函数就会出严重问题,因为此时线程已经被杀死,task指向的地址已经无效,struct kthread 也已经不存在,操作此时使用kthread_stop()设置should_stop是没有意义的。同样可以得出结论,当线程结束之后使用kthread_should_stop()来查看线程运行状态也会造成内核异常。
IS_ERR()函数的原理:
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
static inline long IS_ERR(const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
内核中的函数常常返回指针,问题是如果出错,也希望能够通过返回的指针体现出来。
所幸的是,内核返回的指针一般是指向页面的边界(4K边界),即
ptr & 0xfff == 0
这样ptr的值不可能落在(0xfffff000,0xffffffff)之间,而一般内核的出错代码也是一个小负数,在-1000到0之间,转变成unsigned long,正好在(0xfffff000,0xffffffff)之间。因此可以用
(unsigned long)ptr > (unsigned long)-1000L
也就等效于(x) >= (unsigned long)-MAX_ERRNO
其中MAX_ERRNO 为4095
来判断内核函数的返回值是一个有效的指针,还是一个出错代码。
涉及到的任何一个指针,必然有三种情况,一种是有效指针,一种是NULL,空指针,一种是错误指针,或者说无效指针.而所谓的错误指针就是指其已经到达了 最后一个page.比如对于32bit的系统来说,内核空间最高地址0xffffffff,那么最后一个page就是指的 0xfffff000~0xffffffff(假设4k一个page).这段地址是被保留的,如果超过这个地址,则肯定是错误的。
linux驱动之内核多线程(四)的更多相关文章
- linux驱动之内核多线程(二)
本文摘自http://www.cnblogs.com/zhuyp1015/archive/2012/06/11/2545702.html 内核多线程是在项目中使用到,自己也不熟悉,遇到一个很囧的问题, ...
- linux驱动之内核多线程(一)
本文摘自http://www.cnblogs.com/zhuyp1015/archive/2012/06/11/2545624.html Linux内核可以看作一个服务进程(管理软硬件资源,响应用户进 ...
- linux驱动之内核多线程(三)
本文摘自 http://www.cnblogs.com/zhuyp1015/archive/2012/06/13/2548458.html 接上 一篇文章 ,这里介绍另一种线程间通信的方式:compl ...
- Linux驱动之内核自带的S3C2440的LCD驱动分析
先来看一下应用程序是怎么操作屏幕的:Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这个设备来供用户 ...
- 【转载】小结一下linux 2.6内核的四种IO调度算法
在LINUX 2.6中,有四种关于IO的调度算法,下面综合小结一下: 1) NOOP NOOP算法的全写为No Operation.该算法实现了最最简单的FIFO队列,所有IO请求大致按照先来后到的顺 ...
- Linux驱动之内核加载模块过程分析
Linux内核支持动态的加载模块运行:比如insmod first_drv.ko,这样就可以将模块加载到内核所在空间供应用程序调用.现在简单描述下insmod first_drv.ko的过程 1.in ...
- 【Linux驱动】内核等待队列
在Linux中, 一个等待队列由一个"等待队列头"来管理,等待队列是双向链表结构. 应用场合:将等待同一资源的进程挂在同一个等待队列中. 数据结构 在include/linux/w ...
- Linux驱动:内核等待队列
在Linux中, 一个等待队列由一个"等待队列头"来管理,等待队列是双向链表结构. 应用场合:将等待同一资源的进程挂在同一个等待队列中. 数据结构 在include/linux/w ...
- Linux 驱动之内核定时器
1.定时器 之前说过两类跟时间相关的内核结构. 1.延时:通过忙等待或者睡眠机制实现延时. 2.tasklet和工作队列,通过某种机制使工作推后运行,但不知道运行的详细时间. 接下来要介绍的定时器,可 ...
随机推荐
- 数据页结构 .InnoDb行格式、以及索引底层原理分析
局部性原理 局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中. 首先要明白局部性原理能解决的是什么问题,也就是主存容量远远比缓存大, CP ...
- hostapd阅读(openwrt)-2
深入追踪openwrt下的hostapd之后,发现openwrt无线管理机制格外的复杂,几乎所以的触发与回调均离不开ubus,关于ubus这里不作解释,先大概了解其用途即可(出门左转:https:// ...
- 缓存利器、Lua模块下的共享内存
上一节讲到了worker进程的共享内存,它利用丰富的指令使数据的缓存操作变得非常简单,但它也存在一些缺点. 1.worker进程之间会有锁竞争,在高并发的情况下会增加性能开销.2.只支持Lua布尔值. ...
- 关于cnpm的命令出错 cant find module npm-cli.js,以及vue packages version mismatch出错
1.cant find module npm-cli.js 这个修复比较简单粗暴,直接找到安装node的安装软件,然后点开,里面有一个修复选项. 修复完就可以了 2.第二个vue packages v ...
- Python os.major() 方法
概述 os.major() 方法用于从原始的设备号中提取设备major号码 (使用stat中的st_dev或者st_rdev field).高佣联盟 www.cgewang.com 语法 major( ...
- PHP pi() 函数
实例 返回圆周率 PI 的值: <?phpecho(pi());?>高佣联盟 www.cgewang.com 定义和用法 pi() 函数返回圆周率 PI 的值. 提示:命名常量 M_PI ...
- luogu P5410 模板 扩展 KMP Z函数 模板
LINK:P5410 模板 扩展 KMP Z 函数 画了10min学习了一下. 不算很难 思想就是利用前面的最长匹配来更新后面的东西. 复杂度是线性的 如果不要求线性可能直接上SA更舒服一点? 不管了 ...
- win10下visual studio code安装及mingw C/C++编译器配置,launch.json和task.json文件的配置
快一年了,我竟然还有脸回来..... 过去一年,由于毕设.找工作的原因,发生太多变故,所以一直没更(最主要的原因还是毅力不够...),至于发生了什么事,以后想说的时候再更吧..依然是小白,下面说正事. ...
- python网络爬虫实战PDF高清完整版免费下载|百度云盘|Python基础教程免费电子书
点击获取提取码:vg1y python网络爬虫实战帮助读者学习Python并开发出符合自己要求的网络爬虫.网络爬虫,又被称为网页蜘蛛,网络机器人,是一种按照一定的规则,自动地抓取互联网信息的程序或者脚 ...
- 【oracle】-表连接类型:内连接,外连接...
一.数据准备 1.emp表 delete from emp; insert into emp (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) ...