当前位置: 首页 > article >正文

SylixOS 中 select 原理及使用分析

1、select接口简介

1.1 select接口使用用例

  select 是操作系统多路 I/O 复用技术实现的方式之一。

  select 函数允许程序监视多个文件描述符,等待所监视的一个或者多个文件描述符变为“准备好”的状态。所谓的”准备好“状态是指:文件描述符不再是阻塞状态,可以用于某类 IO 操作了,包括可读,可写,发生异常三种。

  select 在应用中使用的例子如下段代码所示。

#include <stdio.h>
#include <sys/select.h>int main (int argc, char *argv[])
{fd_set fdset;int ret;struct timeval timeout;char ch;timeout.tv_sec = 10;timeout.tv_usec = 0;for (;;) {FD_ZERO(&fdset);FD_SET(STDIN_FILENO, &fdset);ret = select(STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout);if (ret <= 0) {break;} else if (FD_ISSET(STDIN_FILENO, &fdset)) {read(STDIN_FILENO, &ch, 1);if (ch == '\n') {continue;}fprintf(stdout, "input char: %c\n", ch);if (ch == 'q') {break;}}}return (0);
}

1.2 select函数原型分析

LW_API INT   select(INT                  iWidth, fd_set              *pfdsetRead,fd_set              *pfdsetWrite,fd_set              *pfdsetExcept,struct timeval      *ptmvalTO);
  • iWidth 为设置的文件集中,最大的文件号 + 1;
  • pfdsetRead 为关心的可读文件集;
  • pfdsetWrite 为关心的可写文件集;
  • pfdsetExcept 为关心的异常文件集;
  • ptmvalTO 为等待超时时间,LW_NULL 表示永远等待;
  • 返回值:正常返回等待到的文件数量,错误返回 PX_ERROR。

2、select 实现

2.1 内核中 select 实现

select 函数具体实现如下,主体可以分为 3 个部分:

  • 检查读文件集、写文件集、异常文件集,调用 ioctl 的 FIOSELECT 命令
  • 调用 API_SemaphoreBPend 接口进行阻塞
  • 被唤醒后,调用 ioctl 的 FIOUNSELECT 命令
LW_API  
INT     pselect (INT                     iWidth, fd_set                 *pfdsetRead,fd_set                 *pfdsetWrite,fd_set                 *pfdsetExcept,const struct timespec  *ptmspecTO,const sigset_t         *sigsetMask)
{......if (pfdsetRead) {                                                   /*  检查读文件集                */selwunNode.SELWUN_seltypType = SELREAD;if (__selDoIoctls(&pselctx->SELCTX_fdsetOrigReadFds, pfdsetRead, iWidth, FIOSELECT, &selwunNode, LW_TRUE)) {                      /*  遇到错误,立即退出           */iIsOk = PX_ERROR;}}....../*  开始等待,这里是 select 阻塞的根源。 一般会在驱动的中断处理函数中调用 wakeup_node ,去释放这个二进制信号量   */ulError = API_SemaphoreBPend(pselctx->SELCTX_hSembWakeup,ulWaitTime);                            /*  开始等待                    */if (pfdsetRead) {                                                   /*  检查读文件集                */selwunNode.SELWUN_seltypType = SELREAD;if (__selDoIoctls(&pselctx->SELCTX_fdsetOrigReadFds, pfdsetRead, iWidth, FIOUNSELECT, &selwunNode, LW_FALSE)) {                     /*  如果存在节点,删除节点       */iIsOk = PX_ERROR;}}......
}

  select 操作的一个重要数据结构,就是 “唤醒节点” ——LW_SEL_WAKEUPNODE

  select 函数允许程序监视多个文件描述符,这里的每一个文件描述符,对应一个“唤醒节点”。唤醒节点中一个重要的变量就是 SELWUN_hThreadId 线程 ID,记录了创建该等待节点的线程句柄(其实就是调用 select 接口的线程)。该数据结构通过 ioctl 接口,传递到设备文件描述符对应的设备驱动中,由设备驱动去维护、管理该唤醒节点。

/*********************************************************************************************************等待节点类型
*********************************************************************************************************/typedef enum {SELREAD,                                                            /*  读阻塞                      */SELWRITE,                                                           /*  写阻塞                      */SELEXCEPT                                                           /*  异常阻塞                    */
} LW_SEL_TYPE;/*********************************************************************************************************等待链表节点.
*********************************************************************************************************/typedef struct {LW_LIST_LINE            SELWUN_lineManage;                          /*  管理链表                   */UINT32                  SELWUN_uiFlags;LW_OBJECT_HANDLE        SELWUN_hThreadId;                           /*  创建节点的线程句柄          */INT                     SELWUN_iFd;                                 /*  链接点的文件描述符          */LW_SEL_TYPE             SELWUN_seltypType;                          /*  等待类型                   */
} LW_SEL_WAKEUPNODE;
typedef LW_SEL_WAKEUPNODE  *PLW_SEL_WAKEUPNODE;    

2.2 设备驱动的 ioctl 实现

  SylixOS 的 select 接口实现中,系统会调用到每一个 fd 对应的设备驱动的 ioctl 接口,并会调用到如下表所示的两个命令:

命令说明
FIOSELECT添加 SEL_WAKE_NODE 节点
FIOUNSELECT移除 SEL_WAKE_NODE 节点

  驱动中 ioctl 的 FIOSELECT 实现,通常会调用 SEL_WAKE_NODE_ADD 接口,向设备驱动中添加一个“唤醒节点”(也可以把它理解成“等待节点”)。以 gpio 驱动为例:

static INT  _gpiofdSelect (PLW_GPIOFD_FILE  pgpiofdfil, PLW_SEL_WAKEUPNODE   pselwunNode)
{......SEL_WAKE_NODE_ADD(&pgpiofdfil->GF_selwulist, pselwunNode);......
}static INT  _gpiofdUnselect (PLW_GPIOFD_FILE  pgpiofdfil, PLW_SEL_WAKEUPNODE   pselwunNode)
{......SEL_WAKE_NODE_DELETE(&pgpiofdfil->GF_selwulist, pselwunNode);......
}static INT  _gpiofdIoctl (PLW_GPIOFD_FILE pgpiofdfil, INT             iRequest, LONG            lArg)
{......switch (iRequest) {......case FIOSELECT:pselwunNode = (PLW_SEL_WAKEUPNODE)lArg;return  (_gpiofdSelect(pgpiofdfil, pselwunNode));case FIOUNSELECT:pselwunNode = (PLW_SEL_WAKEUPNODE)lArg;return  (_gpiofdUnselect(pgpiofdfil, pselwunNode));}......
}

节点的组织形式如下:

  • 设备驱动相关结构体中,会维护一个指针,指向唤醒节点链表(这个链表由设备驱动去维护)
  • 链表节点的添加,是调用SEL_WAKE_NODE_ADD 函数完成的

在这里插入图片描述

2.3 阻塞与唤醒实现

阻塞
  select 本身是一个阻塞函数。通过调用二进制信号量 API_SemaphoreBPend,实现阻塞操作。

注意,这里的二进制信号量,实际上是一个同步信号量。在调用 pend 之前,pselect 会首先调用 ioctl,传递 FIOSELECT 参数。此接口中会判断 当前 是否满足 select 的唤醒条件,若满足则先调用 post,以使之后调用的 pend 不会被阻塞; 若 当前 不满足 select 的唤醒条件,则会进入阻塞状态,等待设备驱动主动去唤醒

唤醒
  通常是由 select 所监听的文件描述符集对应的设备驱动去唤醒。还是以 gpio 驱动为例,当一个 gpio 中断(电平触发、边沿触发)产生时,就会告诉操作系统,该 gpio 的状态“可读”,通过调用 SEL_WAKE_UP_ALL 接口实现唤醒操作。该接口底层实现,实际上就是调用 API_SemaphoreBPost

LW_API  
VOID    API_SelWakeup (PLW_SEL_WAKEUPNODE   pselwunNode)
{
....../*  根据唤醒节点中保存的线程 ID,获取线程 TCB 结构  */usIndex = _ObjectGetIndex(pselwunNode->SELWUN_hThreadId);ptcb = __GET_TCB_FROM_INDEX(usIndex);if (!ptcb || !ptcb->TCB_pselctxContext) {                           /*  线程不存在                  */return;}/*  设置唤醒节点的 READY 属性 */LW_SELWUN_SET_READY(pselwunNode);/*  根据 TCB,找到需要唤醒的句柄 SELCTX_hSembWakeup  */pselctxContext = ptcb->TCB_pselctxContext;API_SemaphoreBPost(pselctxContext->SELCTX_hSembWakeup);             /*  提前激活即将等待线程        */
}static irqreturn_t  _gpiofdIsr (PLW_GPIOFD_FILE pgpiofdfil)
{
......SEL_WAKE_UP_ALL(&pgpiofdfil->GF_selwulist, SELREAD);
......
}

相关文章:

SylixOS 中 select 原理及使用分析

1、select接口简介 1.1 select接口使用用例 select 是操作系统多路 I/O 复用技术实现的方式之一。 select 函数允许程序监视多个文件描述符&#xff0c;等待所监视的一个或者多个文件描述符变为“准备好”的状态。所谓的”准备好“状态是指&#xff1a;文件描述符不再是阻塞状…...

软考笔记——软件工程基础知识

第五章节——软件工程基础知识 软件工程基础知识 第五章节——软件工程基础知识一、软件工程概述1. 计算机软件2. 软件工程基本原理3. 软件生命周期4. 软件过程 二、软件过程模型1. 瀑布模型2. 增量模型3. 演化模型&#xff08;原型模型、螺旋模型)4. 喷泉模型5. 基于构建的开发…...

FastGPT原理分析-数据集创建第二步:处理任务的执行

概述 文章《FastGPT原理分析-数据集创建第一步》已经分析了数据集创建的第一步&#xff1a;文件上传和预处理的实现逻辑。本文介绍文件上传后&#xff0c;数据处理任务的具体实现逻辑。 数据集创建总体实现步骤 从上文可知数据集创建总体上来说分为两大步骤&#xff1a; &a…...

基于Python的3D贴图制作技术研究与实践

摘要&#xff1a;本文深入探讨了利用Python进行3D贴图制作的技术&#xff0c;介绍了Python在3D图形领域的应用优势&#xff0c;阐述了3D贴图的基本原理和常见类型。详细讲解了借助Python的相关库&#xff0c;如Pillow、OpenCV、PyTorch3D开展3D贴图制作的流程&#xff0c;包括纹…...

【MySQL数据库】视图 + 三范式

视图 视图的基本介绍 MySQL中的视图&#xff08;View&#xff09;是一种虚拟的表&#xff0c;其内容是从一个或多个基本表中检索出来的。视图可以简化复杂的查询操作&#xff0c;提高查询效率&#xff0c;同时也可以对敏感数据进行安全性控制。下面是关于MySQL视图的一些基本…...

STM32学习笔记之存储器映射(原理篇)

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…...

如何通过数据可视化提升管理效率

通过数据可视化提升管理效率的核心方法包括清晰展示关键指标、及时发现和解决问题、支持决策优化。其中&#xff0c;清晰展示关键指标尤为重要。通过数据可视化工具直观地呈现关键绩效指标&#xff08;KPI&#xff09;&#xff0c;管理者能快速、准确地理解业务现状&#xff0c…...

数据结构:利用递推式计算next表

next 表是 KMP 算法的核心内容&#xff0c;下面介绍一种计算 next 表的方法&#xff1a;利用递推式计算 如图 6.3.1 所示&#xff0c;在某一趟匹配中&#xff0c;当对比到最后一个字符的时候&#xff0c;发现匹配失败&#xff08;s[i] ≠ t[j]&#xff09;。根据 BF 算法&…...

每日算法-250326

83. 删除排序链表中的重复元素 题目描述 思路 使用快慢指针遍历排序链表。slow 指针指向当前不重复序列的最后一个节点&#xff0c;fast 指针用于向前遍历探索。当 fast 找到一个与 slow 指向的节点值不同的新节点时&#xff0c;就将 slow 的 next 指向 fast&#xff0c;然后 …...

trino查询mysql报Unknown or incorrect time zone: ‘Asia/Shanghai‘

问题 trino查询mysql时报Error listing schemas for catalog mysql: java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.&#xff0c;trino的日志中看到Unknown or incorrect time zone…...

java学习笔记7——面向对象

关键字&#xff1a;static 类变量 静态变量的内存解析&#xff1a; 相关代码&#xff1a; public class ChineseTest {public static void main(String[] args) {System.out.println(Chinese.nation); //null 没赋值前System.out.println(Chinese.nation); //中国 静态变量赋值…...

leetcode day31 453+435

453 用最少数量引爆气球 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。 一支弓箭可以沿着 x 轴从不同点 完全垂直 地…...

C++三大特性之继承

1.继承的概念及定义 回忆封装 C Stack类设计和C设计Stack对比。封装更好&#xff1a;访问限定符类的数据和方法放在一起 -> 避免底层接口的暴露&#xff0c;数据更加的安全&#xff0c;程序的耦合性更高迭代器的设计&#xff0c;封装了容器底层结构&#xff0c;在不暴露底层…...

PyQt QDoubleSpinBox控件用法详解

QDoubleSpinBox 是 PyQt中用于输入浮点数的控件&#xff0c;支持键盘输入和上下箭头调整数值。与QtSpinBox不同&#xff0c;QtSpinBox是用于输入整数的控件。 关键属性和方法 QDoubleSpinBox 的关键属性和方法如下表所示&#xff1a; 方法/属性说明setRange(min, max)设置数…...

解决Vmware 运行虚拟机Ubuntu22.04卡顿、终端打字延迟问题

亲测可用 打开虚拟机设置&#xff0c;关闭加速3D图形 &#xff08;应该是显卡驱动的问题&#xff0c;不知道那个版本的驱动不会出现这个问题&#xff0c;所以干脆把加速关了&#xff09;...

查询Marklogic数据库,因索引配置造成的返回数据count不同的问题

查询Marklogic数据库&#xff0c;因索引配置造成的返回数据count不同的问题 一&#xff0c;问题&#xff1a; 目前由两个MarkLogic DB&#xff0c;其中A表示所有的数据库统称&#xff0c;包含于BCD&#xff1b; 调用查询接口&#xff0c;通过A和B入口且相同的查询条件去查询B…...

ctfshow做题笔记—栈溢出—pwn73、pwn74

目录 一、pwn73(愉快的尝试一下一把梭吧&#xff01;) 二、pwn74(噢&#xff1f;好像到现在为止还没有了解到one_gadget?) 前言&#xff1a; 抽空闲时间继续学习&#xff0c;记录了两道题&#xff0c;pwn74卡了几天哈哈。 一、pwn73(愉快的尝试一下一把梭吧&#xff01;) …...

026-zstd

zstd 以下为Zstandard&#xff08;zstd&#xff09;压缩算法从原理到代码实现的技术调研报告&#xff0c;结合流程图、结构图及完整C代码实现&#xff1a; 一、核心原理与技术架构 1.1 算法原理 Zstd基于LZ77衍生算法与熵编码&#xff08;FSE/Huffman&#xff09;的混合架构&…...

AF3 quat_to_rot函数解读

AlphaFold3 rigid_utils 模块的 quat_to_rot 函数的功能是把四元数转换为旋转矩阵,函数利用预定义的四元数到旋转矩阵的转换表 _QTR_MAT 来简化计算。 理解四元数到旋转矩阵的转换 源代码: _quat_elements = ["a", "b", "c", "d"]…...

Elasticsearch 的搜索功能

Elasticsearch 的搜索功能 建议阅读顺序&#xff1a; Elasticsearch 入门Elasticsearch 搜索&#xff08;本文&#xff09; 1. 介绍 使用 Elasticsearch 最终目的是为了实现搜索功能&#xff0c;现在先将文档添加到索引中&#xff0c;接下来完成搜索的方法。 查询的分类&…...

Vala编成语言教程-构造函数和析构函数

构造函数 Vala支持两种略有不同的构造方案&#xff1a;我们将重点讨论Java/C#风格的构造方案&#xff0c;另一种是GObject风格的构造方案。 Vala不支持构造函数重载的原因与方法重载不被允许的原因相同&#xff0c;这意味着一个类不能有多个同名构造函数。但这并不构成问题&…...

Mybatis-plus配置动态多数据源

前言&#xff1a;微服务架构中&#xff0c;有些模块中可能不同组件用不同数据源&#xff0c;或者做数据库主从集群需要读写分离&#xff0c;动态切换数据源&#xff0c;或不同方法需要不同数据源就需要一个快捷方便的方法。引用动态数据源组件dynamic-datasource-spring-boot-s…...

CSS+JS 堆叠图片动态交互切换

结合DeepSeek提供的代码&#xff0c;终于实现了堆叠两张图片动态循环切换&#xff0c;以下是代码&#xff1a; 通过绝对定位放了两张图片 <div class"col-lg-5" style"z-index: 40; position: relative;"><img src"images/banner_1.png&quo…...

内存检查之Valgrind工具

内存检查之Valgrind工具 Author: Once Day Date: 2025年3月26日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章请查看专栏: Linux实践记录_Once-Day的博客-CSD…...

强大的AI网站推荐(第四集)—— Gamma

网站&#xff1a;Gamma 号称&#xff1a;展示创意的新媒介 博主评价&#xff1a;快速展示创意&#xff0c;重点是展示&#xff0c;在几秒钟内快速生成幻灯片、网站、文档等内容 推荐指数&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x…...

javafx项目结构+代码规范

javafx项目 1. 新建项目&#xff0c;对项目的理解 jdk&#xff1a; 是 Java Development ToolKit 的简称&#xff0c;也就是 Java 开发工具包。JDK 是整个 Java 的核心&#xff0c;包括 Java 运行环境&#xff08;Java Runtime Envirnment&#xff0c;简称 JRE&#xff09;&a…...

国外计算机证书推荐(考证)(6 Sigma、AWS、APICS、IIA、Microsoft、Oracle、PMI、Red Hat)

文章目录 证书推荐1. 六西格玛 (6 Sigma)2. 亚马逊网络服务 (AWS)3. 美国生产与库存控制学会 (APICS)4. 内部审计师协会 (IIA)5. 微软 (Microsoft)6. 甲骨文 (Oracle)7. 项目管理协会 (PMI)8. 红帽 (Red Hat) 证书推荐 1. 六西格玛 (6 Sigma) 介绍&#xff1a;六西格玛是一种…...

黑盒测试与白盒测试详解

黑盒测试和白盒测试是软件测试中两种最基本的测试方法&#xff0c;它们在测试视角、测试重点和适用场景等方面存在显著差异。 一、黑盒测试 1. 基本概念 黑盒测试又称功能测试&#xff0c;将软件视为一个"黑盒子"&#xff0c;不关心内部结构和实现细节&#xff0c;只…...

准确--配置服务器文件数

某些系统可能在 /etc/security/limits.d/ 目录下有额外配置覆盖全局设置。检查是否存在冲突文件&#xff1a; ls /etc/security/limits.d/如果有文件&#xff08;如 90-nproc.conf 或 90-nofile.conf&#xff09;&#xff0c;需编辑或删除这些文件中的冲突配置。 确保系统启用…...

《熔化焊接与热切割作业》考试注意事项

考试前的准备 携带必要的证件和材料&#xff1a;考生需携带身份证、准考证等有效证件&#xff0c;以及考试所需的焊接工具、材料等。确保证件齐全&#xff0c;避免因证件问题影响考试。 提前检查焊接设备和工具&#xff1a;在考试前&#xff0c;考生应仔细检查焊接设备和工具是…...