一文玩轉(zhuǎn)Linux內(nèi)核同步機(jī)制之completion
內(nèi)核編程中常見的一種模式是,在當(dāng)前線程之外初始化某個(gè)活動(dòng),然后等待該活動(dòng)的結(jié)束。這個(gè)活動(dòng)可能是,創(chuàng)建一個(gè)新的內(nèi)核線程或者新的用戶空間進(jìn)程、對(duì)一個(gè)已有進(jìn)程的某個(gè)請(qǐng)求,或者某種類型的硬件動(dòng)作,等等。在這種情況下,我們可以使用信號(hào)量來同步這兩個(gè)任務(wù)。然而,內(nèi)核中提供了另外一種機(jī)制——completion接口。Completion是一種輕量級(jí)的機(jī)制,他允許一個(gè)線程告訴另一個(gè)線程某個(gè)工作已經(jīng)完成。
結(jié)構(gòu)與初始化
Completion在內(nèi)核中的實(shí)現(xiàn)基于等待隊(duì)列(關(guān)于等待隊(duì)列理論知識(shí)在前面的文章中有介紹),completion結(jié)構(gòu)很簡(jiǎn)單:
和信號(hào)量一樣,初始化分為靜態(tài)初始化和動(dòng)態(tài)初始化兩種情況:
靜態(tài)初始化:
動(dòng)態(tài)初始化:
可見,兩種初始化都將用于同步的done原子量置位了0,后面我們會(huì)看到,該變量在wait相關(guān)函數(shù)中減一,在complete系列函數(shù)中加一。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ? ??


實(shí)現(xiàn)
同步函數(shù)一般都成對(duì)出現(xiàn),completion也不例外,我們看看最基本的兩個(gè)complete和wait_for_completion函數(shù)的實(shí)現(xiàn)。
wait_for_completion最終由下面函數(shù)實(shí)現(xiàn):
而complete實(shí)現(xiàn)如下:
不看內(nèi)核實(shí)現(xiàn)的源代碼我們也能想到他的實(shí)現(xiàn),不外乎在wait函數(shù)中循環(huán)等待done變?yōu)榭捎茫ㄕ?,而另一邊的complete函數(shù)為喚醒函數(shù),當(dāng)然是將done加一,喚醒待處理的函數(shù)。是的,從上面的代碼看到,和我們想的一樣。內(nèi)核也是這樣做的。
運(yùn)用
運(yùn)用LDD3中的例子:
測(cè)試步驟:
mknod /dev/complete創(chuàng)建complete節(jié)點(diǎn),在linux上驅(qū)動(dòng)程序需要手動(dòng)創(chuàng)建文件節(jié)點(diǎn)。
insmod complete.ko 插入驅(qū)動(dòng)模塊,這里要注意的是,因?yàn)槲覀兊拇a中是手動(dòng)分配的設(shè)備號(hào),很可能被系統(tǒng)已經(jīng)使用了,所以如果出現(xiàn)這種情況,查看/proc/devices文件。找一個(gè)沒有被使用的設(shè)備號(hào)。
cat /dev/complete 用于讀該設(shè)備,調(diào)用設(shè)備的讀函數(shù)
打開另一個(gè)終端輸入 echo “hello” > /dev/complete 該命令用于寫入該設(shè)備。
