http://blog.sina.com.cn/s/blog_6a1837e90100onsb.html
2011
static spinlock_tRequestResponseLock = SPIN_LOCK_UNLOCKED;
spin_lock_bh(&RequestResponseLock);//spin_lock_bh 在獲取鎖之前禁止軟件中斷, 但是硬件中斷留作打開的.
spin_unlock_bh(&RequestResponseLock);
spin_lock(&RequestResponseLock);
spin_unlock(&RequestResponseLock);
//上層調(diào)用函數(shù)內(nèi)包含自旋鎖時(shí)使用spin_lock_bh,而內(nèi)核層底半步調(diào)用時(shí)使用spin_lock。bh指bottom_half,即底半。
--------------------------------------------------------------------------------------------------
create_proc_info_entry( REQUEST_RESPONSE_STATUS_NAME, 0,proc_dir, RequestResponseCacheStatus );
remove_proc_entry(REQUEST_RESPONSE_STATUS_NAME,proc_dir);
--------------------------------------------------------------------------------------------------
init_timer(&m->timer);
m->timer.function =&RequestResponseEntryExpired;
m->timer.data = (unsignedlong)m;
mod_timer(&m->timer,jiffies + GetRadiusResponseTimeout());
del_timer(&m->timer);
--------------------------------------------------------------------------------------------------
struct list_head e;
list_add(&m->e,&RequestResponseCache.hash_list[h].head);
while(!list_empty(&RequestResponseCache.hash_list[i].head))
m =list_entry(RequestResponseCache.hash_list[i].head.next, structRequestResponseEntry, e);
list_for_each_entry(m,&RequestResponseCache.hash_list[h].head,e)
list_del(&m->e);
--------------------------------------------------------------------------------------------------
insmod/lib/modules/2.6.18-8.el5/kernel/drivers/rtc/rtc-lib.ko
insmodmonitor.ko
mknod /dev/mapdrv0 c250 0
rmmod monitor
--------------------------------------------------------------------------------------------------
內(nèi)核編程中:
#include<ctype.h>
存在錯(cuò)誤,而
#include<linux/ctype.h>
正常
--------------------------------------------------------------------------------------------------
#ifdef __KERNEL__
#include<linux/ctype.h>
#else
#include<ctype.h>
#endif
宏__KERNEL__能夠區(qū)別當(dāng)前程序是在用戶層還是內(nèi)核層。
上述代碼包含在.h中,此頭文件可以被用戶層和內(nèi)核層的程序包含。
--------------------------------------------------------------------------------------------------
在strnpcy之后,需在目標(biāo)字符串的結(jié)尾加上'\0',即
strncpy(dest, src,size);
dest[size] ='\0'
--------------------------------------------------------------------------------------------------
2的n次方使用(1<< n)的形式
--------------------------------------------------------------------------------------------------
kmalloc只能申請(qǐng)128K的內(nèi)存,建議使用vmalloc
vfree()不能放在spin_lock_bh和spin_unlock_bh之間;
--------------------------------------------------------------------------------------------------
module_init()
module_exit()
函數(shù)module_init()和module_exit()是模塊編程中最基本也是必須的兩個(gè)函數(shù)。
module_init()向內(nèi)核注冊(cè)模塊所提供的新功能,
而module_exit()注銷由模塊提供的所有功能。
MODULE_LICENSE("GPL")用于聲明模塊的許可證
--------------------------------------------------------------------------------------------------
Linux內(nèi)核模塊的編譯需要給gcc指示-D__KERNEL__-DMODULE -DLINUX參數(shù)
--------------------------------------------------------------------------------------------------
void *kmalloc(unsigned int len, intpriority);
void kfree(void*__ptr);
priority:
GFP_KERNEL
GFP_ATOMIC
--------------------------------------------------------------------------------------------------
unsigned long copy_from_user(void *to,const void *from, unsigned long n);
unsigned longcopy_to_user (void * to, void * from, unsigned longlen);
put_user
get_user
--------------------------------------------------------------------------------------------------
內(nèi)核編程用printk替代printf
內(nèi)核一共有8個(gè)優(yōu)先級(jí).如果優(yōu)先級(jí)數(shù)字比intconsole_loglevel變量小的話,消息就會(huì)打印到控制臺(tái)上。如果syslogd和klogd守護(hù)進(jìn)程在運(yùn)行的話,則不管是否向控制臺(tái)輸出,消息都會(huì)被追加進(jìn)/var/log/messages文件。klogd只處理內(nèi)核消息,syslogd 處理其他系統(tǒng)消息,比如應(yīng)用程序。
--------------------------------------------------------------------------------------------------
include/linux/module.h中定義的宏MODULE_PARM(var,type)用于向模塊傳遞命令行參數(shù)。var為接受參數(shù)值的變量名,type為采取如下格式的字符串[min[-max]]{b,h,i,l,s}。min及max用于表示當(dāng)參數(shù)為數(shù)組類型時(shí),允許輸入的數(shù)組元素的個(gè)數(shù)范圍;
b:byte;h:short;i:int;l:long;s:string。
有了MODULE_PARM,在裝載內(nèi)核模塊時(shí),用戶可以向模塊傳遞一些參數(shù),如:
insmod modnamevar=value
--------------------------------------------------------------------------------------------------
#Makefile2.6
obj-m += hellomod.o # 產(chǎn)生hellomod 模塊的目標(biāo)文件
CURRENT_PATH :=$(shell pwd) #模塊所在的當(dāng)前路徑
LINUX_KERNEL :=$(shell uname -r) #Linux內(nèi)核源代碼的當(dāng)前版本
LINUX_KERNEL_PATH :=/usr/src/linux-headers-$(LINUX_KERNEL)#Linux內(nèi)核源代碼的絕對(duì)路徑
all:
make -C$(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #編譯模塊了
clean:
make -C$(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理
有了Makefile,執(zhí)行make命令,會(huì)自動(dòng)形成相關(guān)的后綴為.o和.ko文件。
--------------------------------------------------------------------------------------------------
模塊和內(nèi)核都在內(nèi)核空間運(yùn)行,模塊編程在一定意義上說就是內(nèi)核編程
模塊是具有獨(dú)立功能的程序,它可以被單獨(dú)編譯,但不能獨(dú)立運(yùn)行。
模塊通常由一組函數(shù)和數(shù)據(jù)結(jié)構(gòu)組成,用來實(shí)現(xiàn)一種文件系統(tǒng)、一個(gè)驅(qū)動(dòng)程序或其他內(nèi)核上層的功能。
因?yàn)閮?nèi)核版本的每次變化,其中的某些函數(shù)名也會(huì)相應(yīng)地發(fā)生變化,因此模塊編程與內(nèi)核版本密切相關(guān)
內(nèi)置模塊:可加載模塊
--------------------------------------------------------------------------------------------------
這些變量和函數(shù)就統(tǒng)稱為符號(hào)。
其中宏定義EXPORT_SYMBOL()本身的含義是“移出符號(hào)”。為什么說是“移出”呢?因?yàn)檫@些符號(hào)本來是內(nèi)核內(nèi)部的符號(hào),通過這個(gè)宏放在一個(gè)公開的地方,使得裝入到內(nèi)核中的其他模塊可以引用它們。
在模塊編程中,可以根據(jù)符號(hào)名從這個(gè)文件中檢索出其對(duì)應(yīng)的地址,然后直接訪問該地址從而獲得內(nèi)核數(shù)據(jù)。
第三列“所屬模塊”指符號(hào)所在的模塊名,對(duì)于從內(nèi)核這一母模塊移出的符號(hào),這一列為空。
模塊加載后,2.4內(nèi)核下可通過/proc/ksyms、 2.6 內(nèi)核下可通過/proc/kallsyms查看模塊輸出的內(nèi)核符號(hào)
--------------------------------------------------------------------------------------------------
模塊依賴
為了確保模塊安全地卸載,每個(gè)模塊都有一個(gè)引用計(jì)數(shù)器
--------------------------------------------------------------------------------------------------
1.Insmod命令:
2.rmmod命令:
3.lsmod命令:讀取/proc文件系統(tǒng)中的文件/proc/modules中的信息
4.ksyms命令:讀取/proc文件系統(tǒng)中的文件/proc/kallsyms。
--------------------------------------------------------------------------------------------------
//MODULE_PARM_DESC(interface,”A networkinterface”); 2.4內(nèi)核中該宏的用法
molule_parm(interface,charp,0644) //2.6內(nèi)核中的宏
//MODULE_PARM_DESC(irq,”The IRQ of the networkinterface”);
module_param(irq,int,0644);
insmod myirq.kointerface=eth0 irq=9
if(request_irq(irq, &myinterrupt, SA_SHIRQ,interface,&irq)) //注冊(cè)中斷,中斷值為irq,中斷函數(shù)myinterrupt
free_irq(irq,&irq);
具體網(wǎng)卡 irq的值可以查看cat /proc/interrupts
可動(dòng)態(tài)更改
--------------------------------------------------------------------------------------------------
insmod(安裝 LKM),
rmmod (刪除LKM),
modprobe(insmod和 rmmod的包裝器),加載當(dāng)前當(dāng)前模塊與其相關(guān)聯(lián)的其他模塊,單一模塊無關(guān)聯(lián)時(shí),必須使用insmod,否則會(huì)報(bào)錯(cuò),當(dāng)自寫編寫模塊時(shí),建議不要使用。
depmod(用于創(chuàng)建模塊依賴項(xiàng)),
modinfo(用于為模塊宏查找值)。
LKM只不過是一個(gè)特殊的可執(zhí)行可鏈接格式(Executable and LinkableFormat,ELF)對(duì)象文件。
在模塊的加載和卸載期間,模塊子系統(tǒng)維護(hù)了一組簡單的狀態(tài)變量,用于表示模塊的操作。
--------------------------------------------------------------------------------------------------
內(nèi)核中有一個(gè)叫做 HZ的頻率變量,它表示每秒的時(shí)鐘節(jié)拍數(shù)。一般的,在某種平臺(tái)上它會(huì)有一個(gè)固定值,這個(gè)固定值是人為設(shè)定的,
也就是可編程的(對(duì)系統(tǒng)定時(shí)器編程)。設(shè)定 HZ的大小需要權(quán)衡。這個(gè)值設(shè)大了,帶來的好處是定時(shí)器間隔變小,
從而使進(jìn)程(任務(wù))的調(diào)度的精確性得以提高,但帶來的缺點(diǎn)是導(dǎo)致開銷過大,讓系統(tǒng)變得耗電,
這樣在一些經(jīng)常使用電池的設(shè)備來說(比如筆記本,平板電腦)是難以接受的。
在現(xiàn)在一般的 x86平臺(tái),2.6 內(nèi)核的 linux 下,這個(gè)值會(huì)被設(shè)為 100 。也就是說,一個(gè)時(shí)鐘節(jié)拍為 1/100 = 0.01s = 10ms。
一個(gè)時(shí)鐘節(jié)拍也稱為 1 個(gè)jiffy 。
內(nèi)核中還有一個(gè)重要的變量叫jiffies 。它記錄了系統(tǒng)從啟動(dòng)到當(dāng)前所觸發(fā)定時(shí)器的次數(shù)。jiffies 每秒鐘增加 HZ 個(gè)計(jì)數(shù),
實(shí)際上就是 N 個(gè) jiffy。
--------------------------------------------------------------------------------------------------
中斷服務(wù)程序一般都是在中斷請(qǐng)求關(guān)閉的條件下執(zhí)行的,以避免嵌套而使中斷控制復(fù)雜化。
下半部運(yùn)行時(shí)是允許中斷請(qǐng)求的,而上半部運(yùn)行時(shí)是關(guān)中斷的,這是二者之間的主要區(qū)別。
--------------------------------------------------------------------------------------------------
小任務(wù)(Tasklet)機(jī)制
Count域是小任務(wù)的引用計(jì)數(shù)器。如果它不為0,則小任務(wù)被禁止,不允許執(zhí)行;只有當(dāng)它為零,小任務(wù)才被激活,并且在被設(shè)置為掛起時(shí),小任務(wù)才能夠執(zhí)行。
DECLARE_TASKLET(name, func, data)
DECLARE_TASKLET_DISABLED(name, func, data)
DECLARE_TASKLET(my_tasklet, my_tasklet_handler,dev);
這行代碼其實(shí)等價(jià)于
structtasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0),tasklet_handler, dev};
static voidtasklet_handler (unsigned long data)
tasklet_init(&my_tasklet,tasklet_handler, 0);
tasklet_schedule(&my_tasklet);
tasklet_kill(&my_tasklet);
--------------------------------------------------------------------------------------------------
如果推后執(zhí)行的任務(wù)需要睡眠,那么就選擇工作隊(duì)列。如果推后執(zhí)行的任務(wù)不需要睡眠,那么就選擇tasklet。
另外,如果需要用一個(gè)可以重新調(diào)度的實(shí)體來執(zhí)行你的下半部處理,也應(yīng)該使用工作隊(duì)列。
voidwork_handler(void *data); //工作隊(duì)列待執(zhí)行的函數(shù)
DECLARE_WORK(name, void (*func) (void *), void *data);//這樣就會(huì)靜態(tài)地創(chuàng)建一個(gè)名為name,待執(zhí)行函數(shù)為func,參數(shù)為data的work_struct結(jié)構(gòu)。
INIT_WORK(struct work_struct *work, woid(*func) (void *),void *data); //這會(huì)動(dòng)態(tài)地初始化一個(gè)由work指向的工作。
queue =create_singlethread_workqueue(“helloworld”);
if(!queue)
gotoerr;
destroy_workqueue(queue);
schedule_work(&work);//把給定工作的待處理函數(shù)提交給缺省的events工作線程
schedule_delayed_work(&work, delay);//&work指向的work_struct直到delay指定的時(shí)鐘節(jié)拍用完以后才會(huì)執(zhí)行。
--------------------------------------------------------------------------------------------------