zoukankan      html  css  js  c++  java
  • Linux内核-内核线程

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

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

            内核线程(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的初始化阶段从无到有的创建的一个内核线程。这个祖先进程使用静态分配的数据结构。

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

    进程1 

          由进程0创建的内核线程执行init()函数,init() 一次完成内核的初始化。init()调用execve系统调用装入可执行程序init ,结果,init 内核线程变成一个普通的进程,且拥有自己的每个进程内核数据结构。在系统关闭之前,init 进程一直存活,因为它创建和监控在操作系统外层执行的所有进程的活动。

    其他内核线程

          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");





  • 相关阅读:
    Git标签使用技巧
    Git入门基本概述
    过滤器+缓存在.NET5WebApi项目中的简单使用
    在.NET5中 使用JWT鉴权授权
    Git常用开发命令
    时间戳的实际使用
    两个日期字段相减,进行计算
    MQ的理论理解
    第一周学习C语言的总结!
    问题(the question)
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3174463.html
Copyright © 2011-2022 走看看