最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Linux驅(qū)動(dòng)程序基石-POLL機(jī)制

2020-05-09 16:28 作者:韋東山  | 我要投稿


今天《升級(jí)版全系列嵌入式視頻_入門篇》新增一節(jié)視頻:19.2_POLL機(jī)制
時(shí)長(zhǎng)24分鐘,免費(fèi)觀看
何為POLL機(jī)制?

給驅(qū)動(dòng)程序加一個(gè)鬧鐘,讓APP不必死等數(shù)據(jù);

既可以快速掌握 POLL機(jī)制,更有對(duì)內(nèi)核代碼的詳細(xì)講解


多種觀看方式:


一,?B站(關(guān)注UP主-韋東山,視頻更新后會(huì)有通知)

19.2_POLL機(jī)制 :

https://www.bilibili.com/video/BV1w4411B7a4?p=81

(復(fù)制到瀏覽器打開)


二,?官網(wǎng)(100ask.net)(支持在線觀看,爽歪歪)

19.2_POLL機(jī)制:

wx48b57d2def17d3a6.h5.xiaoe-tech.com

(復(fù)制到瀏覽器打開,或者從100ask.net進(jìn)入)

溫馨提示:

為方便及時(shí)通知您,您需要支付1分錢訂閱該專欄,

然后依次填寫年齡,職位等信息。辛苦了。沒有您的允許我們不會(huì)泄露這些信息。


三 ,

百度網(wǎng)盤(適合不方便上網(wǎng)的同學(xué))

鏈接:eyun.baidu.com/s/3dFZmE

密碼:6FJk

路徑:

->04_快速入門(正式開始)

->02_嵌入式linux驅(qū)動(dòng)開發(fā)基礎(chǔ)知識(shí)

->19.驅(qū)動(dòng)程序基石

下面是視頻文稿:

19.2 POLL機(jī)制

19.2.1 適用場(chǎng)景

在前面引入中斷時(shí),我們?cè)?jīng)舉過一個(gè)例子:



媽媽怎么知道臥室里小孩醒了?

① 時(shí)不時(shí)進(jìn)房間看一下:查詢方式

簡(jiǎn)單,但是累

② 進(jìn)去房間陪小孩一起睡覺,小孩醒了會(huì)吵醒她:休眠-喚醒

不累,但是媽媽干不了活了

③ 媽媽要干很多活,但是可以陪小孩睡一會(huì),定個(gè)鬧鐘:poll方式

要浪費(fèi)點(diǎn)時(shí)間,但是可以繼續(xù)干活。

媽媽要么是被小孩吵醒,要么是被鬧鐘吵醒。

④ 媽媽在客廳干活,小孩醒了他會(huì)自己走出房門告訴媽媽:異步通知

媽媽、小孩互不耽誤


使用休眠-喚醒的方式等待某個(gè)事件發(fā)生時(shí),有一個(gè)缺點(diǎn):等待的時(shí)間可能很久。我們可以加上一個(gè)超時(shí)時(shí)間,這時(shí)就可以使用poll機(jī)制。

① APP不知道驅(qū)動(dòng)程序中是否有數(shù)據(jù),可以先調(diào)用poll函數(shù)查詢一下,poll函數(shù)可以傳入超時(shí)時(shí)間;

② APP進(jìn)入內(nèi)核態(tài),調(diào)用到驅(qū)動(dòng)程序的poll函數(shù),如果有數(shù)據(jù)的話立刻返回;

③ 如果發(fā)現(xiàn)沒有數(shù)據(jù)時(shí)就休眠一段時(shí)間;

④ 當(dāng)有數(shù)據(jù)時(shí),比如當(dāng)按下按鍵時(shí),驅(qū)動(dòng)程序的中斷服務(wù)程序被調(diào)用,它會(huì)記錄數(shù)據(jù)、喚醒APP;

⑤ 當(dāng)超時(shí)時(shí)間到了之后,內(nèi)核也會(huì)喚醒APP;

⑥ APP根據(jù)poll函數(shù)的返回值就可以知道是否有數(shù)據(jù),如果有數(shù)據(jù)就調(diào)用read得到數(shù)據(jù)

19.2.2 使用流程

媽媽進(jìn)入房間時(shí),會(huì)先看小孩醒沒醒,鬧鐘響之后走出房間之前又會(huì)再看小孩醒沒醒。

注意:看了2次小孩!

POLL機(jī)制也是類似的,流程如下:



函數(shù)執(zhí)行流程如上圖①~⑧所示,重點(diǎn)從③開始看。假設(shè)一開始無按鍵數(shù)據(jù):

③ APP調(diào)用poll之后,進(jìn)入內(nèi)核態(tài);

④ 導(dǎo)致驅(qū)動(dòng)程序的drv_poll被調(diào)用:

注意,drv_poll要把自己這個(gè)線程掛入等待隊(duì)列wq中;假設(shè)不放入隊(duì)列里,那以后發(fā)生中斷時(shí),中斷服務(wù)程序去哪里找到你嘛?

drv_poll還會(huì)判斷一下:有沒有數(shù)據(jù)???返回這個(gè)狀態(tài)。

⑤ 假設(shè)當(dāng)前沒有數(shù)據(jù),則休眠一會(huì);

⑥ 在休眠過程中,按下了按鍵,發(fā)生了中斷:

在中斷服務(wù)程序里記錄了按鍵值,并且從wq中把線程喚醒了。

⑦ 線程從休眠中被喚醒,繼續(xù)執(zhí)行for循環(huán),再次調(diào)用drv_poll:

drv_poll返回?cái)?shù)據(jù)狀態(tài)

⑧ 哦,你有數(shù)據(jù),那從內(nèi)核態(tài)返回到應(yīng)用態(tài)吧

⑨ APP調(diào)用read函數(shù)讀數(shù)據(jù)

如果一直沒有數(shù)據(jù),調(diào)用流程也是類似的,重點(diǎn)從③開始看,如下:

③ APP調(diào)用poll之后,進(jìn)入內(nèi)核態(tài);

④ 導(dǎo)致驅(qū)動(dòng)程序的drv_poll被調(diào)用:

注意,drv_poll要把自己這個(gè)線程掛入等待隊(duì)列wq中;假設(shè)不放入隊(duì)列里,那以后發(fā)生中斷時(shí),中斷服務(wù)程序去哪里找到你嘛?

drv_poll還會(huì)判斷一下:有沒有數(shù)據(jù)???返回這個(gè)狀態(tài)。

⑤ 假設(shè)當(dāng)前沒有數(shù)據(jù),則休眠一會(huì);

⑥ 在休眠過程中,一直沒有按下了按鍵,超時(shí)時(shí)間到:內(nèi)核把這個(gè)線程喚醒;

⑦ 線程從休眠中被喚醒,繼續(xù)執(zhí)行for循環(huán),再次調(diào)用drv_poll:

drv_poll返回?cái)?shù)據(jù)狀態(tài)

⑧ 哦,你還是沒有數(shù)據(jù),但是超時(shí)時(shí)間到了,那從內(nèi)核態(tài)返回到應(yīng)用態(tài)吧

⑨ APP不能調(diào)用read函數(shù)讀數(shù)據(jù)


注意幾點(diǎn):

① drv_poll要把線程掛入隊(duì)列wq,但是并不是在drv_poll中進(jìn)入休眠,而是在調(diào)用drv_poll之后休眠

② drv_poll要返回?cái)?shù)據(jù)狀態(tài)

③ APP調(diào)用一次poll,有可能會(huì)導(dǎo)致drv_poll被調(diào)用2次

④ 線程被喚醒的原因有2:中斷發(fā)生了去隊(duì)列wq中把它喚醒,超時(shí)時(shí)間到了內(nèi)核把它喚醒

⑤ APP要判斷poll返回的原因:有數(shù)據(jù),還是超時(shí)。有數(shù)據(jù)時(shí)再去調(diào)用read函數(shù)。

19.2.3 驅(qū)動(dòng)編程

使用poll機(jī)制時(shí),驅(qū)動(dòng)程序的核心就是提供對(duì)應(yīng)的drv_poll函數(shù)。

在drv_poll函數(shù)中要做2件事:

① 把當(dāng)前線程掛入隊(duì)列wq:poll_wait

APP調(diào)用一次poll,可能導(dǎo)致drv_poll被調(diào)用2次,但是我們并不需要把當(dāng)前線程掛入隊(duì)列2次。

可以使用內(nèi)核的函數(shù)poll_wait把線程掛入隊(duì)列,如果線程已經(jīng)在隊(duì)列里了,它就不會(huì)再次掛入。

② 返回設(shè)備狀態(tài):

APP調(diào)用poll函數(shù)時(shí),有可能是查詢“有沒有數(shù)據(jù)可以讀”:POLLIN,也有可能是查詢“你有沒有空間給我寫數(shù)據(jù)”:POLLOUT。

所以drv_poll要返回自己的當(dāng)前狀態(tài):(POLLIN | POLLRDNORM) 或 (POLLOUT | POLLWRNORM)。

POLLRDNORM等同于POLLIN,為了兼容某些APP把它們一起返回。

POLLWRNORM等同于POLLOUT ,為了兼容某些APP把它們一起返回。


APP調(diào)用poll后,很有可能會(huì)休眠。對(duì)應(yīng)的,在按鍵驅(qū)動(dòng)的中斷服務(wù)程序中,也要有喚醒操作。

驅(qū)動(dòng)程序中poll的代碼如下:

static unsigned int gpio_key_drv_poll(struct file *fp, poll_table * wait)

{

printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

poll_wait(fp, &gpio_key_wait, wait);

return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;

}

19.2.4 應(yīng)用編程

注意:APP可以調(diào)用poll或select函數(shù),這2個(gè)函數(shù)的作用是一樣的。

poll/select函數(shù)可以監(jiān)測(cè)多個(gè)文件,可以監(jiān)測(cè)多種事件:

事件類型

說明

POLLIN

有數(shù)據(jù)可讀

POLLRDNORM

等同于POLLIN

POLLRDBAND

Priority band data can be read,有優(yōu)先級(jí)較較高的“band data”可讀

Linux系統(tǒng)中很少使用這個(gè)事件

POLLPRI

高優(yōu)先級(jí)數(shù)據(jù)可讀

POLLOUT

可以寫數(shù)據(jù)

POLLWRNORM

等同于POLLOUT

POLLWRBAND

Priority data may be written

POLLERR

發(fā)生了錯(cuò)誤

POLLHUP

掛起

POLLNVAL

無效的請(qǐng)求,一般是fd未open


在調(diào)用poll函數(shù)時(shí),要指明:

① 你要監(jiān)測(cè)哪一個(gè)文件:哪一個(gè)fd

② 你想監(jiān)測(cè)這個(gè)文件的哪種事件:是POLLIN、還是POLLOUT

最后,在poll函數(shù)返回時(shí),要判斷狀態(tài)。


應(yīng)用程序代碼如下:

struct pollfd fds[1];

int timeout_ms = 5000;

int ret;


fds[0].fd = fd;

fds[0].events = POLLIN;


ret = poll(fds, 1, timeout_ms);

if ((ret == 1) && (fds[0].revents & POLLIN))

{

read(fd, &val, 4);

printf("get button : 0x%x\n", val);

}

19.2.5 現(xiàn)場(chǎng)編程

看視頻

19.2.6 上機(jī)實(shí)驗(yàn)

看視頻

19.2.7 POLL機(jī)制的內(nèi)核代碼詳解

Linux APP系統(tǒng)調(diào)用,基本都可以在它的名字前加上“sys_”前綴,這就是它在內(nèi)核中對(duì)應(yīng)的函數(shù)。比如系統(tǒng)調(diào)用open、read、write、poll,與之對(duì)應(yīng)的內(nèi)核函數(shù)為:sys_open、sys_read、sys_write、sys_poll。

對(duì)于系統(tǒng)調(diào)用poll或select,它們對(duì)應(yīng)的內(nèi)核函數(shù)都是sys_poll。分析sys_poll,即可理解poll機(jī)制。

19.2.7.1 sys_poll函數(shù)

sys_poll位于fs/select.c文件中,代碼如下:

SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,

int, timeout_msecs)

{

struct timespec64 end_time, *to = NULL;

int ret;


if (timeout_msecs >= 0) {

to = &end_time;

poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC,

NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));

}


ret = do_sys_poll(ufds, nfds, to);

……

SYSCALL_DEFINE3是一個(gè)宏,它定義于include/linux/syscalls.h,展開后就有sys_poll函數(shù)。

sys_poll對(duì)超時(shí)參數(shù)稍作處理后,直接調(diào)用do_sys_poll。


19.2.7.2 do_sys_poll函數(shù)

do_sys_poll位于fs/select.c文件中,我們忽略其他代碼,只看關(guān)鍵部分:

int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,

struct timespec64 *end_time)

{

……

poll_initwait(&table);

fdcount = do_poll(head, &table, end_time);

poll_freewait(&table);

……

}

poll_initwait函數(shù)非常簡(jiǎn)單,它初始化一個(gè)poll_wqueues變量table:

poll_initwait

init_poll_funcptr(&pwq->pt, __pollwait);

pt->qproc = qproc;

即table->pt->qproc = __pollwait,__pollwait將在驅(qū)動(dòng)的poll函數(shù)里用到。


do_poll函數(shù)才是核心,繼續(xù)看代碼。


19.2.7.3 do_poll函數(shù)

do_poll函數(shù)位于fs/select.c文件中,這是POLL機(jī)制中最核心的代碼,貼圖如下:



① 從這里開始,將會(huì)導(dǎo)致驅(qū)動(dòng)程序的poll函數(shù)被第一次調(diào)用。

沿著②③④⑤,你可以看到:驅(qū)動(dòng)程序里的poll_wait會(huì)調(diào)用__pollwait函數(shù)把線程放入某個(gè)隊(duì)列。

當(dāng)執(zhí)行完①之后,在⑥或⑦處,pt->_qproc被設(shè)置為NULL,所以第二次調(diào)用驅(qū)動(dòng)程序的poll時(shí),不會(huì)再次把線程放入某個(gè)隊(duì)列里。

⑧ 如果驅(qū)動(dòng)程序的poll返回有效值,則count非0,跳出循環(huán);

⑨ 否則休眠一段時(shí)間;當(dāng)休眠時(shí)間到,或是被中斷喚醒時(shí),會(huì)再次循環(huán)、再次調(diào)用驅(qū)動(dòng)程序的poll。

回顧APP的代碼,APP可以指定“想等待某些事件”,poll函數(shù)返回后,可以知道“發(fā)生了哪些事件”:



驅(qū)動(dòng)程序里怎么體現(xiàn)呢?在上上一個(gè)圖中,看②位置處,細(xì)說如下:


-☆ END ☆-

我是韋東山,10多年一直在研究linux+ARM,希望我的分享對(duì)你有幫助,歡迎進(jìn)店訂閱我的付費(fèi)內(nèi)容:100ask.taobao.com

歡迎加群與韋老師交流討論:





Linux驅(qū)動(dòng)程序基石-POLL機(jī)制的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
绥阳县| 恩平市| 始兴县| 江孜县| 贵阳市| 武山县| 扎鲁特旗| 清新县| 丘北县| 清河县| 汽车| 林芝县| 松潘县| 綦江县| 德阳市| 上思县| 庆云县| 柳河县| 湟源县| 隆子县| 河西区| 黔江区| 永修县| 定安县| 乳山市| 阳原县| 攀枝花市| 乡宁县| 定结县| 连南| 四会市| 浑源县| 开封市| 西贡区| 临朐县| 铁岭县| 桃江县| 和硕县| 金湖县| 轮台县| 神木县|