Linux内核-内核线程

         线程分类:内核线程、用户线程(指不须要内核支持而彻底创建在用户空间的线程库,这种线程效率高,因为Linux内核没有轻量级进程(线程)的概念,所以不能独立的对用户线程进行调度,而是由一个线程运行库来组织线程的调度)和轻量级线程(内核线程的高级抽象,大多数操做涉及到系统调用,效率不高)。html

         传统的Unix系统把一些重要的任务委托给周期性的执行进程,这些任务包括刷新磁盘高速缓存,交换出不用的页框,维护网络链接等。这些线程只运行在内核态(普通进程既能够运行在内核态,也能够运行在用户态),内核线程只运行在内核态,因此只使用大于PAGE_OFFSET的线性地址空间。现代操做系统把它们的函数委托给内核线程,内核线程不受没必要要的用户态上下文拖累。内核线程的使用是廉价的,惟一使用的资源就是内核栈和上下文切换时保存寄存器的空间。linux

        内核线程(thread)或叫守护进程(daemon)缓存


建立内核线程网络

         kernel_thread()函数建立一个新的内核线程,它接受的参数:所要执行的内核函数地址(fn)、要传递给函数的参数(arg)、一组clone标志(flags)。该函数的本质上是调用数据结构

 

do_fork(flags|CLONE_VM|CLONE_UNTRACED),0,pregs,0,NULL,NULL);
//pregs表示内核栈的地址
//CLONE_VM;避免复制进程页表
 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
     struct pt_regs regs;
     memset(®s, 0, sizeof(regs));
     regs.ARM_r1 = (unsigned long)arg;
     regs.ARM_r2 = (unsigned long)fn;
     regs.ARM_r3 = (unsigned long)do_exit;
     regs.ARM_pc = (unsigned long)kernel_thread_helper;
     regs.ARM_cpsr = SVC_MODE;
     return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL,NULL);
}

 

 

进程0 
       全部进程的祖先叫作进程0,idle进程或由于历史的缘由叫作swapper 进程。它是在linux的初始化阶段从无到有的建立的一个内核线程。这个祖先进程使用静态分配的数据结构。app

      在多处理器系统中,每一个CPU都有一个进程0,只要打开机器电源,计算机的BIOS就启动一个CPU,同时禁用其余CPU。运行的CPU 0上的swapper进程初初始化内核数据结构,而后激活其余的CPU,而且使用copy_process()函数建立另外的swapper进程,把0 传递给新建立的swapper进程做为他们进程的PID。函数

 

进程1 ui

      由进程0建立的内核线程执行init()函数,init() 一次完成内核的初始化。init()调用execve系统调用装入可执行程序init ,结果,init 内核线程变成一个普通的进程,且拥有本身的每一个进程内核数据结构。在系统关闭以前,init 进程一直存活,由于它建立和监控在操做系统外层执行的全部进程的活动。atom

 

其余内核线程spa

      events 处理内核事件 不少软硬件事件(好比断电,文件变动)被转换为events,并分发给对相应事件感兴趣的线程进行响应

      ksoftirqd :处理软中断 硬件中断处理每每须要关中断,而这个时间不能太长,不然会丢失新的中断。因此中断处理的很大一部分工做移出,转给不辞辛苦的ksoftirqd在中断以外进行处理。好比一个网络包,从网卡里面取出这个过程可能须要关中断,可是TCP/IP协议处理就没必要关中断了

      kblockd :管理磁盘块读写

      kjournald: Ext3文件系统的日志管理 一般每一个 _已mount_ 的 Ext3分区会有一个 kjournald看管,各分区的日志是独立

      Pdflush: dirty内存页面的回写 太多dirty的页面意味着风险,好比故障时候的内容丢失,以及对突发的大量物理内存请求的响应(大量回写会致使糟糕的响应时间)

 kswapd :内存回收 确保系统空闲物理内存的数量在一个合适的范围

      aio :代替用户进程管理io 用以支持用户态的AIO


驱动中应用内核线程

 

#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>
static pid_t thread_id;
staticDECLARE_COMPLETION(exit_completion);
static atomic_t time_to_quit =ATOMIC_INIT(0);
 
int my_fuction(void *arg){     
    int ret;
    daemonize("demo-thread");        
    allow_signal(SIGKILL);
    complete(&exit_completion);
    while(!signal_pending(current)){                
         printk("jiffies is %lu/n", jiffies);
         set_current_stat(TASK_INTERRUPTIBLE);                                   
         schedule_timeout(10 * HZ);
         if(atomic_read(&kthread->terminate))
         { /* we receiveda request to terminate ourself */ break; }
     }
    /*
    for(;;)
    {
        Ret = wait_event_interruptible(wq,condition); //可采用任何同步措施
     }*/
    complete_and_exit(&exit_completion,1); 
    return0;
}
static int __init init(void)
{        
    thread_id = kernel_thread(my_fuction,NULL, CLONE_FS | CLONE_FILES);
    wait_for_completion(&exit_completion);
    return 0;
}
static void __exit finish(void)
{     
    atomic_inc(&time_to_quit); 
    kill_proc(thread_id, SIGKILL, 1); 
    wait_for_completion(&exit_completion);
    printk("Goodbye/n");
}
module_init(init);
module_exit(finish);
MODULE_LICENSE("GPL");