自己创建的内核线程,当把模块加载到内核之后,可以通过: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 = 0;int my_fuction(void *arg)
{printk(" in %s()\n", __FUNCTION__);allow_signal(SIGKILL); //使得线程可以接收SIGKILL信号mdelay(2000);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 * 5);   printk("should stop: %d\n",kthread_should_stop());}printk("Leaving my_function\n");flag = 1; //flag很关键!return 0;}static int __init init(void)
{task = kthread_run(my_fuction,NULL,"my_function");printk("<1> init wait_for_completion()\n");return 0;}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内核多线程(五)相关推荐

  1. Linux内核多线程实现方法 —— kthread_create函数

          Linux内核多线程实现方法 -- kthread_create函数 内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernle thread)完成独立运行在内核空间的标准进 ...

  2. 【内核】嵌入式linux内核的五个子系统

    Perface Linux内核主要由进程调度(SCHED).内存管理(MM).虚拟文件系统(VFS).网络接口(NET)和进程间通信(IPC)5个子系统组成,如图1所示. 图1 Linux内核的组成部 ...

  3. Linux内核必读五本书籍(强烈推荐)

    <深入理解Linux内核> 推荐等级:5颗星 为了透彻理解Linux的工作机理,以及为何它在各种系统上能顺畅运行,你需要深入到内核的心脏.cPu与外部世界的所有交互活动都是由内核处理的,哪 ...

  4. 360 n6 linux内核版本,五年26个版本:Linux系统内核全程回顾

    五年26个版本:Linux系统内核全程回顾 出处:快科技 2010-11-04 16:53:56     作者:上方文Q 编辑:上方文Q[爆料] 收藏文章 LAME MP3 Encoding:音频编码 ...

  5. (笔记)Linux内核学习(五)之中断推后处理机制

    一 中断 硬件通过中断与操作系统进行通信,通过对硬件驱动程序处注册中断处理程序,快速响应硬件的中断. 硬件中断优先级很高,打断当前正在执行的程序.有两种情况: 硬件中断在中断处理程序中处理 硬件中断延 ...

  6. Linux内核多线程(三)

    接上 一篇文章 ,这里介绍另一种线程间通信的方式:completion机制.Completion机制是线程间通信的一种轻量级机制:允许一个线程告诉另一个线程工作已经完成.为使用 completion, ...

  7. linux内核分成如下五个子系统,linux内核主要由5个子系统 Linux内核由哪几个子系统组成?...

    1, Linux内核由哪几个子系统组成? Linux内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进程间通信.1.进程调度(SCHED):控制进程对CPU的访问.当需要选择下一 ...

  8. Linux内核学习--内存管理模块

    Linux内核学习--内存管理模块 首先,Linux内核主要由五个部分组成,他们分别是:进程调度模块.内存管理模块.文件系统模块.进程间通信模块和网络接口模块. 本部分所讲的内存是内存管理模块,其主要 ...

  9. 【转】Linux内核结构详解

    Linux内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进程间通信. 1.进程调度 (SCHED):控制进程对CPU的访问.当需要选择下一个进程运行时,由调度程序选择最值得运行 ...

  10. 认识linux内核结构

    linux内核结构 用户级 函数库 :提供了应用程序支配内核干活的接口 内核级 Linux内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进程间通信. 1.进程调度(Proces ...

最新文章

  1. 电子学会青少年编程等级考试案例:曲奇饼干
  2. python画图三维-Python三维绘图之Matplotlib库的使用方法
  3. OS X 要改名为 MacOS 是因为 iOS 10 要来了?
  4. PHP 获取两个日期之间所有日期
  5. voc_eval.py:41: RuntimeWarning: invalid value encountered in greater_equal if np.sum(rec = t) ==
  6. 打破学习的玻璃墙_打破Google背后的创新深度学习
  7. cf1553D. Backspace
  8. 单例设计模式之安全的懒汉式
  9. markdown居中文本 - 代码篇
  10. Dubbo服务端暴露全流程
  11. 如何实现一个c/s模式的flv视频点播系统
  12. 因式分解题目及过程_【数学.天问】为什么有些题目一看就会,一做就废?是不是你的手有自己的想法?...
  13. iOS UIWebView清除缓存
  14. java面向对象_谈谈Java的面向对象
  15. java 异或代码编程
  16. 阿里云云盘扩容数据盘_Linux
  17. [ZZ]Sign Up for the First-Ever Appium Roadshow on August 20th in New York City
  18. 第一次在GitHub上提交代码
  19. springboot---微信小程序上传文件(word/pdf文件)
  20. java jcmd,JVM工具_jcmd

热门文章

  1. Java应用中使用ShutdownHook友好地清理现场
  2. HDU 3639 Hawk-and-Chicken
  3. ArcGIS 10 SDE for ORACLE ---迁移 (1)
  4. java代码调用python_java 直接调用python脚本,并传递参数代码实例
  5. centos压缩和解压缩命令之zip
  6. 泛微发布亿元补贴计划,推动移动办公普及
  7. java:eclipse:windows开发环境log4j系统找不到指定的路径
  8. 360换机 v2.12.5.9 官方安卓版
  9. 重载类型转换操作符(overload conversion operator)
  10. Delphi程序结构