0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

rt-smart select的實(shí)現(xiàn)

冬至子 ? 來源:HAHABO ? 作者:HAHABO ? 2023-08-09 16:05 ? 次閱讀

select介紹

select()是常用的多路IO復(fù)用的posix調(diào)用接口。select () 函數(shù)指示指定的文件描述符中的哪些已準(zhǔn)備好讀取、準(zhǔn)備好寫入或有待處理的錯誤條件。如果指定的條件對于所有指定的文件描述符都為假, 則 select() 阻塞,直到發(fā)生超時或直到指定的條件對于至少一個指定的文件描述符為真。

rt-smart select的實(shí)現(xiàn)

rt-smart是一個包含用戶層內(nèi)核層包含MMU硬件功能的OS,用戶層發(fā)送的系統(tǒng)調(diào)用請求,會通過特定的指令使cpu陷入異常,并進(jìn)行相應(yīng)的異常處理,其中用戶態(tài)的select函數(shù)最終會調(diào)用lwp_syscall.c中的sys_select函數(shù)。sys_select函數(shù)會調(diào)用rt-smart的虛擬文件系統(tǒng)dfs實(shí)現(xiàn)的select函數(shù)(所在文件)。而select函數(shù)則會調(diào)用rt-smart的虛擬文件系統(tǒng)dfs實(shí)現(xiàn)的poll函數(shù)(所在文件)。

int poll(struct pollfd *fds, nfds_t nfds, int timeout)
{
int num;
struct rt_poll_table table;
poll_table_init(&table);
num = poll_do(fds, nfds, &table, timeout);
poll_teardown(&table);
return num;
}

這里會首先初始化一個poll的表,然后調(diào)用poll_do函數(shù)。

static void poll_table_init(struct rt_poll_table *pt)
{
pt->req._proc = _poll_add;
pt->triggered = 0;
pt->nodes = RT_NULL;
pt->polling_thread = rt_thread_self();
}
poll_table_init中將table的triggered設(shè)置為了0.

關(guān)于poll_do的函數(shù)解釋,寫在了函數(shù)注釋中。

static int poll_do(struct pollfd *fds, nfds_t nfds, struct rt_poll_table *pt, int msec)
{
while (1)
{
pf = fds;
num = 0;
for (n = 0; n < nfds; n ++)
{
/ do_pollfd函數(shù)會調(diào)用對應(yīng)的設(shè)備節(jié)點(diǎn)的poll回調(diào)函數(shù) /
ret = do_pollfd(pf, &pt->req);
if(ret < 0)
{
/*dealwith the device return error -1 */
pt->req._proc = RT_NULL;
return ret;
}
else if(ret > 0) / 如果返回值大于0,num計(jì)數(shù)增加 /
{
num ++;
pt->req._proc = RT_NULL;
}
pf ++;
}
pt->req._proc = RT_NULL;
/ 如果num大于0或istimeout不為0則跳出循環(huán) /
if (num || istimeout)
break;
/ 如果poll_wait_timeout返回值大于0則標(biāo)記為超時,之后會再調(diào)用do_pollfd,但是無論do_pollfd的結(jié)果如何最終由于istimeout不為0,都會導(dǎo)致循環(huán)退出 /
if (poll_wait_timeout(pt, msec))
istimeout = 1;
}
return num;
}
static int poll_wait_timeout(struct rt_poll_table *pt, int msec)
{
if (timeout != 0 && !pt->triggered)
{
if (rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE) == RT_EOK)
{
rt_hw_interrupt_enable(level);
rt_schedule();
level = rt_hw_interrupt_disable();
}
}
ret = !pt->triggered; / 這個值會在wakeup中被修改 /
rt_hw_interrupt_enable(level);
return ret;
}

wait函數(shù)在中途會調(diào)用 rt_schedule()觸發(fā)系統(tǒng)調(diào)度,當(dāng)前線程被切回來以后會檢查pt->triggered的值來確定函數(shù)的返回值。

poll函數(shù)的實(shí)現(xiàn)
int test_dev_poll(struct dfs_fd *fd, struct rt_pollreq *req)
{
/ 這里的waitqueue是設(shè)備節(jié)點(diǎn)dev中的waitqueue /
rt_poll_add(waitqueue, req);
if(is_sould_return)
return POLLIN | POLLRDNORM;
return 0;
}

這個函數(shù)的邏輯是當(dāng)設(shè)備節(jié)點(diǎn)的poll函數(shù)回調(diào)被調(diào)用時,需要看一下此時有沒有數(shù)據(jù)可以讓用戶態(tài)去讀取,而這個有沒有數(shù)據(jù)的信息需要驅(qū)動自己維護(hù)。如果有的話就返回非0的值,如果沒有的話就直接返回0。

而rt_poll_add(waitqueue, req);會掛載一個req資源到waitqueue中,如果有人喚醒了這個隊(duì)列,那么前面的poll_wait_timeout就會被喚醒。rt_poll_add會調(diào)用req的_proc函數(shù),這個函數(shù)在前面的poll_table_init中被賦值為了_poll_add。

static void _poll_add(rt_wqueue_t *wq, rt_pollreq_t *req)
{
node->wqn.key = req->_key;
rt_list_init(&(node->wqn.list));
node->wqn.polling_thread = pt->polling_thread;
node->wqn.wakeup = __wqueue_pollwake;
node->next = pt->nodes;
node->pt = pt;
pt->nodes = node;
rt_wqueue_add(wq, &node->wqn);
}

這里比較重要的是node->wqn.wakeup被賦值為了__wqueue_pollwake。之后隊(duì)列喚醒的時候這個回調(diào)函數(shù)會被調(diào)用。

void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key)
{
if (!(rt_list_isempty(queue_list)))
{
for (node = queue_list->next; node != queue_list; node = node->next)
{
entry = rt_list_entry(node, struct rt_wqueue_node, list);
if (entry->wakeup(entry, key) == 0)
{
rt_thread_resume(entry->polling_thread);
need_schedule = 1;
rt_wqueue_remove(entry);
break;
}
}
}
}

wakeup函數(shù)用于喚醒一個正在因隊(duì)列等待而休眠的線程,該函數(shù)會去查找entry的wakeup回調(diào)函數(shù),這個回調(diào)函數(shù)就是前面提到的__wqueue_pollwake。

static int __wqueue_pollwake(struct rt_wqueue_node *wait, void *key)
{
struct rt_poll_node *pn;
if (key && !((rt_ubase_t)key & wait->key))
return -1;
pn = rt_container_of(wait, struct rt_poll_node, wqn);
pn->pt->triggered = 1;
return __wqueue_default_wake(wait, key);
}

__wqueue_pollwake函數(shù)最終將triggered置位了1,代表poll_wait_timeout被wakeup的話,其返回值就是0。poll_do函數(shù)由于循環(huán)的原因會再次調(diào)用poll函數(shù)。

那么rt_wqueue_wakeup這個函數(shù),在正常的設(shè)備驅(qū)動中一般就由中斷函數(shù)來調(diào)用,如果中斷函數(shù)代表有數(shù)據(jù)需要應(yīng)用層讀取處理的話。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 處理器
    +關(guān)注

    關(guān)注

    68

    文章

    18938

    瀏覽量

    227330
  • 驅(qū)動器
    +關(guān)注

    關(guān)注

    51

    文章

    8014

    瀏覽量

    145069
  • 觸發(fā)器
    +關(guān)注

    關(guān)注

    14

    文章

    1990

    瀏覽量

    60891
  • MMU
    MMU
    +關(guān)注

    關(guān)注

    0

    文章

    91

    瀏覽量

    18169
  • 串口中斷
    +關(guān)注

    關(guān)注

    0

    文章

    64

    瀏覽量

    13800
收藏 人收藏

    評論

    相關(guān)推薦

    通過Uboot?TFTP啟動rt-smart內(nèi)核

    介紹Windows下通過 Uboot??TFTP 方式下載和啟動rt-smart 內(nèi)核
    的頭像 發(fā)表于 06-30 12:34 ?3511次閱讀
    通過Uboot?TFTP啟動<b class='flag-5'>rt-smart</b>內(nèi)核

    RT-Smart的資料合集

    1、RT-Smart的啟動過程在熟悉 RT-Smart 架構(gòu)的過程中,研究其啟動過程的是必不可少的,那么在系統(tǒng)正常運(yùn)行之前,需要做哪些準(zhǔn)備工作呢。本文將以 32 位 RT-Smart 的源代碼為
    發(fā)表于 03-22 15:06

    rt-smart中斷阻塞問題是怎么引起的

    rt-smart 中斷阻塞問題如何解決?該問題是怎么引起的?為了測試rt-smart的實(shí)時性,測試了一下中斷的穩(wěn)定性。用systick的1ms中斷做測試源。平時都正常的,但是發(fā)現(xiàn)打印時,波形老是抖動
    發(fā)表于 03-25 09:56

    請問rt-smart gdbserver是閉源的嗎?

    編譯“RT-Smart”,啟用RT_USING_GDBSERVER時,發(fā)現(xiàn)許多文件都找不到,請問這部分代碼不公開嗎?比如#include #include
    發(fā)表于 04-19 09:37

    請問rt-smart gdbserver是閉源的嗎?

    編譯“RT-Smart”,啟用RT_USING_GDBSERVER時,發(fā)現(xiàn)許多文件都找不到,請問這部分代碼不公開嗎?比如#include #include
    發(fā)表于 04-26 10:01

    基于RT-Thread操作系統(tǒng)衍生rt-smart實(shí)時操作系統(tǒng)簡介

    1、rt-smart 實(shí)時操作系統(tǒng)簡介RT-Thread Smart(簡稱 rt-smart)嵌入式實(shí)時操作系統(tǒng)是基于 RT-Thread
    發(fā)表于 06-22 17:56

    rt-smart應(yīng)用程序系統(tǒng)調(diào)用實(shí)現(xiàn)過程是怎么樣的?

    rt-smart應(yīng)用程序系統(tǒng)調(diào)用實(shí)現(xiàn)過程是怎么樣的? 比如open時候怎么一步一步切換到內(nèi)核態(tài)的?
    發(fā)表于 09-08 17:00

    樹莓派上rt-smart的應(yīng)用編程入門

    我們從現(xiàn)在開始會逐步連載RT-Thread Smart(簡稱rt-smart,甚至有時會稱為smart os)的介紹文章,旨在讓大家認(rèn)識,接觸到sm
    的頭像 發(fā)表于 05-13 14:10 ?2985次閱讀
    樹莓派上<b class='flag-5'>rt-smart</b>的應(yīng)用編程入門

    rt-smart移植分析:從樹莓派3b入手

    移植rt-smart到最新的板子上具體需要注意哪些細(xì)節(jié),哪些才是移植rt-smart的關(guān)鍵點(diǎn)?本文從樹莓派3b上移植rt-smart的角度,從頭分析rt-sm...
    發(fā)表于 01-25 18:48 ?0次下載
    <b class='flag-5'>rt-smart</b>移植分析:從樹莓派3b入手

    優(yōu)雅的在D1S上運(yùn)行RT-Smart

    前言 最近在學(xué)習(xí) RT-Smart ,正巧有在全志開發(fā)者論壇看到這么一篇帖子【驚】在麻雀上運(yùn)行國產(chǎn)rt-smart系統(tǒng),看到很多人都在關(guān)注 D1S 在 Smart 上的運(yùn)行情況。如今該 BSP 已經(jīng)
    的頭像 發(fā)表于 11-16 20:15 ?2595次閱讀

    絲滑的在RT-Smart用戶態(tài)運(yùn)行LVGL

    開發(fā)流程 1、RT-Smart 環(huán)境搭建 下載 RT-Smart 用戶態(tài)應(yīng)用代碼: 1 git?clone?https: //github.com/RT-Thread/userapps.git
    的頭像 發(fā)表于 11-22 20:20 ?1120次閱讀

    RT-Smart riscv64匯編注釋

    rt-smart在全志D1上的代碼為例,主要注釋了rt-smart在riscv64上的系統(tǒng)初始化和異常處理的代碼倉庫地址https://gitee.com/rtthread/rt
    的頭像 發(fā)表于 02-08 21:40 ?1026次閱讀

    零基礎(chǔ)上手rt-smart適配bsp

    RT-Thread Smart(簡稱rt-smart)是基于RT-Thread操作系統(tǒng)衍生,面向帶MMU(Memory Management Unit),中高端應(yīng)用的芯片,例如ARM
    的頭像 發(fā)表于 08-08 10:34 ?806次閱讀
    零基礎(chǔ)上手<b class='flag-5'>rt-smart</b>適配bsp

    RT-Smart riscv64匯編注釋

    rt-smart在全志D1上的代碼為例,主要注釋了rt-smart在riscv64上的系統(tǒng)初始化和異常處理的代碼
    的頭像 發(fā)表于 10-12 17:26 ?517次閱讀
    <b class='flag-5'>RT-Smart</b> riscv64匯編注釋

    RT-Smart應(yīng)用開發(fā)筆記:fopen造成文件被清空問題的分析記錄

    RT-Smart 應(yīng)用(apps)開發(fā)環(huán)境,ubuntu 20.04 + win10 VS Code
    的頭像 發(fā)表于 10-20 16:01 ?469次閱讀
    <b class='flag-5'>RT-Smart</b>應(yīng)用開發(fā)筆記:fopen造成文件被清空問題的分析記錄