我们经常会遇到一些情况,需要内核在后台执行某些操作,这时我们可以使用kernel threads来实现,kernel threads也是standard processes,但是它们仅仅存在于内核空间。Kernelthreads与normal processes的重要区别就是kernelthreads没有地址空间,因此它们的mm指针就是NULL。Kernel threads仅仅在内核空间中活动,不会切换到用户空间。但是,kernelthreads也与normal processes一样,也是schedulable和preemptable(可调度并且可抢占的)。
Linux系统也有一些tasks会委托给kernel threads去处理,最明显的就是flush task和ksoftirqd task,在我们的Linux系统中运行ps –ef命令就可以看到这些内核线程了:
其实并不止这两个,如上图显示的一样,还有很多kernel threads执行的tasks。
Kernelthreads是在系统启动时由其它的kernel threads创建。的确,一个kernel thread只能由其它的kernel thread创建。内核会自动进行处理,通过挖走kthreadd kernel process的所有新的kernel threads进行处理。
从已存在的kernel thread孵化出新的kernel thread的接口在<linux/kthread.h>中进行了声明:
struct task_struct *kthread_create(int (*threadfn)(void*data),
void *data,
const char namefmt[], ...)
__attribute__((format(printf,3, 4)));
新task是由kthread kernel process通过clone()系统调用创建的。新的process将运行threadfn函数,这个函数是通过data参数传递的。这个process将被命名为namefmt,变量参数列表中的namefmt采用的是printf-style formatting 的参数。这个process在创建后,处于unrunnable的状态,直到显示的调用wake_up_process()函数后,它才开始运行(或者runnable)。
也可以通过一个函数创建一个process并且让它变成runnable:kthread_run()
#define kthread_run(threadfn, data, namefmt, ...) \
({ \
structtask_struct *__k \
=kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
if(!IS_ERR(__k)) \
wake_up_process(__k); \
__k; \
})
这个例程是一个宏,同时调用了kthread_create()和wake_up_process()。
一旦开始,kernel thread就会一直存在直到 它自己调用do_exit()函数或者内核的其它部分调用kthread_stop()函数并且将kthread_create()返回的task_struct结构的地址传递给kthread_stop():
int kthread_stop(struct task_struct *k);