Linux getrandom 设置 GRND_NONBLOCK 后为什么返回 EAGAIN
来源:17golang原创
时间:2026-11-15 00:50:55 173浏览 收藏
我在 Linux 服务启动阶段遇到 getrandom() 返回 EAGAIN 时,第一反应也曾是“随机数接口是不是坏了”。但如果调用参数里有 GRND_NONBLOCK,这个结果通常正是参数承诺的行为:随机源还没准备好时,不等待,立即返回。
官方文档:https://man7.org/linux/man-pages/man2/getrandom.2.html
默认从 urandom 源读取时,如果随机池尚未初始化,getrandom 会等待;加入GRND_NONBLOCK后则返回-1,并把errno设为EAGAIN。处理重点不是把 EAGAIN 当成参数错误,而是决定启动流程要延后、有限重试,还是允许系统调用阻塞。
GRND_NONBLOCK 为什么会把等待变成 EAGAIN
getrandom() 默认从 urandom 源获取随机字节。这里有一个启动时序:内核随机池尚未初始化时,普通调用会阻塞;如果 flags 包含 GRND_NONBLOCK,调用者明确告诉内核“不要在这里等”,于是内核用 EAGAIN 表示暂时没有可立即返回的数据。

因此下面两种写法的取舍不同:
/* 允许内核等待随机池就绪;适合不要求启动路径非阻塞的初始化。 */
ssize_t n = getrandom(buf, sizeof buf, 0);
/* 明确不等待;随机池未就绪时要检查 errno == EAGAIN。 */
ssize_t n = getrandom(buf, sizeof buf, GRND_NONBLOCK);
第二种写法并不保证“永远更快”。它只是把等待责任交还给应用:应用可以延后初始化、安排下一次事件,或者做有上限的重试。若把它写成无间隔死循环,反而会在启动早期持续占用 CPU。
先判断返回值,再判断 errno
调用约定很简单,但顺序不能反:返回值为 -1 时才读取 errno;返回非负值时,返回值本身表示已经复制到缓冲区的字节数。对于小于或等于 256 字节、且使用默认 urandom 源的读取,文档给出了“初始化完成后通常一次返回请求字节数”的保证,但代码仍应检查返回值。
#include
#include
#include
int read_seed(unsigned char *buf, size_t size) {
/* 非阻塞只改变“未就绪时怎么返回”,不会改变错误检查规则。 */
ssize_t n = getrandom(buf, size, GRND_NONBLOCK);
if (n == (ssize_t)size) {
/* 读取完整,调用者可以继续初始化。 */
return 0;
}
if (n == -1 && errno == EAGAIN) {
/* 随机池暂未就绪:这是可延后的状态,不是参数错误。 */
return 1;
}
if (n == -1 && errno == EINTR) {
/* 被信号打断,是否重试要由上层策略决定。 */
return 2;
}
/* 其他错误或短读都不能假装成完整种子。 */
return 3;
}
这里返回 1、2、3 是给示例调用者区分状态的本地约定,不是 Linux 的 errno 编号。尤其不要把 n >= 0 直接等价于“成功”:如果请求较大,或者使用了 GRND_RANDOM,返回字节数可能小于请求值。
启动阶段怎样设计有限重试
如果服务必须尽快完成启动,又需要随机种子,可以只对 EAGAIN 做短暂、有限的等待。下面示例使用 256 字节缓冲区,并把重试次数写成显式上限;它是策略示例,不代表某个发行版的最佳时间参数。

#include
#include
#include
int fill_seed(unsigned char seed[32]) {
const int max_attempts = 5; /* 上限防止启动路径无限忙等。 */
for (int attempt = 0; attempt
这个策略有三个关键点:第一,只有明确识别出的暂态情况才重试;第二,重试有总次数上限;第三,耗尽后必须把失败交给上层,而不是用时间戳、固定字符串等不等价的数据替代。对于对启动延迟不敏感的程序,直接不加 GRND_NONBLOCK 可能更简单。
256 字节、GRND_RANDOM 和短读边界
不要把“getrandom 返回 EAGAIN”与所有随机源情况混为一谈:
| 场景 | 需要关注的结果 | 处理重点 |
|---|---|---|
| 默认 urandom,随机池未初始化,带 GRND_NONBLOCK | -1,errno=EAGAIN | 延后或有限重试 |
| 默认 urandom,读取不超过 256 字节且已初始化 | 通常返回完整请求 | 仍检查返回值 |
| 指定 GRND_RANDOM,随机源暂时没有足够字节 | 可能短读或 EAGAIN | 不能假设一次填满 |
| 大于 256 字节的请求被信号打断 | 可能短读或 EINTR | 按实际 n 和 errno 处理 |
在普通服务初始化中,我更倾向于请求较小的缓冲区,并让初始化函数明确返回“完成、暂时不可用、永久失败”三类状态。这样调用方能决定是稍后重试,还是让服务管理器重新安排启动,而不是把内核的时序信号吞掉。
排查 EAGAIN 时的一套判断顺序
- 确认 flags 是否真的包含
GRND_NONBLOCK,不要先去怀疑随机设备文件。 - 只在返回值为
-1时读取errno,确认是否为EAGAIN。 - 确认请求使用的是默认 urandom 源还是
GRND_RANDOM,两者的短读和等待语义不同。 - 检查请求大小,优先把启动阶段的种子读取控制在 256 字节以内。
- 为 EAGAIN 设计有限重试或异步延后,为其他错误保留明确失败路径。
几个容易混淆的问题
EAGAIN 是不是说明 getrandom 参数非法?
不是。非法 flags 通常对应 EINVAL;EAGAIN 表示如果不使用非阻塞标志,调用本来会等待,但当前选择了立即返回。
把 GRND_NONBLOCK 去掉就一定更好么?
不一定。它会让调用可能阻塞,启动路径是否允许等待取决于服务的时延目标、依赖关系和故障处理方式。关键是明确选择,而不是盲目替换参数。
收到 EAGAIN 能不能马上 while 重试?
可以实现,但不建议无间隔无限重试。应使用短暂等待、次数或截止时间上限,并在耗尽后交给上层决定延后启动还是失败退出。
GRND_NONBLOCK 的真正含义,是把“随机源何时可用”从隐式阻塞变成了应用可观察的状态。理解这一点后,EAGAIN 就不再是神秘错误,而是启动流程需要认真处理的一条分支。
-
278 收藏
-
483 收藏
-
291 收藏
-
195 收藏
-
292 收藏
-
267 收藏
-
文章 · linux | 48分钟前 | 命令行工具 · linux运维 · 故障排查 · Linux systemd journalctl 日志排查 启动日志 Boot ID systemd-journald311 收藏
-
文章 · linux | 50分钟前 | linux运维 · 文件系统 · Linux 文件句柄 name_to_handle_at open_by_handle_at file_handle mount_id340 收藏
-
351 收藏
-
490 收藏
-
文章 · linux | 57分钟前 | linux运维 · 故障排查 · 服务治理 · Linux systemd 故障恢复 服务重启 RestartSec StartLimit Restart RestartSteps312 收藏
-
132 收藏
-
文章 · linux | 1小时前 | linux运维 · Linux cgroup v2 frozen cgroup.freeze cgroup.events populated 进程层级 运维监控332 收藏
-
481 收藏
-
313 收藏
-
165 收藏
-
329 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习