Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
poll
select
rt-smart select的实现
发布于 2023-05-12 21:34:49 浏览:718
订阅该版
[tocm] ## select介绍 select()是常用的多路IO复用的posix调用接口。select () 函数指示指定的文件描述符中的哪些已准备好读取、准备好写入或有待处理的错误条件。如果指定的条件对于所有指定的文件描述符都为假, 则 select() 阻塞,直到发生超时或直到指定的条件对于至少一个指定的文件描述符为真。 关于select函数的更多信息请查看 https://pubs.opengroup.org/onlinepubs/7908799/xsh/select.html ## rt-smart select的实现 代码详情可到以下地址查看 https://gitee.com/rtthread/rt-thread/blob/rt-smart/components/lwp/lwp_syscall.c rt-smart是一个包含用户层内核层包含MMU硬件功能的OS,用户层发送的系统调用请求,会通过特定的指令使cpu陷入异常,并进行相应的异常处理,其中用户态的select函数最终会调用lwp_syscall.c中的sys_select函数。sys_select函数会调用rt-smart的虚拟文件系统dfs实现的select函数([所在文件][1])。而select函数则会调用rt-smart的虚拟文件系统dfs实现的poll函数([所在文件][2])。 ``` C 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函数。 ``` C 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的函数解释,写在了函数注释中。 ``` C 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; } ``` ```C 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函数的实现 ``` C 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。 ``` C 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。之后队列唤醒的时候这个回调函数会被调用。 ``` C 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。 ``` C 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这个函数,在正常的设备驱动中一般就由中断函数来调用,如果中断函数代表有数据需要应用层读取处理的话。 [1]: https://gitee.com/rtthread/rt-thread/blob/rt-smart/components/dfs/src/select.c [2]: https://gitee.com/rtthread/rt-thread/blob/rt-smart/components/dfs/src/poll.c
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
HAHABO
这家伙很懒,什么也没写!
文章
4
回答
1
被采纳
0
关注TA
发私信
相关文章
1
rt-thread的多线程非阻塞网络编程server的例程有吗
2
select poll bug 导致内存泄漏
3
RTT标准版中posix poll接口使用疑问
4
接收数据不触发select
5
之前select死循环的问题查清楚了
6
支持多个fd同时select,目前的rtt貌似不支持
7
非阻塞 socket
8
使用fifo通道读取数据select不返回
9
select不返回问题,昨天未描述清楚
10
请问Kconfig中select 如何选择非bool值的config的值呢
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
UART
ESP8266
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
RTT_逍遥
8
个答案
2
次被采纳
KunYi
8
个答案
1
次被采纳
三世执戟
7
个答案
1
次被采纳
winfeng
2
个答案
1
次被采纳
chenyaxing
2
个答案
1
次被采纳
本月文章贡献
catcatbing
2
篇文章
5
次点赞
swet123
1
篇文章
3
次点赞
YZRD
1
篇文章
2
次点赞
Days
1
篇文章
2
次点赞
阳光的掌控者
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部