pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
(unsigned long)arg, NULL, NULL);
}
代码分析中,kernel_thread()是通过do_fork()进行创建的线程,在2.6的版本中,这种创建内核线程的方式还可以用于驱动
模块中,但是在4.x的内核版本中就不可以在驱动模块中使用,也就是说想要使用kernel_thread之内将驱动程序编译进内核
才能够创建线程,想要使用insmod方式创建内核线程,就会被拒绝insmod,因为kernel_thread没有EXPORT_SYSMBOL
出来。
注意:kernel_thread创建出的线程的父进程是init
2. kthread_create()/kthread_run() 函数创建线程
两种方式创建线程的方式其实是一种线程,因为,kthrad_run()是一个宏定义,最终调用到kthread_create()
#define kthread_run(threadfn, data, namefmt, ...) \
({ \
struct task_struct *__k \
= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
if (!IS_ERR(__k)) \
wake_up_process(__k); \
__k; \
})
而kthread_create()其实也是宏定义
#define kthread_create(threadfn, data, namefmt, arg...) \
kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
void *data,
int node,
const char namefmt[], ...);
最终是调用到kthread_create_on_node()函数, kthread_create_on_node()已经被EXPORT_SYSMBOL出来,所以,无论是
在内核中使用还是在驱动模块中,都可以创建出新线程。
注意:kthreat_create()创建出的新线程的父进程是kthreadd,在kthread_create创建出的线程也对其上下文环境也进行了清理
,所以kthread_create()是比较正统的创建线程的方法。推荐使用kthread_create()的方式创建线程。
3. 示例
kernel_thread的方式: 在4.x的版本内核中的驱动模块中使用
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
#define CLONE_KERNEL (CLONE_FS | CLONE_FILES | CLONE_SIGHAND)
int my_kernel_thread(void *arg)
{
int n = 0;
while(1)
{
printk("%s: %d\n",__func__,n++);
ssleep(3);
}
return 0;
}
static int __init practiceCall(void)
{
printk("%s:\n",__func__);
kernel_thread(my_kernel_thread,NULL,CLONE_KERNEL);
return 0;
}
static void __exit practiceCallExit(void)
{
printk("%s:\n",__func__);
}
module_init(practiceCall);
module_exit(practiceCallExit);
kthread_run方式创建线程:
#include
#include
#include
#include
#include
static int dmatest_work (void *data)
{
allow_signal(SIGTERM);
current->state = TASK_INTERRUPTIBLE;
printk("New kernel thread run\n");
return 0;
}
static int __init dmatest_init(void)
{
/* Schedule the test thread */
kthread_run (dmatest_work, NULL, "dmatest");
return 0;
}
static void __exit dmatest_exit(void)
{
return;
}
MODULE_LICENSE("Dual BSD/GPL");
module_init(dmatest_init);
module_exit(dmatest_exit);