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");
相關文章
相關標籤/搜索