systemd Basic 模块深度分析


  团队博客: 汽车电子社区


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 模块分层架构

网络工具层
系统集成层
进程管理层
文件I/O层
核心工具层
Basic 模块架构
socket-util.c
套接字操作
resolve-util.c
DNS解析
ether-addr-util.c
网络地址
architecture.c
架构检测
build.c
构建信息
conf-files.c
配置文件
env-util.c
环境变量
process-util.c
进程管理
capability-util.c
能力管理
signal-util.c
信号处理
cgroup-util.c
cgroup集成
fileio.c
文件操作
fd-util.c
文件描述符
fs-util.c
文件系统
iovec-wrapper.c
向量I/O
macro.h
扩展宏定义
basic-forward.h
前向声明
assert-util.h
断言工具
cleanup-util.h
清理框架
文件I/O层
核心工具层
进程管理层
系统集成层
网络工具层

7.2 模块依赖关系图

上层模块
Basic 层
Fundamental 层
libsystemd
shared
core
network
macro.h
basic-forward.h
fileio.c
process-util.c
cgroup-util.c
macro-fundamental.h
memory-util-fundamental.h
string-util-fundamental.h
cleanup-fundamental.h

8. 接口调用流程

8.1 安全文件操作流程

调用者 fileio fd-util fs-util 系统 write_string_file(path, data, flags) 检查路径安全性 openat() 系统调用 返回文件描述符 设置 O_CLOEXEC 处理原子写入标志 写入数据到文件 fsync() 同步到磁盘 alt [需要] safe_close() 关闭文件 close() 系统调用 返回操作结果 调用者 fileio fd-util fs-util 系统

8.2 cgroup 操作流程

请求 cgroup 操作
检查控制器支持
控制器是否支持?
返回错误
构建 cgroup 路径
检查路径存在
路径是否存在?
创建 cgroup
设置 cgroup 属性
写入配置文件
验证操作结果
操作成功?
返回成功
清理并返回错误

8.3 进程管理流程

调用者 process-util /proc 文件系统 内核 pid_get_comm(pid) 构建 /proc/[pid]/stat 路径 读取 stat 文件 内核进程信息 返回进程状态 解析进程信息 提取进程名 返回结果 调用者 process-util /proc 文件系统 内核

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 各组件间的一致性和可靠性。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值