背景:
我在用户空间代码中使用 pselect 系统调用来等待 GPIO 引脚进行切换。我知道发生此切换的时间不应超过 5 毫秒,并且我已使用示波器验证了此时间。然而令人困惑的是,pselect 调用有时需要长达 20 毫秒的时间才能返回。
调查:
我修改了 GPIO 驱动程序、内核中的 pselect 实现以及 glibc 库中的 pselect 实现,以便在命中时都打印当前时间。使用这些,我已经验证了 GPIO 驱动程序和内核的 pselect 实现是否及时命中,但是,在内核 pselect 调用返回和紧随 glibc 系统调用进入内核之后的行之间有 6 到 15 毫秒的时间。
我对c库中系统调用如何实现的理解是,特定于体系结构的宏“INLINE_SYSCALL”在用户模式和内核模式之间切换CPU,将参数传递给内核,实际调用内核函数,然后处理设置errno(如果适用) 。在 ARM 中,这个逻辑似乎是几个汇编指令,我希望它们几乎不需要花费任何时间。
硬件和软件:
我使用的是内核版本 4.1.33(带有抢占实时补丁)和 glibc 版本 2.23,在 ARM Cortex A9 上运行。
问题):
从内核函数返回到 glibc 调用内核之后的那一行之间发生了什么,这可以解释任何重大的时间损失?
我可以运行任何其他测试来进一步缩小这次时间损失的原因吗?
更新/编辑:
作为健全性检查,我暂时用一个紧密的繁忙循环替换了 pselect 逻辑,该循环请求尽可能快地获取 GPIO 引脚的值。该循环仅在观察到 gpio 引脚的值发生变化时退出,并且总是在 5 毫秒内退出,这表明 pselect 实际上是问题所在。
经过一些额外的测试后,我发现尽管 poll 系统调用基本上与 pselect 执行相同的操作,但它似乎不会受到使用 pselect 时观察到的时间损失的影响。因此,我能够解决这个问题,但是如果可能的话,我仍然想了解其原因......