4.6.2 错误码
2026/7/16大约 5 分钟内核组件内核错误处理错误码errno
4.6.2 错误码
📚 本节导读
学习时长: 约 15 分钟
难度级别: ⭐⭐☆☆☆
前置知识: C 语言错误处理模式
🎯 学习目标
- 熟悉 OneOS 全部错误码的定义和含义
- 掌握
os_errno()函数和OS_SET_ERRNO/OS_GET_ERRNO宏的使用 - 建立规范的错误码检查模式
一、错误码概念
错误码是 OneOS 错误处理体系的第二层,用于函数返回值的规范化错误报告。当函数执行过程中遇到可预见的运行时错误(如参数无效、资源不足、超时等),函数不会直接崩溃,而是返回相应的错误码,由调用者决定如何处理。
错误码定义在 kernel/include/os_errno.h 中,以 os_err_t 类型(通常是 int 类型)表示。
二、全部错误码定义
以下错误码直接来自 kernel/include/os_errno.h:
#define OS_SUCCESS 0 /* 没有错误,操作成功 */
#define OS_FAILURE -1 /* 通用错误 */
#define OS_TIMEOUT -2 /* 超时 */
#define OS_FULL -3 /* 资源已满 */
#define OS_EMPTY -4 /* 资源为空 */
#define OS_NOMEM -5 /* 内存不足 */
#define OS_NOSYS -6 /* 功能未实现 */
#define OS_BUSY -7 /* 设备或资源忙 */
#define OS_EIO -8 /* IO 错误 */
#define OS_INTR -9 /* 系统调用被中断 */
#define OS_INVAL -10 /* 无效参数 */
#define OS_NODEV -11 /* 无此设备 */
#define OS_EPERM -12 /* 操作不允许 */
#define OS_EBADF -13 /* 错误的文件号 */
#define OS_EACCES -14 /* 权限拒绝 */
#define OS_EFAULT -15 /* 错误的地址 */
#define OS_EDEADLK -16 /* 资源死锁 */
#define OS_ENXIO -17 /* 无此设备或地址 */
#define OS_E2BIG -18 /* 参数列表过长 */
#define OS_ENOSYS -19 /* 功能未实现 */
#define OS_EAGAIN -20 /* 请重试 */
#define OS_ENODATA -21 /* 无可用数据 */
#define OS_EADDRINUSE -22 /* 地址已被使用 */错误码分类
| 类别 | 错误码 | 典型场景 |
|---|---|---|
| 成功 | OS_SUCCESS (0) | 操作成功完成 |
| 通用错误 | OS_FAILURE (-1) | 未分类的通用错误 |
| 时间相关 | OS_TIMEOUT (-2) | 等待超时、操作超时 |
| 资源状态 | OS_FULL (-3) / OS_EMPTY (-4) | 队列满、邮箱满 / 队列空、邮箱空 |
| 内存相关 | OS_NOMEM (-5) | 内存分配失败 |
| 功能状态 | OS_NOSYS (-6) / OS_ENOSYS (-19) | 功能未实现 |
| 设备状态 | OS_BUSY (-7) / OS_NODEV (-11) | 设备忙 / 设备不存在 |
| IO 错误 | OS_EIO (-8) | 输入输出错误 |
| 中断相关 | OS_INTR (-9) | 系统调用被中断信号打断 |
| 参数错误 | OS_INVAL (-10) | 无效参数 |
| 权限相关 | OS_EPERM (-12) / OS_EACCES (-14) | 操作不允许 / 权限拒绝 |
| 文件相关 | OS_EBADF (-13) | 错误的文件描述符 |
| 地址相关 | OS_EFAULT (-15) / OS_EADDRINUSE (-22) | 错误地址 / 地址已占用 |
| 死锁 | OS_EDEADLK (-16) | 资源死锁 |
| 限制相关 | OS_ENXIO (-17) / OS_E2BIG (-18) | 设备不存在 / 参数列表过长 |
| 重试 | OS_EAGAIN (-20) | 临时失败,请重试 |
| 数据 | OS_ENODATA (-21) | 无可用数据 |
三、任务级错误码
3.1 os_errno — 获取任务错误码指针
/* 定义在 kernel/include/os_task.h 中 */
int *os_errno(void);os_errno() 返回当前任务的错误码变量指针。每个任务有自己独立的错误码,不会相互干扰。
3.2 OS_SET_ERRNO / OS_GET_ERRNO
/* 定义在 kernel/include/os_task.h 中 */
#define OS_SET_ERRNO(err_code) *os_errno() = (err_code) /* 设置错误号 */
#define OS_GET_ERRNO() *os_errno() /* 获取错误号 */使用方式:
/* 设置错误码 */
OS_SET_ERRNO(OS_EIO);
/* 获取错误码 */
os_err_t err = OS_GET_ERRNO();与标准 C 库的 errno 类似,OS_SET_ERRNO / OS_GET_ERRNO 提供了任务级别的错误码存储,在线程安全的上下文中使用。
四、错误码检查模式
4.1 基本模式
os_err_t result;
result = os_sem_wait(sem_id, OS_WAIT_FOREVER);
if (result != OS_SUCCESS)
{
/* 处理错误 */
os_kprintf("sem_wait failed: %d\r\n", result);
return result;
}
/* 正常执行 */4.2 模式匹配
os_err_t result = os_mutex_lock(mutex_id, timeout);
switch (result)
{
case OS_SUCCESS:
/* 成功获取锁 */
break;
case OS_TIMEOUT:
/* 超时,做相应处理 */
handle_timeout();
break;
case OS_EDEADLK:
/* 死锁检测 */
handle_deadlock();
break;
default:
/* 其他错误 */
handle_unknown_error(result);
break;
}4.3 使用 OS_SET_ERRNO / OS_GET_ERRNO
void my_function(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "test", callback, OS_NULL,
os_tick_from_ms(1000),
OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
/* os_timer_create 内部可能设置了错误码 */
os_err_t err = OS_GET_ERRNO();
os_kprintf("Timer creation failed, errno: %d\r\n", err);
return;
}
/* 继续使用 timer... */
os_timer_destroy(timer);
}4.4 错误码传播
os_err_t do_step1(void)
{
os_err_t ret;
ret = do_sub_operation();
if (ret != OS_SUCCESS)
{
return ret; /* 向上传播错误码 */
}
return OS_SUCCESS;
}
os_err_t do_step2(void)
{
os_err_t ret;
ret = do_step1();
if (ret != OS_SUCCESS)
{
os_kprintf("Step1 failed with error: %d\r\n", ret);
return ret; /* 继续向上传播 */
}
return OS_SUCCESS;
}五、常见 API 的返回值
| API | 成功返回值 | 失败返回值 |
|---|---|---|
os_timer_create | 定时器 ID | OS_NULL |
os_timer_destroy | OS_SUCCESS | 错误码 |
os_timer_start | OS_SUCCESS | 错误码 |
os_timer_stop | OS_SUCCESS | 错误码 |
os_sem_post | OS_SUCCESS | 错误码 |
os_sem_wait | OS_SUCCESS | OS_TIMEOUT / 错误码 |
os_mutex_lock | OS_SUCCESS | OS_TIMEOUT / OS_EDEADLK / 错误码 |
os_malloc | 有效指针 | OS_NULL (OS_NOMEM) |
六、使用建议
- 始终检查返回值:不要忽略任何 API 的返回值,即使确信"不会出错"
- 区分错误类型:根据错误码做不同的处理,而不是简单地判断"成功/失败"
- 及时处理:不要将错误码延迟到后续处理,应尽早处理
- 传播有意义的错误码:不要将所有错误都转换为
OS_FAILURE,保留原始错误码以便上层做出更精确的判断 - 使用 OS_SET_ERRNO 记录错误:在自定义函数中,对于无法通过返回值传递的错误,使用
OS_SET_ERRNO设置任务级错误码
📝 本节小结
错误码是 OneOS 错误处理体系的第二层,提供了 22 种标准化的错误码用于规范化的错误报告。OS_SUCCESS 表示成功,负值表示各种类型的错误。每个任务拥有独立的错误码变量,通过 os_errno() 访问,OS_SET_ERRNO / OS_GET_ERRNO 宏提供了便捷的读写接口。在实际开发中,始终检查 API 返回值并根据错误类型做相应处理,是编写健壮嵌入式代码的基本要求。