Linux Kernel Development----内核线程

简介:

内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernel thread)完成--独立运行在内核空间的标准进程。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为NULL;它只在 内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占。

实际上,内核线程只能由其他内核线程创建,在现有的内核线程中创建一个新的内核线程的方法:

1. kernel_thread      

int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);        

kernel_thread通过do_fork实现:do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL)。    

需要注意的是,在执行函数fn里面必须用daemonize释放资源并挂到init下,还需要用completion等待这一过程的完成。

2. kthread_run

    struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt,...);

    创建内核线程并启动。    

3. kthread_create

    struct task_struct *kthread_create(int (*threadfn)(void *data),void *data, const char namefmt[], ...);

  int wake_up_process(struct task_struct *p);

    kthread_create创建一个新的内核线程,但线程是停止的,需要用wake_up_process启动它

使用示例

复制代码
 1 #include <linux/kthread.h>
 2 #include <linux/module.h>
 3 
 4 #ifndef SLEEP_MILLI_SEC
 5 #define SLEEP_MILLI_SEC(nMilliSec)\
 6     do { \
 7     long timeout = (nMilliSec) * HZ / 1000; \
 8     while(timeout > 0) \
 9     { \
10     __set_current_state(TASK_INTERRUPTIBLE); \
11     timeout = schedule_timeout(timeout); \
12     } \
13     }while(0);
14 #endif
15 
16 static struct task_struct * MyThread = NULL;
17 
18 static int MyPrintk(void *data)
19 {
20     char *mydata = kmalloc(strlen(data)+1,GFP_KERNEL);
21     memset(mydata,'\0',strlen(data)+1);
22     strncpy(mydata,data,strlen(data));
23     while(!kthread_should_stop())
24     {
25         SLEEP_MILLI_SEC(1000);
26         printk("%s\n",mydata);
27     }
28     kfree(mydata);
29     return 0;
30 }
31 
32 static int __init init_kthread(void)
33 {
34     MyThread = kthread_run(MyPrintk,"hello world","mythread");
35     return 0;
36 }
37 
38 static void __exit exit_kthread(void)
39 {
40     if(MyThread)
41     {
42         printk("stop MyThread\n");
43         kthread_stop(MyThread);
44     }
45 }
46 
47 module_init(init_kthread);
48 module_exit(exit_kthread);
49 MODULE_LICENSE("Dual BSD/GPL");
复制代码

内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernel thread)完成--独立运行在内核空间的标准进程。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为NULL;它只在 内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占。

实际上,内核线程只能由其他内核线程创建,在现有的内核线程中创建一个新的内核线程的方法:

1. kernel_thread      

int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);        

kernel_thread通过do_fork实现:do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL)。    

需要注意的是,在执行函数fn里面必须用daemonize释放资源并挂到init下,还需要用completion等待这一过程的完成。

2. kthread_run

    struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt,...);

    创建内核线程并启动。    

3. kthread_create

    struct task_struct *kthread_create(int (*threadfn)(void *data),void *data, const char namefmt[], ...);

  int wake_up_process(struct task_struct *p);

    kthread_create创建一个新的内核线程,但线程是停止的,需要用wake_up_process启动它

使用示例

复制代码
 1 #include <linux/kthread.h>
 2 #include <linux/module.h>
 3 
 4 #ifndef SLEEP_MILLI_SEC
 5 #define SLEEP_MILLI_SEC(nMilliSec)\
 6     do { \
 7     long timeout = (nMilliSec) * HZ / 1000; \
 8     while(timeout > 0) \
 9     { \
10     __set_current_state(TASK_INTERRUPTIBLE); \
11     timeout = schedule_timeout(timeout); \
12     } \
13     }while(0);
14 #endif
15 
16 static struct task_struct * MyThread = NULL;
17 
18 static int MyPrintk(void *data)
19 {
20     char *mydata = kmalloc(strlen(data)+1,GFP_KERNEL);
21     memset(mydata,'\0',strlen(data)+1);
22     strncpy(mydata,data,strlen(data));
23     while(!kthread_should_stop())
24     {
25         SLEEP_MILLI_SEC(1000);
26         printk("%s\n",mydata);
27     }
28     kfree(mydata);
29     return 0;
30 }
31 
32 static int __init init_kthread(void)
33 {
34     MyThread = kthread_run(MyPrintk,"hello world","mythread");
35     return 0;
36 }
37 
38 static void __exit exit_kthread(void)
39 {
40     if(MyThread)
41     {
42         printk("stop MyThread\n");
43         kthread_stop(MyThread);
44     }
45 }
46 
47 module_init(init_kthread);
48 module_exit(exit_kthread);
49 MODULE_LICENSE("Dual BSD/GPL");
复制代码

本文转自feisky博客园博客,原文链接:http://www.cnblogs.com/feisky/archive/2013/03/05/2945187.html,如需转载请自行联系原作者

相关文章
|
3月前
|
安全 网络协议 Linux
深入理解Linux内核模块:加载机制、参数传递与实战开发
本文深入解析了Linux内核模块的加载机制、参数传递方式及实战开发技巧。内容涵盖模块基础概念、加载与卸载流程、生命周期管理、参数配置方法,并通过“Hello World”模块和字符设备驱动实例,带领读者逐步掌握模块开发技能。同时,介绍了调试手段、常见问题排查、开发规范及高级特性,如内核线程、模块间通信与性能优化策略。适合希望深入理解Linux内核机制、提升系统编程能力的技术人员阅读与实践。
391 1
|
3月前
|
Ubuntu Linux
Ubuntu 23.04 用上 Linux 6.2 内核,预计下放到 22.04 LTS 版本
Linux 6.2 带来了多项内容更新,修复了 AMD 锐龙处理器设备在启用 fTPM 后的运行卡顿问题,还增强了文件系统。
|
3月前
|
Ubuntu Linux
Ubuntu 23.10 现在由Linux内核6.3提供支持
如果你想在你的个人电脑上测试一下Ubuntu 23.10的最新开发快照,你可以从官方下载服务器下载最新的每日构建ISO。然而,请记住,这是一个预发布版本,所以不要在生产机器上使用或安装它。
|
3月前
|
监控 Ubuntu Linux
什么Linux,Linux内核及Linux操作系统
上面只是简单的介绍了一下Linux操作系统的几个核心组件,其实Linux的整体架构要复杂的多。单纯从Linux内核的角度,它要管理CPU、内存、网卡、硬盘和输入输出等设备,因此内核本身分为进程调度,内存管理,虚拟文件系统,网络接口等4个核心子系统。
283 0
|
3月前
|
Web App开发 缓存 Rust
|
3月前
|
Ubuntu 安全 Linux
Ubuntu 发行版更新 Linux 内核,修复 17 个安全漏洞
本地攻击者可以利用上述漏洞,攻击 Ubuntu 22.10、Ubuntu 22.04、Ubuntu 20.04 LTS 发行版,导致拒绝服务(系统崩溃)或执行任意代码。
|
2月前
|
Linux 应用服务中间件 Shell
二、Linux文本处理与文件操作核心命令
熟悉了Linux的基本“行走”后,就该拿起真正的“工具”干活了。用grep这个“放大镜”在文件里搜索内容,用find这个“探测器”在系统中寻找文件,再用tar把东西打包带走。最关键的是要学会使用管道符|,它像一条流水线,能把这些命令串联起来,让简单工具组合出强大的功能,比如 ps -ef | grep 'nginx' 就能快速找出nginx进程。
385 1
二、Linux文本处理与文件操作核心命令
|
2月前
|
Linux
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
284 137
|
2月前
|
安全 Ubuntu Unix
一、初识 Linux 与基本命令
玩转Linux命令行,就像探索一座新城市。首先要熟悉它的“地图”,也就是/根目录下/etc(放配置)、/home(住家)这些核心区域。然后掌握几个“生存口令”:用ls看周围,cd去别处,mkdir建新房,cp/mv搬东西,再用cat或tail看文件内容。最后,别忘了随时按Tab键,它能帮你自动补全命令和路径,是提高效率的第一神器。
642 57