問:如何喚醒??
答:喚醒源有三個:1.數(shù)據(jù)可用的喚醒,2.接收到信號的喚醒,3.超時喚醒?
如果是數(shù)據(jù)可用的喚醒,那就預(yù)示著表明硬件設(shè)備可用,如果判斷硬件設(shè)備可用呢,一般要不輪詢,要不因為中斷,因為一旦設(shè)備給CPU發(fā)一個中斷信號,表明設(shè)備可用,那么只需在中斷處理函數(shù)中喚醒休眠的進(jìn)程即可,這種喚醒就是數(shù)據(jù)設(shè)備可用的喚醒!?
問:在內(nèi)核中如何喚醒呢??
答:在中斷處理函數(shù)中調(diào)用一下函數(shù)即可實現(xiàn)喚醒進(jìn)程:?
wake_up/wake_up_interruptible?
案例:編寫按鍵驅(qū)動,采用中斷和等待隊列機制來實現(xiàn)應(yīng)用程序獲取按鍵值,當(dāng)按鍵按下,上報0x51,按鍵松開,上報0x50
問:為什么要采用中斷和等待隊列機制來實現(xiàn)按鍵驅(qū)動?
答:因為按鍵驅(qū)動采用輪詢方式,非常浪費CPU的資源,也就是按鍵有沒有操作,應(yīng)用程序都會去讀取按鍵設(shè)備,做了大量的無用功。所以需要這么改進(jìn):當(dāng)按鍵沒有操作時,應(yīng)該讓應(yīng)用程序進(jìn)入休眠狀態(tài),這個休眠的實現(xiàn)過程應(yīng)該在底層驅(qū)動來做(驅(qū)動能夠檢查按鍵是否有操作---中斷)。如果一旦按鍵有操作,必然產(chǎn)生中斷,中斷處理函數(shù)中喚醒休眠的進(jìn)程,進(jìn)程被喚醒以后,再去去讀按鍵的有效數(shù)據(jù)即可。中斷本身不能和用戶空間進(jìn)行數(shù)據(jù)的往來,如果需要中斷向用戶空間上報數(shù)據(jù)信息,還要結(jié)合系統(tǒng)調(diào)用(file_operations).還需要中斷和內(nèi)核的等待隊列機制來實現(xiàn)第二版本的驅(qū)動。
linux內(nèi)核非阻塞的實現(xiàn):
1.阻塞訪問方式是linux訪問設(shè)備的默認(rèn)方式,也就說如果設(shè)備不可用(不可讀,不可寫),那么驅(qū)動程序利用等待隊列將進(jìn)程進(jìn)行休眠。
2.如果驅(qū)動程序不想讓進(jìn)程進(jìn)入休眠,而是采用非阻塞方式來處理(立即返回應(yīng)用程序),如何實現(xiàn)這種機制呢?
非阻塞的實現(xiàn)步驟:
1.應(yīng)用程序調(diào)用open時,需要指定采用非阻塞來訪問設(shè)備
int fd = open("/dev/mybuttons", O_RDWR|O_NONBLOCK);//只需指定一個O_NONBLOCK表明對設(shè)備的訪問就是采用非阻塞來訪問。
問:應(yīng)用程序open指定了這個宏,怎么樣就讓底層驅(qū)動的btn_read函數(shù)就知道了是采用非阻塞訪問呢?
答:open->sys_open:
1.從inode->i_rdev獲取設(shè)備號
2.以設(shè)備號為索引找到自己的cdev
3.創(chuàng)建struct file對象
4.將找到的cdev中的ops賦值給file->f_op
5.然后將O_RDWR|O_NONBLOCK這些信息保存在file->f_flags
6.如果file->f_op中有open的實現(xiàn),那么就調(diào)用底層驅(qū)動的open,如果沒有,立即返回用戶空間(永遠(yuǎn)成功)
通過以上的過程可知,在底層驅(qū)動的其他接口函數(shù)中,比如read,write,通過file->f_flags來獲取應(yīng)用程序是采用阻塞還是非阻塞
if (file->f_flags & O_NONBLOCK) {
//采用非阻塞方式
if (設(shè)備數(shù)據(jù)是否可用)
如果不可用,直接return 用戶空間即可
}else {
//阻塞方式
}