select介紹
select()是常用的多路IO復用的posix調用接口。select () 函數指示指定的文件描述符中的哪些已準備好讀取、準備好寫入或有待處理的錯誤條件。如果指定的條件對于所有指定的文件描述符都為假, 則 select() 阻塞,直到發生超時或直到指定的條件對于至少一個指定的文件描述符為真。
rt-smart select的實現
rt-smart是一個包含用戶層內核層包含MMU硬件功能的OS,用戶層發送的系統調用請求,會通過特定的指令使cpu陷入異常,并進行相應的異常處理,其中用戶態的select函數最終會調用lwp_syscall.c中的sys_select函數。sys_select函數會調用rt-smart的虛擬文件系統dfs實現的select函數(所在文件)。而select函數則會調用rt-smart的虛擬文件系統dfs實現的poll函數(所在文件)。
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的表,然后調用poll_do函數。
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設置為了0.
關于poll_do的函數解釋,寫在了函數注釋中。
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函數會調用對應的設備節點的poll回調函數 /
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計數增加 /
{
num ++;
pt->req._proc = RT_NULL;
}
pf ++;
}
pt->req._proc = RT_NULL;
/ 如果num大于0或istimeout不為0則跳出循環 /
if (num || istimeout)
break;
/ 如果poll_wait_timeout返回值大于0則標記為超時,之后會再調用do_pollfd,但是無論do_pollfd的結果如何最終由于istimeout不為0,都會導致循環退出 /
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函數在中途會調用 rt_schedule()觸發系統調度,當前線程被切回來以后會檢查pt->triggered的值來確定函數的返回值。
poll函數的實現
int test_dev_poll(struct dfs_fd *fd, struct rt_pollreq *req)
{
/ 這里的waitqueue是設備節點dev中的waitqueue /
rt_poll_add(waitqueue, req);
if(is_sould_return)
return POLLIN | POLLRDNORM;
return 0;
}
這個函數的邏輯是當設備節點的poll函數回調被調用時,需要看一下此時有沒有數據可以讓用戶態去讀取,而這個有沒有數據的信息需要驅動自己維護。如果有的話就返回非0的值,如果沒有的話就直接返回0。
而rt_poll_add(waitqueue, req);會掛載一個req資源到waitqueue中,如果有人喚醒了這個隊列,那么前面的poll_wait_timeout就會被喚醒。rt_poll_add會調用req的_proc函數,這個函數在前面的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。之后隊列喚醒的時候這個回調函數會被調用。
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函數用于喚醒一個正在因隊列等待而休眠的線程,該函數會去查找entry的wakeup回調函數,這個回調函數就是前面提到的__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函數最終將triggered置位了1,代表poll_wait_timeout被wakeup的話,其返回值就是0。poll_do函數由于循環的原因會再次調用poll函數。
那么rt_wqueue_wakeup這個函數,在正常的設備驅動中一般就由中斷函數來調用,如果中斷函數代表有數據需要應用層讀取處理的話。
-
處理器
+關注
關注
68文章
19440瀏覽量
231315 -
驅動器
+關注
關注
53文章
8290瀏覽量
147150 -
觸發器
+關注
關注
14文章
2018瀏覽量
61379 -
MMU
+關注
關注
0文章
92瀏覽量
18382 -
串口中斷
+關注
關注
0文章
67瀏覽量
14019
發布評論請先 登錄
相關推薦
RT-Smart的資料合集
rt-smart中斷阻塞問題是怎么引起的
請問rt-smart gdbserver是閉源的嗎?
請問rt-smart gdbserver是閉源的嗎?
基于RT-Thread操作系統衍生rt-smart實時操作系統簡介
rt-smart移植分析:從樹莓派3b入手
![<b class='flag-5'>rt-smart</b>移植分析:從樹莓派3b入手](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
優雅的在D1S上運行RT-Smart
絲滑的在RT-Smart用戶態運行LVGL
RT-Smart riscv64匯編注釋
零基礎上手rt-smart適配bsp
![零基礎上手<b class='flag-5'>rt-smart</b>適配bsp](https://file1.elecfans.com/web2/M00/8F/B3/wKgaomTRqa-AWXQuAAGBIMyA6Sw417.jpg)
評論