實現(xiàn)Linux中的可加載的內(nèi)核模塊(包含一個內(nèi)核線程)

操作系統(tǒng)課上老師只用了一頁ppt講了三個kthread的api, 就出了如標(biāo)題的這么一個問題
順手就當(dāng)做之前理論學(xué)習(xí)的上手實踐了(逃


首先給出一段非百分百原創(chuàng)的代碼

#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/init.h>

static struct task_struct *test_task;

int threadfuc(void)
{
    int i = 0;
    while(1)
    {
        set_current_state(TASK_UNINTERRUPTIBLE);
        if (kthread_should_stop()) break;
        if (1)
        {
            printk(KERN_INFO "i = %d\n", i);
            i++;
        }
        schedule_timeout(HZ);
    }

    return 0;
}

static int test_init(void)
{
    test_task = kthread_run(threadfuc, NULL, "test_task");
    printk(KERN_INFO"module enter");
    return 0;
}

static void test_cleanup(void)
{
    if(test_task)
    {
        kthread_stop(test_task);
        test_task = NULL;
        printk(KERN_INFO"module remove");
    }
}

module_init(test_init);
module_exit(test_cleanup);

1. 首先是module程序的編寫與加載

module程序使用c語言編寫
這個程序不需要main入口
module程序使用insmod和rmmod兩個命令加載
(加載編譯出來的 .ko文件, 下文會提到如何編譯
在加載insmod命令的時候

module_init(test_init);

test_init這個函數(shù)名作為參數(shù)傳入, 并且模塊程序從test_init處開始運行
同理, 在rmmod的時候

module_exit(test_cleanup);

中的test_cleanup函數(shù)執(zhí)行, 進行清理善后工作.

2. 內(nèi)核模塊程序的編譯

同樣先給出makefile(完全非原創(chuàng))(逃
(是可以直接使用的, 可移植性蠻好的(強行

KVERS = $(shell uname -r)
obj-m := task_test.o
build: kernel_modules
kernel_modules:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

姑且先把它當(dāng)成一個模板來用(真不負責(zé)
要改的地方大概只有obj-m 后面的文件名了,改成自己的就可以了
小小的解釋一下:

/lib/modules/$(KVERS)/build 指定到已經(jīng)編譯的內(nèi)核的目錄
M=$(CURDIR) 要編譯的源文件的目錄

具體的解釋以后挖個坑以后慢慢填,坑++

3. 內(nèi)核模塊程序的交互

不像命令行程序, 內(nèi)核模塊的交互并不通過printf在命令行里輸出結(jié)果
在這里介紹一下printf的孿生姐妹printk(太太和小姨子)

printk與printf的差異,是什么導(dǎo)致一個運行在內(nèi)核態(tài)而另一個運行用戶態(tài)?其實這兩個函數(shù)幾乎是相同的,出現(xiàn)這種差異是因為tty_write函數(shù)需要使用fs指向的被顯示的字符串,而fs是專門用于存放用戶態(tài)段選擇符的,因此,在內(nèi)核態(tài)時,為了配合tty_write函數(shù),printk會把fs修改為內(nèi)核態(tài)數(shù)據(jù)段選擇符ds中的值,這樣才能正確指向內(nèi)核的數(shù)據(jù)緩沖區(qū),當(dāng)然這個操作會先對fs進行壓棧保存,調(diào)用tty_write完畢后再出棧恢復(fù)??偨Y(jié)說來,printk與printf的差異是由fs造成的,所以差異也是圍繞對fs的處理。

來源于百度百科

對于上面這個程序, printk的輸出可以使用dmesg命令查看, 當(dāng)然對于這種工具使用管道( | )配合上文字處理工具(tail, more, grep等)來使用就非常舒服了
比如 dmesg | tail -3 就可以查看最后三條記錄

當(dāng)然 , 使用ps auxtop加上grep也是可以的


雷區(qū)預(yù)警

  • 代碼函數(shù)中的void不能省略
  • 由于網(wǎng)頁上編碼格式等問題, 復(fù)制下來的代碼最好重新抄碼一遍
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容