操作系統(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 aux或top加上grep也是可以的
雷區(qū)預(yù)警
- 代碼函數(shù)中的void不能省略
- 由于網(wǎng)頁上編碼格式等問題, 復(fù)制下來的代碼最好重新抄碼一遍