本文摘自

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).这段地址是被保留的,如果超过这个地址,则肯定是错误的。

最新文章

  1. JDBC之存储过程
  2. PHP PDO的setAttribute函数
  3. docker pipework
  4. zookeeper client 常用操作
  5. 不容易系列之二[HDU2042]
  6. 使ViewStub 来提高UI的加载的性能
  7. IntelliJ IDEA 快捷键和设置
  8. 使用Pig预测电信用户的移动路径
  9. 通过控件获取cell
  10. Histats申请Counter网站计数器 - Blog透视镜
  11. &#39;nmake&#39; 不是内部或外部命令,VCVARS32.BAT路径问题
  12. iOS自定义转场动画的实现
  13. [BZOJ]4199: [Noi2015]品酒大会(后缀数组+笛卡尔树)
  14. Java通过实现Runnable接口来创建线程
  15. JSP 2.x 自定义标签
  16. IDEA 热部署设置(JRebel插件激活)
  17. leetcode-9.回文数(水仙花数)
  18. Java笔记(九)EnumMap &amp; EnumSet
  19. 浅谈AC自动机
  20. Git服务器配置及本地克隆提交、服务器获取

热门文章

  1. apache配置Directory目录权限的一些配置
  2. Android中Fragment生命周期和基本用法
  3. 枚举-称硬币POJ1013
  4. Fortify Audit Workbench 笔记 Privacy Violation 隐私泄露
  5. 进度条函数 -------ajax初试
  6. Python列表截取
  7. python小题目汇总
  8. PHP fgetcsv() 函数
  9. PHP popen() 函数
  10. 玩转 SpringBoot2.x 之整合邮件发送