退出sd-bus容器时出现'Device or Resource busy'错误的排查求助
问题分析与解决
你的问题核心在于sd-bus消息容器处理不完整,加上错误处理缺失,导致系统总线资源未正确释放,进而引发容器退出时的"Device or Resource busy"错误。具体原因包括:
- 仅调用
sd_bus_message_enter_container和sd_bus_message_exit_container但未遍历容器内所有元素,sd-bus消息指针未正确重置,内部资源无法正常释放。 - 错误处理不完整:
sd_bus_open_system、sd_bus_call_method失败时未清理已分配资源,也未处理sd_bus_error。 - 未确保所有sd-bus对象(
bus、reply)在任何执行路径下都被正确释放。
解决方案
- 完整遍历容器元素:必须遍历数组容器内的每一个结构体元素,直到
sd_bus_message_next_container返回非0,确保消息指针状态正确。 - 完善错误处理:所有sd-bus调用失败时,清理已分配资源并打印明确错误信息。
- 统一资源释放:使用跳转或RAII机制,保证无论执行路径如何,
bus和reply都能被正确unref。
修改后的代码
#include <iostream> #include <unistd.h> #include <systemd/sd-bus.h> #include <cstring> int main() { sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = nullptr; sd_bus_message *reply = nullptr; int ret = 0; // 打开系统总线 ret = sd_bus_open_system(&bus); if (ret < 0) { std::cerr << "打开系统总线失败: " << strerror(-ret) << std::endl; goto cleanup; } const char *service_name = "org.freedesktop.systemd1"; const char *object_path = "/org/freedesktop/systemd1"; const char *interface = "org.freedesktop.systemd1.Manager"; const char *method = "ListUnits"; // 调用ListUnits方法 ret = sd_bus_call_method(bus, service_name, object_path, interface, method, &error, &reply, ""); if (ret < 0) { std::cerr << "调用ListUnits失败: " << error.message << std::endl; sd_bus_error_free(&error); goto cleanup; } // 进入数组容器 ret = sd_bus_message_enter_container(reply, 'a', "(ssssssouso)"); if (ret < 0) { std::cerr << "进入容器失败: " << strerror(-ret) << std::endl; goto cleanup; } // 遍历数组内所有结构体元素 while ((ret = sd_bus_message_enter_container(reply, 'r', nullptr)) > 0) { const char *unit_name, *unit_description, *unit_load_state, *unit_active_state; const char *sub_state, *followed_state, *object1_path, *queued_job, *job_type, *job_object_path; unsigned int uint; // 读取结构体字段(匹配ListUnits返回类型) ret = sd_bus_message_read(reply, "ssssssouso", &unit_name, &unit_description, &unit_load_state, &unit_active_state, &sub_state, &followed_state, &uint, &object1_path, &queued_job, &job_type, &job_object_path); if (ret < 0) { std::cerr << "读取消息字段失败: " << strerror(-ret) << std::endl; break; } // 此处可添加数据处理逻辑,比如打印单元信息 // std::cout << "单元名称: " << unit_name << " 状态: " << unit_active_state << std::endl; // 退出当前结构体容器 sd_bus_message_exit_container(reply); } // 退出数组容器 sd_bus_message_exit_container(reply); cleanup: // 统一释放所有资源 if (reply) sd_bus_message_unref(reply); if (bus) sd_bus_unref(bus); return ret < 0 ? 1 : 0; }
关键修改说明
- 用
goto cleanup统一处理资源释放,避免因执行路径分支导致资源泄漏。 - 遍历数组内每个结构体元素,确保消息指针正确推进,完成容器的完整处理流程。
- 新增
sd_bus_error_free调用,释放错误信息资源。 - 所有sd-bus调用失败时打印明确错误信息,便于调试定位问题。
修改后sd-bus资源会被正确释放,容器退出时不会再出现"Device or Resource busy"错误,同时能正常读取所有单元数据。
内容的提问来源于stack exchange,提问作者안성현
相关产品推荐
相关产品推荐

