当前位置: 首页 > 工具软件 > SylixOS > 使用案例 >

SylixOS快问快答

高恺
2023-12-01

Q: SylixOS 版权是什么形式, 是否分为<开发版税>和<运行时版税>.

A: SylixOS 是开源并免费的操作系统, 支持 BSD/GPL 协议(GPL 版本暂未确定). 没有任何的运行时版税. 您可以用她来做任何 您喜欢做的项目. 也可以修改 SylixOS 的源代码, 不需要支付任何费用. 当然笔者希望您可以将使用 SylixOS 开发的项目 (不需要开源)或对 SylixOS 源码的修改及时告知笔者.
需要指出: SylixOS 本身仅是笔者用来提升自己水平而开发的一款软件(具有公益性质).

Q: 为什么内核模块在文件中加入了 #define __SYLIXOS_KERNEL 还是没有从 SylixOS.h 中引出内核相关定义?

A: #define __SYLIXOS_KERNEL 一定要放在引用 SylixOS.h 前, 有可能出现文件交叉引用, 导致 内核头文件先于 __SYLIXOS_KERNEL 引用, 所以建议内核模块将 #define __SYLIXOS_KERNEL 放在文件起始, 后面再引用其他头文件.

Q: 为什么加入一些标准 C 库头文件会与 SylixOS 内部数据结构冲突?

A: SylixOS 为了提高兼容性与稳定性, SylixOS 提供了一套最适合自身多线程操作系统特点的标准 C 库(暂不包含数学库). 这套 C 库相关代码是从其他开源项目中演变而来. 当然为了配合 SylixOS 系统, 很多地方做出了修改.这些库中相关的定义会随着 #include <SylixOS.h> 一同引入用户程序, 当用户引用其他辅助 C 库时, 可能产生一些重复定义问题.
这里推荐使用 SylixOS 提供的 C 库, 以保持多线程系统最大的可靠性(除非 SylixOS 没有提供的部分)。 (推荐引用头文件时, 所有头文件使用 “” 方式而不是 <> 因为 SylixOS 已经包含 C 库, 并且在编译器中也
设置了相关的查找目录, 使用 “” 将不会产生使用错误的库造成的问题)

Q: 我的处理器包含多级中断系统 (例如: 级联 8259), 而 SylixOS 的中断向量仅为单级, BSP 部分该怎么设计?

A: SylixOS 使用单级中断系统, 可以通过编译配置来设置操作系统向量表的条目数(内核并不限制中断向量的个数), BSP 需要将硬件多级中断机制抽象为 SylixOS 系统的单级中断机制, 从而使设备驱动程序的编写变得更加容易可靠, 平台无关性好.

Q: 我的项目不需要使用 SylixOS 自带的 lwip 协议栈, 但是又没有找到相关的裁剪宏, 该怎么解决?

A: SylixOS 内部使用了很多开源的中间库(操作系统与相关库接口部分, 符合对应库的license), 绝大多数库中都加入了配置宏, 如: FAT, YAFFS 等, 但是, 由于 lwip 文件过多, 这里没有使用配置宏进行裁剪. 推荐使用两种方法进行裁剪:

  1. 如果使用 IDE 环境, 直接将 lwip 协议栈(/net/lwip/src) 目录从工程中移除, 同时将LW_CFG_NET_EN宏 (net_cfg.h) 置为 0. 并且将所有 net_tools_cfg.h 中的工具都配置为 0.

  2. 如果单纯使用 Make 工具, 则需要修改 MakeFile 或 Config 文件将相关的目标移除即可.当然如果硬件平台 ROM & RAM 空间够大, 则建议保留网络系统.

Q: 我的系统莫名其妙的崩溃, 但却找不到问题.

A: 遇到这种问题, 首先需要检查堆栈的使用情况, 在 shell 环境下可以使用 ss 命令查看, 但是这并不能完全确定是否是堆栈溢出, 因为有可能在检查时, 某线程堆栈使用量较少, 当发生某种情况时, 堆栈用量会突然增加, 例如:多级函数调用, 或某函数局部变量众多, 或者有很大的局部数组, 这都会引起堆栈用量迅速上升, 所以建议不要使用大的局部数据, 而应使用动态内存分配, 如对实时性有要求, 可以先预置分配好的内存供未来使用, 总之要减少局部数组变量的大小. 当发生以上情况(堆栈用量瞬间上升并导致溢出), ss 命令可能束手无策. 这时就可以对怀疑的线程加大堆栈, 再次调试.

堆栈与系统的稳定性关系密切, 所以遇事可以先检查堆栈情况(分配海量的堆栈), 然后再找问题. 这也是笔者总结的经验! SylixOS 操作系统有很多守护线程, 他们的堆栈用量也很关键, 在 SylixOS 配置文件中有相关的定义, 除非系统内存紧张, 一般情况下, 笔者不建议您减少系统线程的堆栈, 特别是 ftp, shell 等等规模较大的线程, 他们可能会突然使用较大的堆栈, 您平时可能无法察觉, 如果分配的少系统可能突然崩溃(所有实时操作系统基本都是这样).

所以笔者请您认真的衡量每个线程堆栈的大小!


Q: 系统配置宏 LW_CFG_PATH_AUTO_CONDENSE 有什么作用?

A: LW_CFG_PATH_AUTO_CONDENSE 可以使系统在处理 io 路径时, 首先进行路径压缩, 也就是说处理掉路径中的 . 和 … 例如: 假设系统存在名为 “/DEVICE” 的设备.
当 LW_CFG_PATH_AUTO_CONDENSE 为 0 时, open(“/DEVICE/b/c/d/…/…/…/./x”); 函数最终会调用到驱动程序 xxxOpen 时 路径将为: “/b/c/d/…/…/…/./x”. 所以, 设备驱动程序一定要支持 . 和 … 目录的处理.
当 LW_CFG_PATH_AUTO_CONDENSE 为 1 时, open(“/DEVICE/b/c/d/…/…/…/./x”); 函数最终会调用到驱动程序 xxxOpen 时 路径将为: “/x”. 操作系统自动将 . 和 … 按照规则予以滤除.

当然 LW_CFG_PATH_AUTO_CONDENSE 为 1 时, 操作系统对文件的打开操作将会稍慢.
但是文件的读写等操作并不受影响. 系统默认是关闭此项功能的, 需要在 system_cfg.h 中将其设置为 1.
当 LW_CFG_PATH_AUTO_CONDENSE 为 1 时, 需要适当稍微加大操作 io 线程的堆栈.


Q: 我怀疑我的应用程序存在内存泄露, 检查起来相当困难, 有没有什么好办法?

A: sylixos 专门设计了一个小型的内存跟踪器用于检查内存使用情况, 探明泄露的内存信息. 此探测器对除了 VMM 模块外的所有的动态内存分配与回收操作皆有效果.

要打开此功能首先要在 shell_cfg.h 中将 LW_CFG_SHELL_HEAP_TRACE_EN 配置宏置为 1, LW_CFG_SHELL_HEAP_TRACE_BUFFER 宏表示跟踪器最多能够缓存的非对称分配数量(def:1024). 此跟踪器需要配合 shell 应用, leakchkstart 命令用于启动内存跟踪器, leakchkstop 用于停止跟踪器, 停止后, 跟踪器将会打印出从 leakchkstart 到 leakchkstop 之间分配并且没有释放的内存信息. 配合源码调试, 方便查找内存泄露原因. 如果你想不想停止跟踪器, 那么就先启动内存跟踪器, 然后可以随时使用 leakchk 查看当前的内存分配状态.

注意: 一般 kernel 内存堆由操作系统负责分配回收, 不会产生泄露, 但是像 lwip 的 timeout cleanup push 可能会造成内存泄露假象, 但是这并不是内存泄露, 操作系统会在适当的时候回收此内存. 遇到 kernel 堆泄露信息可以忽略.

有些操作可能也会导致内存泄露假象, 例如: 向 yaffs 磁盘写入文件或数据等等. 由于 yaffs 本身需要缓存相关信息, 所以自身会占用一些内存, 而非内存泄露. 可以在 fs_cfg.h 中将LW_CFG_YAFFS_ MEMORY_EN 宏置为 1. 使 yaffs 使用自己独立的内存堆来排除 yaffs 系统对内存泄露检查时的干扰.

内存泄露对于嵌入式实时系统来说是比较严重的问题, 由于嵌入式系统应用一般来说较为确定, 最好的解决办法是设计应用时对系统内存的分配回收做好全盘规划并严格执行, 这才是最好的设计方法.


Q: FTP 在传输大批量文件时(成百上千个), PASV 模式有时无法建立, 同时有可能崩溃?

A: FTP 客户端工具在传输大批量文件传输时, 一般会建立多条访问链接, 造成 TCP 控制块不足, 从而导致 PASV 无法建立.

可在编译操作系统时, 加大 TCP 控制块的数量. 但是这并不是导致 FTP 服务器崩溃的原因, 导致崩溃极有可能是 FTP 服务器堆栈不足. FTP 堆栈默认为 12KBytes. 不应该减小此堆栈的大小.


Q: LW_CFG_PATH_VXWORKS 配置是什么意思?

A: 早期的 SylixOS 系统一直使用与 VxWorks 相同的 IO 管理模式, 所有的设备都链入一个统一的链表, 所有设备都是平级关系,设备名中可以包含 “/”. 此目录结构较为简单, 管理简便, 内存堆栈消耗都较小. 但是唯一的缺点就是单级目录不同于 unix目录结构. (LW_CFG_PATH_VXWORKS == 1)

新的 SylixOS 系统推出一种新的 IO 目录管理模式, 所有的设备都挂入 rootfs (根文件系统). 根文件系统可以进行分级目录管理, 类似 unix 系统. 设备名中不能包含 “/”. 所有的设备均放入 /dev 目录下, 此管理模式使用内存和堆栈稍多. 此种方式操作方便安全, 使用健全的根目录管理方式, 同时还提供符号链接文件的支持 . 当使用新的目录管理机制时, 系统将自动在根目录创建 3 个目录作为挂载点: “/dev” “/var” “/mnt”, 根据经验分别 挂载通用设备, 挂载临时设备或文件, 挂载文件系统卷标. 其他的常用目录可以通过 bsp 启动代码或其他多种方式链接到实际的 存储设备中(通过 symbol link), 例如: symlink(“/yaffs2/n0/etc”, “/etc”);(LW_CFG_PATH_VXWORKS == 0)

您习惯于 unix linux … 系统开发时, 可使用 LW_CFG_PATH_VXWORKS == 0 的方式.

您习惯于 VxWorks 的简单目录管理方式时, 可使用 LW_CFG_PATH_VXWORKS == 1 的方式.


Q: 为什么有些文件系统中不能建立链接文件?

A: 当使用新的 SylixOS 分级目录管理时, SylixOS 提供了部分的链接文件支持(不支持硬链接, 仅支持 unix 符号链接), 但是仅仅是在根文件系统(root fs)所属的目录中, 目前 SylixOS 的其他文件系统还不支持链接文件, 所以链接文件(symbol path) 必须在 root fs 管辖的目录中(可以满足绝大多数的应用!). 例如: 可以调用 symlink(“/yaffs2/n0/etc”, “/etc”);或者执行 ln -s /yaffs2/n0/etc /etc 命令即可. 注意: 链接文件内部不能再次建立连接文件!(LW_CFG_PATH_VXWORKS == 1)

当 LW_CFG_PATH_VXWORKS == 1 时, 表示使用 VxWorks 兼容目录时(单层链表式), SylixOS 将不提供任何链接支持.


Q: 编译 libsylixos 后链接器无法连接.

A: 这可能是连接器参数过多超过了某些 sh 的最多(或最长)参数限制. 推荐使用一些支持长参数的 sh 工具或者将 sylixos 源码分块编译并打包成众多 lib*.a 文件. 然后统一连接.


Q: 使用 polarSSL 库时, 有时莫名奇妙的出现线程崩溃.

A: polarSSL 库源于著名的 xySSL 库. 是专为嵌入式系统设计的加密算法库(比 openSSL 小很多). polarSSL 的一些函数, 对堆栈的使用相当大, 有时会达到 50KBytes 以上, 所以建议将需要加密运算的功能放在一个堆栈很大的线程中执行.


Q: 怎样裁剪 libsylixos 第三方软件库.

A: 起初 sylixos 加入第三方软件库是为了测试 sylixos 系统的稳定性与兼容性, 后期作者觉得这些库非常有用于是就保留了下来,几乎所有的第三方软件库源码都在 SylixOS/appl 目录下存放. 当你不需要这些组件时, 只需要手动将代码移除即可, 同时删除appl.h 中引用的相关头文件.


Q: 为什么创建的命名 posix 对象无法在文件系统中找到.

A: SylixOS 使用一个独有的符号空间来管理命名的 posix 对象 (很多操作系统都是如此). 这些对象并不存在于文件系统中.

如果系统加入了 proc 文件系统的支持, 则可以通过查看 /proc/posix/pnamed 文件来查看 posix 命名对象的使用情况.


Q: 为什么通过 FTP 下载的文件会与源文件不同, 例如通过一个 FTP 将一个可执行文件拷入 sylixos 系统, 然后却无法运行.

A: 请注意 FTP 的传输模式, TYPE I 表示二进制, TYPE A 表示 ASCII. 当传输应用程序时, 如果上位机的 FTP 客户端使用TYPE A 模式, 可能会造成应用程序部分字节错误 (但对于文本却没有影响), 这时, 需要设置 FTP 客户端使用二进制模式来传输应用程序等二进制文件.


Q: 使用 loader 装载应用程序执行, 为什么在程序退出时, 系统崩溃或者不稳定?

A: 此问题, 详见 MODULE 文档应用程序模型注意事项.


Q: 我创建的一个设备, 例如: /dev/abc 当应用程序打开设备文件正在操作时, 我调用 iosDevDelete 卸载设备, 此时应用程序

如果再操作这个已经打开的设备文件可能会出错或者崩溃.

A: 设备删除一般有两个方法:

  1. 单独的设备删除函数, 例如: pipe, can… 他们都会有一个独立的设备删除函数. 调用此函数将会删除设备文件

  2. 将设备删除函数装入驱动程序表的 remove 函数指针, 当调用 remove() / unlink() 函数删除设备文件时, 系统将自动

    调用对应驱动程序的 remove 函数. 例如: Fat 文件系统设备

这两种方法的设备删除过程比较类似, 需要做以下几个步骤:

  1. 调用 iosDevFileAbnormal() 使打开此设备的文件转换为异常模式, 此时, 所有打开此设备的文件均不可能再次访问设备.

    iosDevFileAbnormal() 相当关键!

  2. iosDevDelete() 移除设备.

如果设备存在 select() 功能时, 需要加入如下过程:

  1. SEL_WAKE_UP_LIST_TERM(…) 结束 select() 等待队列.

Q: 在 SylixOS INT8 类型是否带有符号

A: INT8 类型在 BSP 中定义, SylixOS 要求 INT8 型为有符号 8 位整形, 有些编译器默认 char 为无符号数, 所以在 BSP中尽一定要将 INT8 定义为 signed char 型. (int8_t 类型由 INT8 定义, C99 中要求 int8_t 为有符号数)


Q: 为什么有时, dirent 中的 d_type 字段为 DT_UNKNOWN ?

A: SylixOS 并不是所有的文件系统(或设备)都支持 d_type 字段, 当文件系统 readdir() 操作无法获取文件类型时, d_type字段应为 DT_UNKNOWN , 这时需要通过 stat() 系列函数来获取文件的具体类型.


Q: 很多特种设备读写都是按块/帧来发送与接收的, 那么 read()/write() 第三个参数和返回值单位是什么?

A: 根据 POSIX 标准, read()/write() 的第三个参数为 nbyte, 也就是为字节数, 不管你的设备到底读写的是什么, 他表示的是 read()/write() 缓冲区的大小, 例如: CAN 设备, 键盘设备, 鼠标设备, 都是这样, 第三个参数和返回值都是字节数.
详细情况请查看, SylixOS/system/device/can/can.h 或者 SylixOS/system/device/input/keyboard.h SylixOS/system/device/input/mouse.h


Q: 为什么我设置了网络数据包过滤器规则, 还是能够接收到本应该被过滤掉的数据包?

A: 网卡默认的驱动程序是不经过 Net Packet Filter 层, 直接将数据送入协议栈的, 必须显式的调用 inetNpfAttach() 函数将 Net Packet Filter 层绑定到网卡上, 此时, 网络数据包过滤器规则才对绑定的网络接口生效.


Q: 为什么我编译的内核模块或者动态链接库, 使用 readelf 观察, 发现内部有很多 gcc libc 的符号? sylixos 无法装载?

A: 由于兼容性问题, sylixos 自带有一个小型的 c 库, 实现了大部分的 libc 的函数, sylixos 操作系统及其模块, 动态库 应用程序, 必须使用 sylixos 自带的 c 库, 所以, 编译应用程序或者模块时, 一定要将 sylixos 提供的所有头文件加入到编译器优先搜索的目录中(-D"…"), 编译动态装载程序时, gcc 的参数一定需要以下三个:

-nostartfiles -nodefaultlibs -nostdlib

这样才能保证 gcc 不引入 gcc 自带的库函数, gcc 自动产生的 memset memcpy memmove memcmp 等已经包含在了 sylixos符号表中, 在编译命令最后一个参数处加入 -lgcc, 这样就加入了编译器最基本的函数库! 这个库恰恰是 sylixos 动态程序运行需要的!

例如:

gcc -nostartfiles -nodefaultlibs -nostdlib -r -o kmodule_test.ko kmodule_test.c -lgcc
gcc -nostartfiles -nodefaultlibs -nostdlib -fpie -pie -shared -o kmodule_test.so kmodule_test.c -lgcc

注意, 编译动态链接库时, 一定要使用 -pie 参数, 不能使用 -pic 参数, 请查阅相关手册. (1.0.0后以支持)


Q: SylixOS 内核模块, 动态链接库或应用程序是否支持 C++ ?

A: SylixOS 内核提供基础的 C++ 运行时支持, 他不仅支持将 C++ 程序与 SylixOS 镜像一起运行, 也支持将 C++ 程序作为动态模块来装载运行, 注意: SylixOS 暂不支持 C++ 异常处理. (如果为应用程序, 链接时加入 -lstdc++ 即可兼容标准C++)


Q: 我编译的应用程序, 已经连接了相应的库, 但是装在运行时, 操作系统还是提示缺少指定的符号,

A: 这个问题是链接时库的顺序问题, 例如: 你的应用程序需要 libx 系统相应的服务, 但是 libx 又需要 liby 提供服务, 这时, 最终的连接命令应写成如下格式:

gcc -nostartfiles -nostdlib -fPIC -shared -o ???.so ???.c -libx -liby -lgcc

ld 链接时, 默认从左向右搜索库, 所以, 最基础的库应该放在最后, 在上例中, 必须先写 -libx 再写 -liby.


Q: 因为 SylixOS 使用 elf 类型 gcc 编译, 一般此类编译器提供的都是 *.a 的静态标准库, 如果我想使用像 linux 一样的动态链接库?

例如: 我想使用 libstd++.so 可是工具链却提供的是 libstd++.a

A: 一下两句可以将静态库转换为动态库: (例如要转换 libstd++.a -> libstd++.so)

arm-sylixos-eabi-ar -x libstdc++.a
arm-sylixos-eabi-g++ -nostdlib -fPIC -shared *.o -o libstdc++.so -lm -lgcc


Q: 我的系统发生缺页中断后, 打印了一些调试系统就重启或者任务被杀死了

A: 由于 SylixOS 操作系统为了保持硬实时操作系统的特性, 所以内核与应用程序没有严格的隔离, 缺页中断如果发生在内核被锁定或者中断中, 则操作系统不能正确处理, 这里需要应用程序员与驱动开发人员注意.


Q: 卸载卷是应该注意什么

A: SylixOS 所有支持热插拔设备(包括文件系统), 当设备需要卸载时, 需要将所有未写入的数据回写磁盘(sync()), 同时关闭所有对此设备操作的文件, 方可以卸载设备, 如果强行卸载, SylixOS 会自动将与此设备有关的文件设置为异常状态, 但是如果这个文件恰巧正在操作磁盘, 可能造成对异常指针的操作, 造成非常危险的结果, 所以不推荐这样操作. 应该首先 umount 这个设备如果无法 umount 则有文件占用, 最好不要强行拔掉可移动卷, 否则非常危险.

注意: 所有可以动态添加与卸载的设备, 必须在 hotplug 线程的上下文中串行的执行, 包括 oemDisk 的操作.


Q: 使用 FPU 应该注意什么

A: SylixOS 支持浮点协处理器, 每一个任务(线程有自己的 FPU 上下文, 可以独立的进程浮点运算), 但是, SylixOS 内核代码包括内核模块, 中断函数, BSP包等等, 强烈不建议使用 FPU 指令, 因为没有独立的 FPU 上下文, 除非操作系统启动时, 参数 kfpu 为 yes, 这样操作系统在中断中会切换 FPU 的上下文, 但是这将造成操作系统中断延迟加大, 所以, 除非兼容老的系统, 其他情况不建议在内核和中断中使用 FPU, 所以在编译操作系统内核, BSP, 驱动程序, 内核模块时, 不要加入 FPU 支持, 特别是编译操作系统内核时, 严禁加入 FPU 指令. 应用程序中可以随意加入 FPU 的支持.


Q: 我的程序遇到有静态初始化的 POSIX 对象, 例如 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 可是在运行时操作系统却提示错误, 这是为什么?

A: SylixOS 内的所有 POSIX 对象都是内核对象, 这点与 VxWorks RTEMS 类似, 所以这些对象都不支持静态初始化, 所以 SylixOS 建议所有的 POSIX 对象均使用对应的创建(或初始化)函数初始化, 并在使用完之后释放, 如果你需要移植的库不方便修改源代码, 则可以使用下列方法, 例如你需要创建静态初始化的 mutex 对象:

#define SYLIXOS_INITIALIZER_MUTEX_FIX(mutex)    \
        __attribute__((constructor)) static void __init_mutex_fix_##mutex (void) \
        {   \
            pthread_mutex_init(&mutex, (void *)0); \
        }   \
        __attribute__((destructor)) static void __deinit_mutex_fix_##mutex (void) \
        {   \
            pthread_mutex_destroy(&mutex); \
        }

则可以:

 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    
   SYLIXOS_INITIALIZER_MUTEX_FIX(mutex)

只需要加入 SYLIXOS_INITIALIZER_MUTEX_FIX(mutex) 话即可.

这是在模块创建的时候使用构造函数创造所有的对象, 然后模块卸载是则释放所有的对象.

1.0.0 之后版本的 SylixOS 支持进程资源自动回收, 所以已经支持的 posix 对象静态初始化.


Q: SylixOS 环境变量是怎么样的?

A: SylixOS 拥有一整套环境变量的算法库, 它定义在 shell 中. 系统上电时, 从 /etc/profile 中获取, 这些系统的全局环境变量模板系统全局环境变量可以通过 shell 来修改, 然后通过 varsave 命令保存到 /etc/profile 文件中.

进程启动时将通过全局环境变量初始化自身的环境变量, 进程内部对环境变量的修改不影响全局环境变量


Q: SylixOS 支持宽字符和多国语言吗

A: SylixOS 内核有限支持宽字符操作, 但是如果是 SylixOS, 只需要连接 libcextern 库, 则 SylixOS 提供全功能的多国语言支持,可以选择的语言与编码位于 /usr/share/locale 目录下. 用户可自行添加需要支持的语言与编码.


Q: 我只用 curses 库的时候为什么不能工作

A: 首先链接应用程序时需要加入对 libcurses 的依赖, 同时 libcurses 依赖于 libcextern.其次检查环境变量 TERM 是否有效, 例如 TERM=vt100, 最后检查环境变量 TERMCAP 指向的 termcap 文件是否有效, 如果无效这需添加这个文件, 默认为 /etc/termcap


Q: 我的程序使用 execl() 系列函数无法加载程序

A: SylixOS 提供 execl() 系列函数来加载可执行文件, 替换本进程空间内的执行程序, SylixOS 要求 execl() 函数必须在一个进程的主线程内被调用, 他将回收当前进程空间并保留进程控制块, 然后使用新的程序替换当前进程执行的程序.


Q: SylixOS 提供了多种多路 I/O 复用的方法, 如 select, poll, epoll 用哪一种比较好呢

A: SylixOS 内核提供的最基本的多路 I/O 复用是 select 子系统, 他的效率最高, 而 poll 和 epoll 均是 SylixOS 为了保证兼容性而在select 子系统上抽象出一层接口, 所以推荐使用 select 子系统. 另外 SylixOS 提供的 epoll fd 不支持再此 select.


Q: SylixOS 是否提供 eventfd signalfd timerfd

A: SylixOS 支持 linux 在 2.6 版添加的 eventfd signalfd timerfd 功能, 其中 eventfd 与 timerfd 功能与 linux 完全相同 signalfd 与 linux 有些许不同, 向进程发送信号时, linux 会选择一个最合适的进程内目标线程, 而 SylixOS 总是发送给进程内部的主线程, 所以 signalfd 的 read 与 select 操作只能接收到针对当前线程的 pend 信号, 例如一个进程主线程为 t1, t1 创建了线程 t2, 如果 t2 线程 read 或者 select signalfd, 则只能接收到针对 t2 的信号, 针对进程(也就是t1)的信号则无法接收. 如果需要侦听针对进程的信号, 则对 signalfd 的 read 与 select 操作必须在主线程中.


Q: 我想使用高速的周期定时服务, 例如 1ms 周期或者更高, 我应该如何设计

A: SylixOS 内核支持两种定时器: 高速定时器和应用定时器. 其中应用定时器是最基本的定时器, 为了一些周期较长的定时服务而设计, 他的最小分辨周期为 tick, 同时 SylixOS 提供的 POSIX 标准定时器和兼容 linux 的 timerfd 都是基于此类型定时器.

高速定时器是专门用于短周期高频定时服务而设计的, 高速定时器工作频率可以通过 hstimerfd_hz() 获取, 如果要在内核里使用, 则直接通过 SylixOS 提供的 API 访问即可, 如果需要在应用中使用, 则可以引用 sys/hstimerfd.h 中声明的设备访问接口访问.

需要说明的是在设计 BSP 时, 如果系统需要 1ms 周期的定时服务, 则对应的硬件定时器可以设计成 1ms 一次中断, 然后直接调用 API_TimerHTicks(), 如果此时为了避免过高的 tick 造成系统负载加重, 则可以用如下程序解决:

void  timer_interrupt_service (void)
   {
       static int  cnt = 0;
       
       if (cnt == 10) {
           cnt =  0;
           API_KernelTicksContext();
           ...  /* call API_KernelTicks() or wakeup tick thread to call API_KernelTicks() */
       } else {
           cnt++;
           API_TimerHTicks();
       }
   }

以上的定时器中断服务设计可以使系统 tick 为高速定时器分辨率的 1 / 10, 例如高速定时器周期为 1ms, 则 tick 为 10ms.

 类似资料: