本文旨在简单介绍一下Linux内核线程:
先举个例子:
不插U盘,在Linux命令行中输入:ps -el;然后插上U盘,再次输入:ps -el
会发现多出了下面一行(当然还会有其他的,比如scsi相关的):
1 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 2 1 S 0 2749 2 0 80 0 - 0 - ? 00:00:00 usb-storage
usb-storage 就是U盘驱动程序(驱动程序是动态加载的)起来之后,由内核创建的内核线程。下面我们就来看一下它是如何被创建的。有关usb-storage的完整内容,以后学习USB驱动时再详解,今天只讨论内核是如何管理内核线程的创建的。
在启动过程中,Linux2.6.22.6/init/main.c::rest_init()会创建另外2个进程(1号进程kernel_init和2号进程kthreadd),今天我们要讨论的就是2号进程kthreadd,它是所有内核线程(比如上面的usb-storage)的父进程。
1 static void noinline __init_refok rest_init(void) 2 __releases(kernel_lock) 3 { 4 int pid; 5 6 kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); // 创建1号进程 7 numa_default_policy(); 8 pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); // 创建2号进程 kthreadd 9 kthreadd_task = find_task_by_pid(pid); 10 unlock_kernel(); 11 .... 12 }
kthreadd()位于Linux2.6.22.6/kernel/kthread.c,今天我们主要就是分析这支文件。
kthreadd进程被创建之后就开始运行,我们看到他有一个死循环(for),他会一直去判断链表kthread_create_list中是否有内容,如果有,就根据链表的元素去创建一个内核线程。而函数kthread_create()会向链表kthread_create_list中插入元素(代码这里就不贴了)。
1 int kthreadd(void *unused) 2 { 3 /* Setup a clean context for our children to inherit. */ 4 kthreadd_setup(); 5 6 current->flags |= PF_NOFREEZE; 7 8 for (;;) { 9 set_current_state(TASK_INTERRUPTIBLE); // 设置进程状态: 可中断的等待状态 10 if (list_empty(&kthread_create_list)) // 如果链表为空 11 schedule(); 12 13 __set_current_state(TASK_RUNNING); 14 15 spin_lock(&kthread_create_lock); 16 while (!list_empty(&kthread_create_list)) { 17 struct kthread_create_info *create; 18 19 create = list_entry(kthread_create_list.next, 20 struct kthread_create_info, list); 21 list_del_init(&create->list); 22 spin_unlock(&kthread_create_lock); 23 24 create_kthread(create); // 他会调用kernel_thread完成真正的内核线程创建 25 26 spin_lock(&kthread_create_lock); 27 } 28 spin_unlock(&kthread_create_lock); 29 } 30 31 return 0; 32 }
U盘驱动程序的内核线程是如何被创建的呢? 就是通过下面这段代码(位于Linux2.6.22.6/driver/usb/storage/usb.c):
1 /* Start up our control thread */ 2 th = kthread_create(usb_stor_control_thread, us, "usb-storage"); // 3 if (IS_ERR(th)) { 4 printk(KERN_WARNING USB_STORAGE 5 "Unable to start control thread\n"); 6 return PTR_ERR(th); 7 }
下面通过一张图来总结一下: