You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从timerfd调用read()时出现无效参数错误的技术求助

搞定timerfd read()返回EINVAL(errno=22)的问题

嗨,我碰到过类似的内核版本差异导致的问题,刚好能帮你分析下:

问题根源

你树莓派上用的Linux 4.9.80属于比较老的内核版本,而笔记本的4.15.15是新内核——两者对timerfd的read()调用规则不一样。在4.11之前的内核里,read()读取timerfd时有个硬要求:你给的缓冲区必须能装下一个uint64_t(也就是8字节)。如果缓冲区比这个小,直接就返回EINVAL(错误码22)。

而新内核(4.11及以后)放宽了这个限制,哪怕缓冲区不够大,也会尝试读取(不过这其实不符合man手册里的规范,因为timerfd本来就该返回8字节的到期计数)。

你要检查的两个关键点

  • 缓冲区大小是否正确
    大概率是你用了太小的变量来接收到期计数。比如用int(4字节)而不是uint64_t(8字节)。正确的写法应该是这样:

    uint64_t exp_count;
    ssize_t ret = read(timer_fd, &exp_count, sizeof(exp_count));
    if (ret == -1) {
        perror("read timerfd failed");
    }
    

    要是你之前用的是int,那缓冲区只有4字节,老内核直接就报错了。

  • 确认定时器是否正常触发
    虽然epoll应该是触发了才会调用read,但还是要确认下你有没有正确调用timerfd_settime()把定时器“武装”起来,而且epoll的事件监听有没有配置对(比如有没有设对EPOLLIN事件)。不过这个可能性比缓冲区问题小很多。

快速验证的小技巧

你可以在树莓派的代码里加一行打印,看看传给read()的缓冲区大小是多少:

printf("Buffer size for read: %zu\n", sizeof(exp_count));

如果输出是4,那就是变量类型的问题,改成uint64_t就搞定了。

最后总结

这个问题就是新旧内核对参数的严格程度不一样导致的,只要把接收计数的变量改成uint64_t,保证缓冲区够8字节,树莓派上的错误就会消失啦。

内容的提问来源于stack exchange,提问作者lyfeng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:41:07