文章目录
团队博客: 汽车电子社区
1. 源码结构和文件组织
1.1 目录结构分析
src/basic/ 目录包含 100+ 个文件,构成了 systemd 的基础工具库:
basic/
├── 核心头文件
│ ├── basic-forward.h # 前向声明和类型定义 (4KB)
│ ├── macro.h # 扩展宏定义 (基于 fundamental)
│ ├── cleanup-util.h # 清理工具扩展
│ └── assert-util.h # 断言工具扩展
├── 文件I/O操作
│ ├── fileio.h/c # 文件读写操作 (54KB/8KB)
│ ├── fd-util.h/c # 文件描述符管理 (40KB/7KB)
│ ├── fs-util.h/c # 文件系统工具 (51KB/6KB)
│ ├── dirent-util.h/c # 目录操作
│ └── path-util.h/c # 路径处理工具
├── 进程管理
│ ├── process-util.h/c # 进程操作工具
│ ├── signal-util.h/c # 信号处理
│ ├── capability-util.h/c # 能力管理 (20KB/3KB)
│ └── exit-status.h # 退出状态定义
├── cgroup 集成
│ ├── cgroup-util.h/c # cgroup 操作工具 (50KB/11KB)
│ └── conf-files.c # 配置文件处理 (32KB)
├── 内存和资源管理
│ ├── alloc-util.h/c # 内存分配工具 (3.5KB/10KB)
│ ├── hashmap.h/c # 哈希表实现
│ ├── set.h/c # 集合数据结构
│ └── prioq.h/c # 优先队列
├── 系统信息
│ ├── architecture.h/c # 架构检测 (6KB/8KB)
│ ├── build.h/c # 构建信息
│ └── os-util.h # 操作系统工具
├── 网络工具
│ ├── socket-util.h/c # 套接字操作
│ ├── resolve-util.h/c # DNS 解析工具
│ └── ether-addr-util.h/c # 以太网地址处理 (8KB/4KB)
├── 时间和定时器
│ ├── time-util.h # 时间工具
│ ├── calendar-util.h/c # 日历计算
│ └── sd-event.c # 事件循环实现
└── 杂项工具
├── string-util.h/c # 字符串处理扩展
├── parse-util.h/c # 解析工具
├── format-util.h/c # 格式化工具
├── compress.h/c # 压缩工具 (43KB/4KB)
└── env-util.h/c # 环境变量处理 (33KB/3KB)
1.2 设计特点
分层设计
fundamental (最底层)
↓
basic (基础工具库)
↓
libsystemd/shared (共享库)
↓
core/其他模块 (上层应用)
依赖规则
- basic 只能依赖 fundamental 和自身
- 提供 fundamental 层的扩展和更高层次的抽象
- 为上层模块提供统一的基础设施
2. 核心功能和 API 设计
2.1 文件I/O操作
安全文件写入
// fileio.h:48-57
int write_string_file_full(int dir_fd, const char *fn, const char *line,
WriteStringFileFlags flags, const struct timespec *ts,
const char *label_fn);
typedef enum {
WRITE_STRING_FILE_CREATE = 1 << 0,
WRITE_STRING_FILE_TRUNCATE = 1 << 1,
WRITE_STRING_FILE_ATOMIC = 1 << 2, // 原子写入
WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 4, // 失败时验证
WRITE_STRING_FILE_SYNC = 1 << 6, // 同步写入
WRITE_STRING_FILE_MKDIR_0755 = 1 << 9, // 自动创建目录
} WriteStringFileFlags;
安全文件读取
// fileio.h:66-72
int read_full_file_full(int dir_fd, const char *filename, uint64_t offset,
size_t size, ReadFullFileFlags flags, const char *bind_name,
char **ret_contents, size_t *ret_size);
typedef enum {
READ_FULL_FILE_SECURE = 1 << 0, // 擦除内部缓冲区
READ_FULL_FILE_UNBASE64 = 1 << 1, // Base64 解码
READ_FULL_FILE_UNHEX = 1 << 2, // 十六进制解码
READ_FULL_FILE_CONNECT_SOCKET = 1 << 4, // 连接套接字读取
} ReadFullFileFlags;
2.2 文件描述符管理
安全关闭机制
// fd-util.c:53-73
int safe_close(int fd) {
if (fd >= 0) {
PROTECT_ERRNO; // 保护 errno 不被改变
// 确保文件描述符被关闭,忽略错误
assert_se(close_nointr(fd) != -EBADF);
}
return -EBADF;
}
// 批量关闭操作
void close_many(const int fds[], size_t n_fds);
void close_many_unset(int fds[], size_t n_fds);
非阻塞I/O支持
// fd-util.c 中的高级操作
int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);
int fd_move_above_stdio(int fd);
2.3 进程管理工具
进程信息获取
// process-util.h:37-55
int pid_get_comm(pid_t pid, char **ret); // 获取进程名
int pid_get_cmdline(pid_t pid, size_t max_columns,
ProcessCmdlineFlags flags, char **ret); // 获取命令行
int get_process_exe(pid_t pid, char **ret); // 获取可执行路径
int pid_get_uid(pid_t pid, uid_t *ret); // 获取用户ID
int get_process_cwd(pid_t pid, char **ret); // 获取工作目录
int get_process_environ(pid_t pid, char **ret); // 获取环境变量
进程等待和终止
// process-util.h:73-82
int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags);
int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout);
void sigkill_wait(pid_t pid); // SIGKILL + 等待
void sigterm_wait(pid_t pid); // SIGTERM + 等待
void sigkill_nowait(pid_t pid); // SIGKILL 不等待
2.4 cgroup 集成
控制器管理
// cgroup-util.h:8-32
typedef enum CGroupController {
CGROUP_CONTROLLER_CPU, // CPU 控制器
CGROUP_CONTROLLER_CPUACCT, // CPU 计账 (v1 only)
CGROUP_CONTROLLER_MEMORY, // 内存控制器
CGROUP_CONTROLLER_IO, // I/O 控制器 (v2 only)
CGROUP_CONTROLLER_BLKIO, // 块设备 I/O (v1 only)
CGROUP_CONTROLLER_PIDS, // 进程数控制器
CGROUP_CONTROLLER_DEVICES, // 设备控制器 (v1 only)
// BPF 伪控制器 (v2 only)
CGROUP_CONTROLLER_BPF_FIREWALL,
CGROUP_CONTROLLER_BPF_DEVICES,
CGROUP_CONTROLLER_BPF_FOREIGN,
// ...
} CGroupController;
资源限制定义
// cgroup-util.h:67-81
#define CGROUP_WEIGHT_INVALID UINT64_MAX
#define CGROUP_WEIGHT_IDLE UINT64_C(0)
#define CGROUP_WEIGHT_MIN UINT64_C(1)
#define CGROUP_WEIGHT_MAX UINT64_C(10000)
#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
// I/O 限制类型
typedef enum CGroupIOLimitType {
CGROUP_IO_RBPS_MAX, // 读取字节数限制
CGROUP_IO_WBPS_MAX, // 写入字节数限制
CGROUP_IO_RIOPS_MAX, // 读取IOPS限制
CGROUP_IO_WIOPS_MAX, // 写入IOPS限制
} CGroupIOLimitType;
3. 关键数据结构和算法
3.1 安全的文件操作实现
原子文件写入算法
// fileio.c 中的实现策略
int write_string_file_full(...) {
// 1. 打开临时文件
int fd = openat(dir_fd, fn, O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, mode);
if (fd < 0) return -errno;
// 2. 写入内容
write_string_stream_full(f, line, flags, ts);
// 3. 原子重命名(如果需要)
if (flags & WRITE_STRING_FILE_ATOMIC) {
// 创建临时文件名
char *temp_path = strjoina(fn, ".tmpXXXXXX");
mktemp(temp_path);
rename(temp_path, fn);
}
// 4. 同步到磁盘(如果需要)
if (flags & WRITE_STRING_FILE_SYNC)
fsync(fd);
}
安全内存擦除
// 基于 fundamental 的扩展
static inline void* memory_erase(void *p, size_t l) {
volatile uint8_t *x = (volatile uint8_t*) p;
for (size_t n = 0; n < l; n++)
x[n] = 0; // volatile 防止编译器优化
return p;
}
3.2 进程管理算法
进程存活检测
// process-util.c 中的实现
int pid_is_alive(pid_t pid) {
if (pid <= 0)
return -EINVAL;
// 发送信号 0 检测进程存在性
if (kill(pid, 0) < 0) {
if (errno == ESRCH) // 进程不存在
return 0;
return -errno; // 其他错误
}
return 1; // 进程存在
}
进程启动时间获取
int pid_get_start_time(pid_t pid, usec_t *ret) {
char path[STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) +
STRLEN("/stat") + 1];
sprintf(path, "/proc/" PID_FMT "/stat", pid);
// 解析 /proc/[pid]/stat 的第22个字段
char *content;
int r = read_one_line_file(path, &content);
if (r < 0) return r;
// 提取启动时间(第22个字段,从22开始的字符)
unsigned long long starttime;
sscanf(content, "%*u %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu %*lu %*ld %*ld %*ld %*ld %*ld %*llu",
&starttime);
// 转换为微秒
*ret = (usec_t)starttime * (USEC_PER_SEC / sysconf(_SC_CLK_TCK));
return 0;
}
3.3 cgroup 操作算法
cgroup 路径解析
// cgroup-util.c 中的核心算法
int cg_get_path(const char *controller, const char *path, const char *suffix,
char **ret) {
char *p;
// 1. 构建基础路径
if (controller) {
p = strjoin("/sys/fs/cgroup/", controller, "/", path, suffix);
} else {
p = strjoin("/sys/fs/cgroup/", path, suffix);
}
if (!p) return -ENOMEM;
*ret = p;
return 0;
}
cgroup 层次遍历
// 遍历 cgroup 层次结构
int cg_recursive_summary(const char *controller, const char *path,
unsigned depth, CGroupUnified unified_requested,
void *data,
int (*func)(const char *path, CGroupMask mask, void *data)) {
CGroupMask mask = 0;
// 1. 获取当前 cgroup 信息
int r = cg_mask_from_string(controller, &mask);
if (r < 0) return r;
// 2. 调用回调函数
r = func(path, mask, data);
if (r != 0) return r;
// 3. 递归处理子目录
if (depth > 0) {
DIR *d = opendir(path);
if (!d) return -errno;
struct dirent *de;
while ((de = readdir(d))) {
if (! dirent_is_file(de))
continue;
char *child_path = path_join(path, de->d_name);
cg_recursive_summary(controller, child_path, depth - 1,
unified_requested, data, func);
free(child_path);
}
}
return 0;
}
4. 模块接口设计
4.1 前向声明系统
统一类型定义
// basic-forward.h:23-24
typedef uint64_t usec_t; // 微秒时间类型
typedef uint64_t nsec_t; // 纳秒时间类型
结构体前向声明
// basic-forward.h:72-115
typedef struct Hashmap Hashmap;
typedef struct OrderedHashmap OrderedHashmap;
typedef struct Set Set;
typedef struct Prioq Prioq;
typedef struct dual_timestamp dual_timestamp;
typedef struct PidRef PidRef;
typedef struct RateLimit RateLimit;
枚举类型前向声明
// basic-forward.h:85-97
typedef enum CGroupFlags CGroupFlags;
typedef enum CGroupMask CGroupMask;
typedef enum UnitActiveState UnitActiveState;
typedef enum UnitDependency UnitDependency;
typedef enum UnitType UnitType;
4.2 宏系统扩展
安全宏定义
// macro.h:51-56 (在 fundamental 基础上扩展)
static inline uint64_t u64_multiply_safe(uint64_t a, uint64_t b) {
if (_unlikely_(a != 0 && b > (UINT64_MAX / a)))
return 0; /* 溢出检测 */
return a * b;
}
容器操作宏
// macro.h:82-87 (基于 fundamental)
#define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member)
#define __container_of(uniq, ptr, type, member) \
({ \
const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \
(type*)( (char *)UNIQ_T(A, uniq) - offsetof(type, member) ); \
})
4.3 清理框架扩展
复杂数据结构清理
// cleanup-util.h (基于 fundamental 扩展)
#define CLEANUP_HASHMAP(hashmap) \
_cleanup_(hashmap_freep) Hashmap **UNIQ_T(h, UNIQ) = &(hashmap)
#define CLEANUP_SET(set) \
_cleanup_(set_freep) Set **UNIQ_T(s, UNIQ) = &(set)
#define CLEANUP_PRIOQ(prioq) \
_cleanup_(prioq_freep) Prioq **UNIQ_T(p, UNIQ) = &(prioq)
5. 性能优化策略
5.1 内存操作优化
零拷贝操作
// 使用 iovec 进行批量I/O
struct iovec_wrapper *iovec_wrapper_new(const struct iovec *iov, size_t n);
int iovec_wrapper_write(int fd, struct iovec_wrapper *wrapper);
内存池管理
// 自定义内存分配器
void* mempool_alloc(struct mempool *p, size_t size);
void mempool_free(struct mempool *p, void *ptr);
5.2 文件操作优化
批量文件操作
// 批量关闭优化
void close_many(const int fds[], size_t n_fds) {
FOREACH_ARRAY(fd, fds, n_fds)
safe_close(*fd);
}
// 批量读取优化
int readv_full(int fd, const struct iovec *iov, int iovcnt);
缓存友好设计
// 缓存局部性优化
static inline unsigned long ALIGN_POWER2(unsigned long u) {
if (u == 0) return 0;
if (u == 1) return 1;
return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL));
}
5.3 系统调用优化
减少系统调用
// 合并系统调用
int openat_report(int dirfd, const char *pathname, int flags,
mode_t mode, char **ret_path);
// 批量属性获取
int fstatat_with_timestamps(int dirfd, const char *path,
struct stat *ret_stat,
int flags, struct timespec *ts);
6. 与 Fundamental 层的集成
6.1 依赖关系管理
头文件包含策略
// basic/macro.h
#include "macro-fundamental.h" // 基础宏
// basic/cleanup-util.h
#include "cleanup-fundamental.h" // 基础清理机制
// basic/memory-util.h
#include "memory-util-fundamental.h" // 基础内存管理
功能扩展模式
// 在 fundamental 基础上扩展
static inline void* memory_erase_secure(void *p, size_t l) {
// 1. 调用 fundamental 层的基础擦除
memory_erase(p, l);
// 2. 添加 basic 层的安全检查
assert(p || l == 0);
// 3. 记录擦除操作(如果需要)
// log_debug("Securely erased %zu bytes", l);
return p;
}
6.2 类型系统集成
基础类型扩展
// 在 fundamental 类型基础上扩展
typedef struct {
usec_t realtime; // 基于 fundamental 的 usec_t
usec_t monotonic; // 单调时间
usec_t boot; // 启动时间
} triple_timestamp;
错误处理集成
// 统一的错误处理机制
#define PROPAGATE_ERROR(expr) \
({ \
int _r_ = (expr); \
if (_r_ < 0) \
return log_debug_errno(_r_, "Failed at %s:%u", __FILE__, __LINE__); \
_r_; \
})
7. 软件架构图
7.1 Basic 模块分层架构
7.2 模块依赖关系图
8. 接口调用流程
8.1 安全文件操作流程
8.2 cgroup 操作流程
8.3 进程管理流程
9. 源码分析
9.1 核心算法实现
批量文件关闭优化
// fd-util.c:89-108
void close_many(const int fds[], size_t n_fds) {
assert(fds || n_fds == 0);
FOREACH_ARRAY(fd, fds, n_fds)
safe_close(*fd);
}
void close_many_and_free(int *fds, size_t n_fds) {
assert(fds || n_fds == 0);
close_many(fds, n_fds); // 先关闭所有文件描述符
free(fds); // 再释放数组内存
}
安全信号处理
// process-util.h:73-82
int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) {
siginfo_t si;
int r;
// 等待进程终止
r = wait_for_terminate(pid, &si);
if (r < 0)
return r;
// 检查退出状态并记录日志
if ((flags & WAIT_LOG_ABNORMAL) &&
!(si.si_code == CLD_EXITED && si.si_status == 0))
log_warning("Process %s[%d] failed with %s",
name, pid, sigchld_code_to_string(si.si_code, si.si_status));
return si.si_status;
}
cgroup 控制器检测
// cgroup-util.c 中的实现
int cg_mask_supported(CGroupMask *ret) {
CGroupMask mask = 0;
// 检查每个控制器的可用性
for (CGroupController c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
const char *p;
// 构建 cgroup 控制器路径
p = cgroup_controller_to_string(c);
if (!p)
continue;
// 检查控制器文件是否存在
if (access(p, F_OK) >= 0)
mask |= CGROUP_CONTROLLER_TO_MASK(c);
}
*ret = mask;
return 0;
}
9.2 内存管理机制
安全内存分配
// alloc-util.h 中的安全分配器
static inline void *malloc_multiply(size_t a, size_t b) {
/* 乘法溢出保护 */
if (a == 0 || b == 0)
return NULL;
return a > SIZE_MAX / b ? NULL : malloc(a * b);
}
static inline void *malloc0(size_t l) {
void *p = malloc(l);
if (p)
memset(p, 0, l);
return p;
}
数组操作工具
// alloc-util.h 中的数组操作
#define GREEDY_REALLOC(array, n) \
greedy_realloc((void**)&(array), &(n), sizeof((array)[0]))
int greedy_realloc0(void **p, size_t *need, size_t size);
int greedy_realloc_append(void **p, size_t *need, size_t size);
9.3 字符串处理扩展
安全字符串操作
// string-util.h 中的扩展
static inline char *strstrip(char *s) {
if (!s)
return NULL;
/* 删除末尾空白 */
char *end = s + strlen(s);
while (end > s && ascii_isspace(*(end - 1)))
end--;
*end = 0;
/* 删除开头空白 */
char *start = s;
while (*start && ascii_isspace(*start))
start++;
/* 移动字符串 */
if (start > s)
memmove(s, start, end - start + 1);
return s;
}
路径处理工具
// path-util.h 中的路径操作
bool path_is_absolute(const char *p);
int path_split_and_make_absolute(const char *p, char **ret_dir, char **ret_name);
char* path_kill_slashes(char *path);
bool path_startswith(const char *path, const char *prefix);
10. 代码质量分析
10.1 安全性设计
防御性编程
- 所有公共 API 都进行参数验证
- 使用 assert() 进行内部一致性检查
- 整数溢出保护在所有数值计算中
- 内存操作安全性检查
资源管理
- RAII 风格的自动资源清理
- 异常安全的错误处理
- 内存泄漏防护机制
- 文件描述符泄漏防护
10.2 可维护性特性
模块化设计
- 清晰的模块边界和职责分离
- 最小化模块间依赖
- 统一的接口设计模式
- 一致的命名约定
代码质量
- 详细的代码注释和文档
- 静态分析工具集成
- 代码覆盖率测试
- 持续集成质量检查
10.3 性能特性
优化策略
- 零拷贝操作
- 缓存友好的数据结构
- 批量操作减少系统调用
- 编译器优化利用
可扩展性
- 内存池管理
- 哈希表和集合的高效实现
- 事件驱动架构支持
- 多线程安全设计
总结
systemd 的 basic 模块展现了优秀的系统级工具库设计:
1. 架构设计:分层清晰、职责明确、接口稳定
2. 功能丰富:覆盖文件I/O、进程管理、系统集成等核心领域
3. 安全可靠:完善的错误处理、资源管理、安全检查
4. 性能优化:高效的数据结构、系统调用优化、内存管理
5. 可维护性:模块化设计、清晰接口、完善文档
basic 模块为整个 systemd 项目提供了可靠的基础设施,是连接 fundamental 基础层和上层应用模块的重要桥梁。通过精心设计的 API 和丰富的功能集合,它确保了 systemd 各组件间的一致性和可靠性。

573

被折叠的 条评论
为什么被折叠?



