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