tee系统调用及示例tee

tee函数详解

1. 函数介绍

tee函数是Linux系统中一个非常实用的函数,它的作用就像现实中的”T型管道”一样。想象一下水管系统中的T型接头,水从主管道流入,同时流向两个不同的分支管道。在Linux编程中,tee函数就是这样一个”管道分流器”,它能够将一个管道中的数据同时复制到另一个管道中,而不需要将数据从内核空间复制到用户空间再复制回去。

使用场景:

  • 管道数据的复制和分流
  • 避免不必要的数据拷贝,提高程序性能
  • 实现数据的并行处理
  • 日志记录系统中同时写入多个输出流

2. 函数原型

#include <fcntl.h>
ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);

3. 功能

tee函数的主要功能是在两个管道描述符之间高效地复制数据。它不经过用户空间,直接在内核中完成数据的复制,这大大提高了效率。这个函数特别适用于需要将数据从一个管道同时发送到多个目的地的场景。

4. 参数

  • fd_in: 源管道文件描述符(输入端)
    • 类型:int
    • 含义:数据来源的管道描述符,必须是管道或套接字
  • fd_out: 目标管道文件描述符(输出端)
    • 类型:int
    • 含义:数据目标的管道描述符,必须是管道或套接字
  • len: 要复制的数据长度
    • 类型:size_t
    • 含义:希望复制的最大字节数
  • flags: 操作标志
    • 类型:unsigned int
    • 含义:控制复制行为的标志位
    • 常用值:
      • SPLICE_F_MOVE:尽可能移动页面而不是复制
      • SPLICE_F_NONBLOCK:非阻塞操作
      • SPLICE_F_MORE:提示还有更多数据要写入
      • SPLICE_F_GIFT:页面是礼品(内核内部使用)

5. 返回值

  • 成功: 返回实际复制的字节数(ssize_t类型)
  • 失败: 返回-1,并设置errno错误码
    • EINVAL:参数无效
    • EBADF:文件描述符无效
    • ESPIPE:文件描述符不是管道
    • ENOMEM:内存不足

6. 相似函数或关联函数

  • splice(): 在文件描述符之间移动数据
  • vmsplice(): 从用户空间缓冲区向管道写入数据
  • read()/write(): 传统的数据读写函数
  • pipe(): 创建管道

7. 示例代码

示例1:基础tee使用 – 简单的数据分流

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

int main() {
    int pipe1[2], pipe2[2];  // 创建两个管道
    char buffer1[100], buffer2[100];
    ssize_t bytes_written, bytes_read;
    
    // 创建管道1
    if (pipe(pipe1) == -1) {
        perror("创建管道1失败");
        exit(EXIT_FAILURE);
    }
    
    // 创建管道2
    if (pipe(pipe2) == -1) {
        perror("创建管道2失败");
        exit(EXIT_FAILURE);
    }
    
    // 向管道1写入数据
    const char* message = "Hello, tee function!";
    write(pipe1[1], message, strlen(message));
    
    // 使用tee函数将管道1的数据复制到管道2
    // 注意:tee不消耗数据,数据仍保留在源管道中
    bytes_written = tee(pipe1[0], pipe2[1], strlen(message), SPLICE_F_NONBLOCK);
    
    if (bytes_written == -1) {
        perror("tee函数执行失败");
        exit(EXIT_FAILURE);
    }
    
    printf("tee函数复制了 %zd 字节的数据\n", bytes_written);
    
    // 从管道1读取数据(验证数据仍然存在)
    bytes_read = read(pipe1[0], buffer1, sizeof(buffer1) - 1);
    if (bytes_read > 0) {
        buffer1[bytes_read] = '\0';
        printf("从管道1读取: %s\n", buffer1);
    }
    
    // 从管道2读取数据(验证数据已成功复制)
    bytes_read = read(pipe2[0], buffer2, sizeof(buffer2) - 1);
    if (bytes_read > 0) {
        buffer2[bytes_read] = '\0';
        printf("从管道2读取: %s\n", buffer2);
    }
    
    // 关闭所有文件描述符
    close(pipe1[0]);
    close(pipe1[1]);
    close(pipe2[0]);
    close(pipe2[1]);
    
    return 0;
}

示例2:tee实现日志同时输出到文件和终端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

int main() {
    int log_pipe[2], stdout_pipe[2];
    int log_file;
    ssize_t bytes_copied;
    const char* log_message = "这是一个重要的日志信息\n";
    
    // 创建管道用于日志处理
    if (pipe(log_pipe) == -1) {
        perror("创建日志管道失败");
        exit(EXIT_FAILURE);
    }
    
    // 创建管道用于标准输出
    if (pipe(stdout_pipe) == -1) {
        perror("创建标准输出管道失败");
        exit(EXIT_FAILURE);
    }
    
    // 打开日志文件
    log_file = open("app.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (log_file == -1) {
        perror("打开日志文件失败");
        exit(EXIT_FAILURE);
    }
    
    // 向日志管道写入消息
    write(log_pipe[1], log_message, strlen(log_message));
    
    // 使用tee将日志同时复制到标准输出管道和日志文件
    // 第一次tee:复制到标准输出管道
    bytes_copied = tee(log_pipe[0], stdout_pipe[1], strlen(log_message), SPLICE_F_MORE);
    if (bytes_copied == -1) {
        perror("tee复制到标准输出失败");
        exit(EXIT_FAILURE);
    }
    
    // 第二次tee:复制到日志文件(使用splice,因为文件不是管道)
    // 注意:tee只能用于管道之间,文件需要使用splice
    bytes_copied = splice(log_pipe[0], NULL, log_file, NULL, strlen(log_message), SPLICE_F_MOVE);
    if (bytes_copied == -1) {
        perror("splice复制到日志文件失败");
        exit(EXIT_FAILURE);
    }
    
    // 从标准输出管道读取并显示
    char output_buffer[256];
    ssize_t bytes_read = read(stdout_pipe[0], output_buffer, sizeof(output_buffer) - 1);
    if (bytes_read > 0) {
        output_buffer[bytes_read] = '\0';
        printf("终端输出: %s", output_buffer);
    }
    
    printf("日志已同时写入文件和终端\n");
    
    // 清理资源
    close(log_pipe[0]);
    close(log_pipe[1]);
    close(stdout_pipe[0]);
    close(stdout_pipe[1]);
    close(log_file);
    
    return 0;
}

示例3:tee与管道链结合使用

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>

int main() {
    int pipe1[2], pipe2[2], pipe3[2];
    pid_t pid1, pid2;
    
    // 创建三个管道
    if (pipe(pipe1) == -1 || pipe(pipe2) == -1 || pipe(pipe3) == -1) {
        perror("创建管道失败");
        exit(EXIT_FAILURE);
    }
    
    // 创建第一个子进程 - 数据生产者
    pid1 = fork();
    if (pid1 == 0) {
        // 子进程1:向管道1写入数据
        close(pipe1[0]); // 关闭读端
        const char* data = "数据流: 1 2 3 4 5\n";
        write(pipe1[1], data, strlen(data));
        close(pipe1[1]);
        exit(0);
    }
    
    // 创建第二个子进程 - 数据处理和分流
    pid2 = fork();
    if (pid2 == 0) {
        // 子进程2:使用tee分流数据
        close(pipe1[1]); // 关闭管道1的写端
        close(pipe2[0]); // 关闭管道2的读端
        close(pipe3[0]); // 关闭管道3的读端
        
        // 使用tee将管道1的数据同时复制到管道2和管道3
        ssize_t copied = tee(pipe1[0], pipe2[1], 1024, SPLICE_F_MORE);
        if (copied > 0) {
            // 再次tee复制到第三个管道
            tee(pipe1[0], pipe3[1], 1024, 0);
        }
        
        close(pipe1[0]);
        close(pipe2[1]);
        close(pipe3[1]);
        exit(0);
    }
    
    // 父进程:读取分流后的数据
    close(pipe1[0]); close(pipe1[1]); // 父进程不需要管道1
    close(pipe2[1]); // 父进程不需要管道2的写端
    close(pipe3[1]); // 父进程不需要管道3的写端
    
    // 等待子进程完成
    waitpid(pid1, NULL, 0);
    waitpid(pid2, NULL, 0);
    
    // 读取管道2的数据
    char buffer2[256];
    ssize_t bytes2 = read(pipe2[0], buffer2, sizeof(buffer2) - 1);
    if (bytes2 > 0) {
        buffer2[bytes2] = '\0';
        printf("处理器1收到: %s", buffer2);
    }
    
    // 读取管道3的数据
    char buffer3[256];
    ssize_t bytes3 = read(pipe3[0], buffer3, sizeof(buffer3) - 1);
    if (bytes3 > 0) {
        buffer3[bytes3] = '\0';
        printf("处理器2收到: %s", buffer3);
    }
    
    // 清理资源
    close(pipe2[0]);
    close(pipe3[0]);
    
    return 0;
}

编译和运行

# 编译示例1
gcc -o tee_example1 tee_example1.c
./tee_example1

# 编译示例2
gcc -o tee_example2 tee_example2.c
./tee_example2

# 编译示例3
gcc -o tee_example3 tee_example3.c
./tee_example3

通过这些示例,你可以看到tee函数在数据分流、日志处理和管道链中的强大应用。记住,tee函数的关键优势是避免了用户空间和内核空间之间的数据拷贝,这在处理大量数据时能显著提高性能。

发表在 linux文章 | 留下评论

tgkill系统调用及示例

tgkill函数详解

1. 函数介绍

tgkill函数是Linux系统中一个精确的进程控制函数,它的名字来源于”Thread Group Kill”(线程组杀死)。在Linux中,每个进程实际上是一个线程组,主线程的ID就是进程ID。tgkill允许你精确地向指定进程组中的特定线程发送信号。

可以把tgkill想象成一个”精确制导导弹”,它不仅能指定攻击哪个”军队”(进程组),还能精确指定攻击该军队中的哪个”士兵”(特定线程)。相比之下,传统的kill函数更像是”地毯式轰炸”,可能会影响整个进程组。

使用场景:

  • 多线程程序中精确控制特定线程
  • 线程调试和测试
  • 实现线程间通信机制
  • 精确的线程终止控制

2. 函数原型

#include <sys/syscall.h>
#include <signal.h>

long syscall(SYS_tgkill, int tgid, int tid, int sig);
// 或者使用封装函数(如果系统提供)
int tgkill(int tgid, int tid, int sig);

注意:tgkill不是标准C库函数,通常需要通过系统调用来使用。

3. 功能

tgkill函数的主要功能是向指定的线程组中的特定线程发送信号。它提供了比传统kill函数更高的精确度:

  • tgid(Thread Group ID):线程组ID,通常是进程ID
  • tid(Thread ID):线程ID,指定线程组中的具体线程
  • sig:要发送的信号

4. 参数

  • tgid: 线程组ID(Thread Group ID)
    • 类型:int
    • 含义:目标线程所属的线程组ID,通常等于进程ID(PID)
  • tid: 线程ID(Thread ID)
    • 类型:int
    • 含义:线程组中具体线程的ID,必须是该线程组中的有效线程
  • sig: 信号编号
    • 类型:int
    • 含义:要发送给目标线程的信号,如SIGTERM、SIGKILL、SIGUSR1等

5. 返回值

  • 成功: 返回0
  • 失败: 返回-1,并设置errno错误码
    • EINVAL:信号编号无效
    • ESRCH:找不到指定的线程组或线程
    • EPERM:没有权限向目标线程发送信号
    • EAGAIN:系统资源不足

6. 相似函数或关联函数

  • kill(): 向进程发送信号
  • pthread_kill(): 向POSIX线程发送信号
  • raise(): 向当前进程发送信号
  • signal()/sigaction(): 设置信号处理函数
  • getpid(): 获取当前进程ID
  • gettid(): 获取当前线程ID

7. 示例代码

示例1:基础tgkill使用 – 精确控制线程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <signal.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>

// 获取线程ID的辅助函数
pid_t gettid(void) {
    return syscall(SYS_gettid);
}

// 线程处理函数
void signal_handler(int sig) {
    printf("线程 %d 收到信号 %d (%s)\n", gettid(), sig, strsignal(sig));
}

// 工作线程函数
void* worker_thread(void* arg) {
    int thread_num = *(int*)arg;
    pid_t tid = gettid();
    
    printf("工作线程 %d 启动,线程ID: %d\n", thread_num, tid);
    
    // 设置信号处理函数
    signal(SIGUSR1, signal_handler);
    signal(SIGTERM, signal_handler);
    
    // 线程主循环
    while(1) {
        printf("线程 %d 正在工作...\n", tid);
        sleep(2);
    }
    
    return NULL;
}

// tgkill系统调用封装
int tgkill(int tgid, int tid, int sig) {
    return syscall(SYS_tgkill, tgid, tid, sig);
}

int main() {
    pthread_t threads[3];
    int thread_nums[3] = {1, 2, 3};
    pid_t main_tid = gettid();
    pid_t pids[3];
    int i;
    
    printf("主线程ID: %d, 进程ID: %d\n", main_tid, getpid());
    
    // 创建多个工作线程
    for(i = 0; i < 3; i++) {
        if(pthread_create(&threads[i], NULL, worker_thread, &thread_nums[i]) != 0) {
            perror("创建线程失败");
            exit(EXIT_FAILURE);
        }
        // 给线程一些时间启动
        sleep(1);
        pids[i] = gettid(); // 这里简化处理,实际应该从线程中获取
    }
    
    // 让线程运行一段时间
    sleep(3);
    
    // 向特定线程发送自定义信号
    printf("\n=== 向线程发送SIGUSR1信号 ===\n");
    if(tgkill(getpid(), pids[0], SIGUSR1) == 0) {
        printf("成功向线程 %d 发送 SIGUSR1 信号\n", pids[0]);
    } else {
        perror("tgkill发送信号失败");
    }
    
    sleep(2);
    
    // 向另一个线程发送终止信号
    printf("\n=== 向线程发送SIGTERM信号 ===\n");
    if(tgkill(getpid(), pids[1], SIGTERM) == 0) {
        printf("成功向线程 %d 发送 SIGTERM 信号\n", pids[1]);
    } else {
        perror("tgkill发送信号失败");
    }
    
    sleep(2);
    
    // 演示错误处理
    printf("\n=== 演示错误处理 ===\n");
    if(tgkill(999999, 999999, SIGTERM) == -1) {
        printf("向不存在的线程发送信号失败(预期行为): %s\n", strerror(errno));
    }
    
    // 等待几秒观察结果
    sleep(3);
    
    // 强制终止所有线程
    printf("\n=== 终止所有线程 ===\n");
    for(i = 0; i < 3; i++) {
        tgkill(getpid(), pids[i], SIGKILL);
    }
    
    return 0;
}

示例2:线程监控和管理

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <signal.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <time.h>

#define MAX_THREADS 5

// 线程信息结构体
typedef struct {
    pthread_t thread;
    pid_t tid;
    int id;
    int running;
    time_t start_time;
} thread_info_t;

thread_info_t threads[MAX_THREADS];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// 获取线程ID
pid_t gettid(void) {
    return syscall(SYS_gettid);
}

// 信号处理函数
void signal_handler(int sig) {
    pid_t tid = gettid();
    printf("[信号处理] 线程 %d 收到信号: %s\n", tid, strsignal(sig));
    
    if(sig == SIGUSR1) {
        printf("[信号处理] 线程 %d 将暂停工作\n", tid);
        sleep(5);
        printf("[信号处理] 线程 %d 恢复工作\n", tid);
    } else if(sig == SIGTERM) {
        printf("[信号处理] 线程 %d 准备退出\n", tid);
        pthread_exit(NULL);
    }
}

// 工作线程函数
void* worker_thread(void* arg) {
    thread_info_t* info = (thread_info_t*)arg;
    info->tid = gettid();
    info->running = 1;
    info->start_time = time(NULL);
    
    printf("工作线程 %d 启动,系统线程ID: %d\n", info->id, info->tid);
    
    // 设置信号处理
    signal(SIGUSR1, signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGINT, signal_handler);
    
    // 工作循环
    while(info->running) {
        printf("线程 %d 正在处理任务...\n", info->tid);
        sleep(3);
    }
    
    printf("线程 %d 正常退出\n", info->tid);
    return NULL;
}

// tgkill封装函数
int tgkill(int tgid, int tid, int sig) {
    return syscall(SYS_tgkill, tgid, tid, sig);
}

// 显示所有线程状态
void show_thread_status() {
    printf("\n=== 线程状态 ===\n");
    pthread_mutex_lock(&mutex);
    for(int i = 0; i < MAX_THREADS; i++) {
        if(threads[i].tid != 0) {
            time_t uptime = time(NULL) - threads[i].start_time;
            printf("线程 %d: TID=%d, 状态=%s, 运行时间=%lds\n", 
                   threads[i].id, threads[i].tid,
                   threads[i].running ? "运行中" : "已停止",
                   uptime);
        }
    }
    pthread_mutex_unlock(&mutex);
    printf("================\n\n");
}

int main() {
    int i;
    
    printf("主线程监控程序启动,PID: %d\n", getpid());
    
    // 初始化线程信息
    memset(threads, 0, sizeof(threads));
    
    // 创建工作线程
    for(i = 0; i < MAX_THREADS; i++) {
        threads[i].id = i + 1;
        if(pthread_create(&threads[i].thread, NULL, worker_thread, &threads[i]) != 0) {
            perror("创建线程失败");
            exit(EXIT_FAILURE);
        }
        printf("创建线程 %d\n", i + 1);
    }
    
    // 给线程一些启动时间
    sleep(2);
    
    // 显示初始状态
    show_thread_status();
    
    // 演示各种tgkill操作
    printf("=== 演示tgkill操作 ===\n");
    
    // 向第一个线程发送暂停信号
    if(tgkill(getpid(), threads[0].tid, SIGUSR1) == 0) {
        printf("向线程 %d 发送暂停信号\n", threads[0].tid);
    }
    
    sleep(1);
    
    // 向第三个线程发送终止信号
    if(tgkill(getpid(), threads[2].tid, SIGTERM) == 0) {
        printf("向线程 %d 发送终止信号\n", threads[2].tid);
        pthread_mutex_lock(&mutex);
        threads[2].running = 0;
        pthread_mutex_unlock(&mutex);
    }
    
    sleep(2);
    show_thread_status();
    
    // 向所有线程发送中断信号
    printf("向所有线程发送中断信号...\n");
    pthread_mutex_lock(&mutex);
    for(i = 0; i < MAX_THREADS; i++) {
        if(threads[i].tid != 0 && threads[i].running) {
            if(tgkill(getpid(), threads[i].tid, SIGINT) == 0) {
                printf("向线程 %d 发送中断信号\n", threads[i].tid);
            }
        }
    }
    pthread_mutex_unlock(&mutex);
    
    sleep(2);
    
    // 等待所有线程结束
    for(i = 0; i < MAX_THREADS; i++) {
        if(threads[i].tid != 0) {
            pthread_join(threads[i].thread, NULL);
            printf("线程 %d 已结束\n", threads[i].id);
        }
    }
    
    printf("所有线程已安全退出,程序结束\n");
    return 0;
}

示例3:错误处理和权限检查

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <signal.h>
#include <errno.h>
#include <string.h>

// tgkill封装函数
int tgkill(int tgid, int tid, int sig) {
    return syscall(SYS_tgkill, tgid, tid, sig);
}

// 错误处理函数
void handle_error(const char* operation) {
    switch(errno) {
        case EINVAL:
            printf("%s 失败: 无效的信号编号\n", operation);
            break;
        case ESRCH:
            printf("%s 失败: 找不到指定的线程或进程\n", operation);
            break;
        case EPERM:
            printf("%s 失败: 权限不足\n", operation);
            break;
        default:
            printf("%s 失败: %s\n", operation, strerror(errno));
            break;
    }
}

int main() {
    pid_t my_pid = getpid();
    pid_t my_tid = syscall(SYS_gettid);
    
    printf("当前进程信息:\n");
    printf("  进程ID (PID): %d\n", my_pid);
    printf("  线程ID (TID): %d\n", my_tid);
    printf("  用户ID (UID): %d\n", getuid());
    printf("  有效用户ID (EUID): %d\n", geteuid());
    printf("\n");
    
    // 测试1: 向自己发送信号(应该成功)
    printf("=== 测试1: 向当前线程发送信号 ===\n");
    if(tgkill(my_pid, my_tid, SIGUSR1) == 0) {
        printf("✓ 成功向当前线程发送信号\n");
    } else {
        handle_error("向当前线程发送信号");
    }
    
    // 测试2: 使用无效信号编号
    printf("\n=== 测试2: 使用无效信号编号 ===\n");
    if(tgkill(my_pid, my_tid, 999) == -1) {
        handle_error("使用无效信号");
    }
    
    // 测试3: 向不存在的进程发送信号
    printf("\n=== 测试3: 向不存在的进程发送信号 ===\n");
    if(tgkill(999999, 999999, SIGTERM) == -1) {
        handle_error("向不存在的进程发送信号");
    }
    
    // 测试4: 向不存在的线程发送信号
    printf("\n=== 测试4: 向不存在的线程发送信号 ===\n");
    if(tgkill(my_pid, 999999, SIGTERM) == -1) {
        handle_error("向不存在的线程发送信号");
    }
    
    // 测试5: 发送各种标准信号
    printf("\n=== 测试5: 发送标准信号 ===\n");
    int signals[] = {SIGHUP, SIGINT, SIGQUIT, SIGUSR1, SIGUSR2};
    const char* signal_names[] = {"SIGHUP", "SIGINT", "SIGQUIT", "SIGUSR1", "SIGUSR2"};
    int num_signals = sizeof(signals) / sizeof(signals[0]);
    
    for(int i = 0; i < num_signals; i++) {
        printf("发送 %s (信号 %d)... ", signal_names[i], signals[i]);
        if(tgkill(my_pid, my_tid, signals[i]) == 0) {
            printf("成功\n");
        } else {
            printf("失败\n");
        }
    }
    
    printf("\n=== 完成所有测试 ===\n");
    printf("注意: 某些信号可能被系统忽略或有特殊处理\n");
    
    return 0;
}

编译和运行

# 编译示例1(需要链接pthread库)
gcc -o tgkill_example1 tgkill_example1.c -lpthread
./tgkill_example1

# 编译示例2
gcc -o tgkill_example2 tgkill_example2.c -lpthread
./tgkill_example2

# 编译示例3
gcc -o tgkill_example3 tgkill_example3.c
./tgkill_example3

重要注意事项

  1. 权限要求: tgkill需要适当的权限才能向目标线程发送信号
  2. 线程ID获取: 需要在线程内部调用syscall(SYS_gettid)获取真实的线程ID
  3. 错误处理: 必须检查返回值并适当处理错误
  4. 信号安全: 在信号处理函数中只能调用异步信号安全的函数
  5. 跨平台兼容性: tgkill是Linux特有的系统调用,不适用于其他操作系统

通过这些示例,你可以理解tgkill在精确线程控制方面的强大功能,它为多线程程序提供了精细化的控制能力。

发表在 linux文章 | 留下评论

timerfd_create, timerfd_gettime, timerfd_settime系统调用及示例

好的,我们来深入学习 timerfd 相关的系统调用 (timerfd_createtimerfd_gettimetimerfd_settime)

1. 函数介绍

在 Linux 系统编程中,处理定时事件是一个常见需求。传统的定时方法包括:

  1. alarm() 和 setitimer() + 信号 (SIGALRM):当定时器到期时,内核会发送一个信号给进程。这属于异步通知方式。信号处理函数有诸多限制(只能调用异步安全函数),并且容易引入竞态条件。
  2. sleep() 系列函数:让进程休眠指定时间。这会阻塞进程,不够灵活。

timerfd 是 Linux 2.6.25 引入的一种基于文件描述符 (File Descriptor) 的定时器接口。它巧妙地将定时器“变成”了一个可以像文件一样操作的描述符。

  • 你调用 timerfd_create() 创建一个定时器,它会返回一个文件描述符
  • 你调用 timerfd_settime() 来启动或修改这个定时器的超时时间和间隔。
  • 当定时器到期时,这个文件描述符就会变为可读状态。
  • 你可以在程序的主循环中使用 read()poll()select() 或 epoll_wait() 等 I/O 多路复用函数来监听这个文件描述符。当 read() 成功时,就意味着定时器超时了。

简单来说,timerfd 就是把定时器“变成”了可以像文件一样读取的数据流,让你可以用处理文件 I/O 或网络 I/O 的方式来处理定时事件。

典型应用场景

  • 事件驱动服务器:将定时器集成到 epoll/poll 的主循环中,统一处理网络 I/O 和定时事件。
  • 避免信号处理的复杂性:用同步的 read() 替代异步的信号处理函数。
  • 精确控制定时:可以创建一次性定时器或周期性定时器。

2. 函数原型

#include <sys/timerfd.h> // 包含 timerfd 相关函数和结构体

// 创建一个定时器并返回文件描述符
int timerfd_create(int clockid, int flags);

// 获取定时器的当前设置
int timerfd_gettime(int fd, struct itimerspec *curr_value);

// 启动或重新设置定时器
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);

3. 功能

  • timerfd_create: 创建一个新的定时器对象,并返回一个与之关联的文件描述符。
  • timerfd_gettime: 查询指定定时器文件描述符的当前定时设置(下次超时时间和间隔)。
  • timerfd_settime: 启动、停止或修改指定定时器文件描述符的定时设置。

4. 参数详解

timerfd_create(int clockid, int flags)

  • clockid:
    • int 类型。
    • 指定定时器基于哪个时钟源。常用的有:
      • CLOCK_REALTIME: 系统实时时钟,表示从 Unix 纪元(1970-01-01 00:00:00 UTC)开始的时间。如果系统时间被手动修改,这个时钟会受到影响。
      • CLOCK_MONOTONIC: 单调时钟,表示从某个未指定起点开始的时间,不会受到系统时间调整的影响,是测量间隔的首选。
  • flags:
    • int 类型。
    • 用于修改定时器行为的标志位。常用的有:
      • TFD_CLOEXEC: 在执行 exec() 系列函数时自动关闭该文件描述符。
      • TFD_NONBLOCK: 使 read() 操作变为非阻塞模式。如果当前没有定时器到期事件可读,read() 会立即返回 -1 并设置 errno 为 EAGAIN 或 EWOULDBLOCK
  • 返回值:
    • 成功: 返回一个有效的定时器文件描述符(非负整数)。
    • 失败: 返回 -1,并设置 errno

timerfd_gettime(int fd, struct itimerspec *curr_value)

  • fd:
    • int 类型。
    • 一个有效的定时器文件描述符。
  • curr_value:
    • struct itimerspec * 类型。
    • 一个指向 struct itimerspec 结构体的指针。函数调用成功后,会将定时器的当前设置填充到这个结构体中。
  • 返回值:
    • 成功: 返回 0。
    • 失败: 返回 -1,并设置 errno

timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value)

  • fd:
    • int 类型。
    • 一个有效的定时器文件描述符。
  • flags:
    • int 类型。
    • 控制 new_value 中时间的解释方式。主要标志:
      • 0 (默认): new_value->it_value 指定的是从当前时间点开始的相对超时时间。
      • TFD_TIMER_ABSTIMEnew_value->it_value 指定的是一个绝对的超时时间点(基于创建定时器时指定的 clockid)。
  • new_value:
    • const struct itimerspec * 类型。
    • 指向一个 struct itimerspec 结构体,定义了新的定时器设置。
  • old_value:
    • struct itimerspec * 类型。
    • 如果不为 NULL,函数调用成功后,会将定时器在设置前的旧设置填充到这个结构体中。如果不需要旧值,可以传 NULL
  • 返回值:
    • 成功: 返回 0。
    • 失败: 返回 -1,并设置 errno

struct itimerspec 结构体

这个结构体用于定义定时器的时间设置:

struct timespec {
    time_t tv_sec;  /* 秒 */
    long   tv_nsec; /* 纳秒 */
};

struct itimerspec {
    struct timespec it_interval; /* 定时器的时间间隔 (周期性定时器) */
    struct timespec it_value;    /* 首次超时的相对/绝对时间 */
};
  • it_value: 指定首次超时的时间。
    • 如果 tv_sec 和 tv_nsec 都为 0,则定时器被停止
    • 如果非 0,则指定定时器下次到期的时间。
  • it_interval: 指定定时器到期后,重复的间隔时间。
    • 如果 tv_sec 和 tv_nsec 都为 0,则定时器是一次性的
    • 如果非 0,则定时器在首次到期后,会按此间隔周期性地重复到期。

5. 如何使用定时器文件描述符

  1. 创建: 使用 timerfd_create() 创建定时器,获得 fd
  2. 设置: 使用 timerfd_settime() 配置定时器的超时和间隔。
  3. 等待: 在主循环中,使用 poll()select()epoll_wait() 或直接 read() (如果设置为阻塞) 来等待 fd 变为可读。
  4. 读取: 当 fd 可读时,调用 read(fd, &expirations, sizeof(expirations))read() 会成功,并且读取到一个 uint64_t 类型的整数,表示自上次 read() 以来定时器到期的次数
  5. 查询/修改: 可以随时使用 timerfd_gettime() 查询当前设置,或再次调用 timerfd_settime() 修改设置。

6. 错误码 (errno)

这些函数共享一些常见的错误码:

  • EINVAL: 参数无效(例如 clockid 无效,flags 无效,itimerspec 字段值无效)。
  • EMFILE: 进程已打开的文件描述符数量达到上限 (RLIMIT_NOFILE)。
  • ENFILE: 系统已打开的文件描述符数量达到上限。
  • ENOMEM: 内核内存不足。
  • EBADFfd 不是有效的文件描述符。
  • EFAULTnew_valueold_value, 或 curr_value 指向无效内存。

7. 相似函数或关联函数

  • alarm / setitimer: 传统的基于信号的定时器。
  • pollselectepoll_wait: I/O 多路复用函数,可以监听 timerfd 文件描述符的可读事件。
  • read: 用于从 timerfd 中读取到期次数。
  • close: 关闭 timerfd 文件描述符。
  • clock_gettime / clock_settime: 获取和设置不同类型的系统时钟。
  • POSIX 定时器 (timer_createtimer_settimetimer_gettime): 另一套定时器 API,也使用信号通知。

8. 示例代码

下面的示例演示了如何使用 timerfd 创建一次性定时器和周期性定时器,并将其集成到 poll 系统调用中。

#define _GNU_SOURCE // 启用 GNU 扩展
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/timerfd.h> // timerfd 相关
#include <poll.h>       // poll 相关
#include <string.h>
#include <errno.h>
#include <inttypes.h>   // 包含 PRIu64 宏,用于 printf uint64_t

// 辅助函数:打印 itimerspec 结构
void print_itimerspec(const char* prefix, const struct itimerspec *ts) {
    printf("%s: ", prefix);
    if (ts->it_value.tv_sec == 0 && ts->it_value.tv_nsec == 0) {
        printf("Timer is STOPPED\n");
    } else {
        printf("Next expiration in %ld.%09ld seconds\n", ts->it_value.tv_sec, ts->it_value.tv_nsec);
    }
    printf("     Interval: %ld.%09ld seconds\n", ts->it_interval.tv_sec, ts->it_interval.tv_nsec);
}

int main() {
    int tfd_one_shot, tfd_periodic;
    struct itimerspec one_shot_time, periodic_time;
    struct pollfd fds[3]; // 监听两个 timerfd 和 标准输入
    uint64_t expirations;
    ssize_t s;

    printf("--- Demonstrating timerfd ---\n");
    printf("PID: %d\n", getpid());

    // 1. 创建两个 timerfd
    // 一次性定时器,基于单调时钟
    tfd_one_shot = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
    if (tfd_one_shot == -1) {
        perror("timerfd_create one-shot");
        exit(EXIT_FAILURE);
    }
    printf("Created one-shot timerfd: %d\n", tfd_one_shot);

    // 周期性定时器,基于单调时钟,非阻塞
    tfd_periodic = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
    if (tfd_periodic == -1) {
        perror("timerfd_create periodic");
        close(tfd_one_shot);
        exit(EXIT_FAILURE);
    }
    printf("Created periodic timerfd: %d (non-blocking)\n", tfd_periodic);

    // 2. 设置一次性定时器:3秒后到期
    one_shot_time.it_value.tv_sec = 3;     // 3 秒后
    one_shot_time.it_value.tv_nsec = 0;
    one_shot_time.it_interval.tv_sec = 0;  // 一次性,不重复
    one_shot_time.it_interval.tv_nsec = 0;
    if (timerfd_settime(tfd_one_shot, 0, &one_shot_time, NULL) == -1) {
        perror("timerfd_settime one-shot");
        close(tfd_one_shot);
        close(tfd_periodic);
        exit(EXIT_FAILURE);
    }
    printf("Set one-shot timer to expire in 3 seconds.\n");

    // 3. 设置周期性定时器:立即启动,每 2 秒重复一次
    periodic_time.it_value.tv_sec = 0;     // 立即启动
    periodic_time.it_value.tv_nsec = 1;    // 纳秒设为1,确保立即触发第一次
    periodic_time.it_interval.tv_sec = 2;  // 每 2 秒重复
    periodic_time.it_interval.tv_nsec = 0;
    if (timerfd_settime(tfd_periodic, 0, &periodic_time, NULL) == -1) {
        perror("timerfd_settime periodic");
        close(tfd_one_shot);
        close(tfd_periodic);
        exit(EXIT_FAILURE);
    }
    printf("Set periodic timer to start immediately and repeat every 2 seconds.\n");

    // 4. 查询并打印初始定时器状态
    struct itimerspec curr_time;
    if (timerfd_gettime(tfd_one_shot, &curr_time) == 0) {
        print_itimerspec("One-shot timer initial state", &curr_time);
    }
    if (timerfd_gettime(tfd_periodic, &curr_time) == 0) {
        print_itimerspec("Periodic timer initial state", &curr_time);
    }

    // 5. 设置 poll 的文件描述符数组
    fds[0].fd = tfd_one_shot;
    fds[0].events = POLLIN;
    fds[1].fd = tfd_periodic;
    fds[1].events = POLLIN;
    fds[2].fd = STDIN_FILENO;
    fds[2].events = POLLIN;

    printf("\nEntering main loop. Waiting for timers or input (type 'quit' to exit)...\n");

    // 6. 主循环:使用 poll 等待事件
    int one_shot_done = 0;
    while (!one_shot_done) { // 循环直到一次性定时器完成
        int poll_num = poll(fds, 3, -1); // -1 表示无限期等待
        if (poll_num == -1) {
            if (errno == EINTR) {
                continue; // poll 被信号中断,继续等待
            } else {
                perror("poll");
                break;
            }
        }

        if (poll_num > 0) {
            // 检查一次性定时器
            if (fds[0].revents & POLLIN) {
                s = read(tfd_one_shot, &expirations, sizeof(expirations));
                if (s == sizeof(expirations)) {
                    printf("\n[ONE-SHOT TIMER] Expired! Expirations counted: %" PRIu64 "\n", expirations);
                    one_shot_done = 1; // 设置标志退出循环

                    // 再次查询状态,确认已停止
                    if (timerfd_gettime(tfd_one_shot, &curr_time) == 0) {
                        print_itimerspec("One-shot timer final state", &curr_time);
                    }
                } else {
                    perror("read one-shot timerfd");
                }
            }

            // 检查周期性定时器
            if (fds[1].revents & POLLIN) {
                s = read(tfd_periodic, &expirations, sizeof(expirations));
                if (s == sizeof(expirations)) {
                    printf("\n[PERIODIC TIMER] Expired! Expirations counted: %" PRIu64 "\n", expirations);
                    // 可以在这里处理周期性任务
                } else if (s == -1) {
                    if (errno != EAGAIN && errno != EWOULDBLOCK) {
                         perror("read periodic timerfd"); // 非 EAGAIN 的错误
                    } // EAGAIN/EWOULDBLOCK 是正常的,因为我们设置了 NONBLOCK
                }
            }

            // 检查标准输入
            if (fds[2].revents & POLLIN) {
                char buf[16];
                ssize_t nread = read(STDIN_FILENO, buf, sizeof(buf) - 1);
                if (nread > 0) {
                    buf[nread] = '\0';
                    printf("Read from stdin: %s", buf);
                    if (strncmp(buf, "quit\n", 5) == 0) {
                        printf("Exiting due to 'quit' command.\n");
                        break;
                    }
                } else if (nread == 0) {
                    printf("EOF on stdin (Ctrl+D). Exiting.\n");
                    break;
                }
            }
        }
    }

    // 7. 清理资源
    printf("\nClosing timerfds...\n");
    close(tfd_one_shot);
    close(tfd_periodic);
    printf("Program finished.\n");

    return 0;
}

9. 编译和运行

# 假设代码保存在 timerfd_example.c 中
gcc -o timerfd_example timerfd_example.c

# 运行程序
./timerfd_example
# 程序会启动定时器,并在终端输出信息。
# 等待 3 秒后一次性定时器触发。
# 每 2 秒周期性定时器会触发。
# 输入 'quit' 并回车可以退出。

10. 预期输出

--- Demonstrating timerfd ---
PID: 12345
Created one-shot timerfd: 3
Created periodic timerfd: 4 (non-blocking)
Set one-shot timer to expire in 3 seconds.
Set periodic timer to start immediately and repeat every 2 seconds.
One-shot timer initial state: Next expiration in 2.999999000 seconds
     Interval: 0.000000000 seconds
Periodic timer initial state: Next expiration in 0.000000001 seconds
     Interval: 2.000000000 seconds

Entering main loop. Waiting for timers or input (type 'quit' to exit)...

[PERIODIC TIMER] Expired! Expirations counted: 1

[PERIODIC TIMER] Expired! Expirations counted: 1

[ONE-SHOT TIMER] Expired! Expirations counted: 1
One-shot timer final state: Timer is STOPPED

[PERIODIC TIMER] Expired! Expirations counted: 1
...
# (继续每2秒打印,直到输入 'quit')
Read from stdin: quit
Exiting due to 'quit' command.

Closing timerfds...
Program finished.

11. 总结

timerfd 提供了一种现代化、同步化、且易于与事件驱动模型集成的定时器机制。

  • 核心优势:将定时事件转换为文件描述符的可读事件,可以方便地融入 poll/select/epoll 等 I/O 多路复用框架。
  • 避免信号:解决了传统信号定时器的异步处理复杂性和竞态条件问题。
  • 灵活配置:通过 timerfd_settime 可以轻松创建一次性或周期性定时器,并支持相对和绝对时间。
  • 信息丰富read() 返回的到期次数 (uint64_t) 可以帮助处理定时器“堆积”(例如程序忙于处理其他任务导致多次到期)的情况。

掌握 timerfd 对于编写高性能、事件驱动的 Linux 应用程序(尤其是服务器)非常有帮助。

https://app-blog.csdn.net/csdn/aiChatNew

1. 函数介绍

2. 函数原型

3. 功能

4. 参数详解

timerfd_create(int clockid, int flags)

timerfd_gettime(int fd, struct itimerspec *curr_value)

timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value)

struct itimerspec 结构体

5. 如何使用定时器文件描述符

6. 错误码 (errno)

7. 相似函数或关联函数

8. 示例代码

9. 编译和运行

10. 预期输出

11. 总结

Markdown 9106 字数 374 行数 当前行 1, 当前列 85

HTML 8433 字数 295 段落

保存草稿 发布文章

发表在 linux文章 | 留下评论

times系统调用及示例

times 函数详解

1. 函数介绍

times 是POSIX标准函数,用于获取进程及其子进程的CPU时间统计信息。它返回自系统启动以来进程在用户态和内核态消耗的CPU时间,以及所有已终止子进程的CPU时间统计。这对于性能分析、资源监控和系统管理非常有用。

2. 函数原型

#include <sys/times.h>
clock_t times(struct tms *buf);

3. 功能

times 函数获取当前进程的CPU时间使用情况,包括用户态CPU时间、系统态CPU时间,以及所有已终止子进程的相应时间。这些信息对于进程性能分析和资源管理至关重要。

4. 参数

  • *struct tms buf: 指向tms结构体的指针,用于存储时间统计信息

5. 返回值

  • 成功: 返回自系统启动以来的滴答数(ticks)
  • 失败: 返回(clock_t)-1,并设置errno

6. 相似函数,或关联函数

  • clock: 获取进程CPU时间
  • getrusage: 获取资源使用情况
  • time/clock_gettime: 获取系统时间
  • wait/waitpid: 等待子进程并获取其资源使用情况

7. 示例代码

示例1:基础times使用

#include <sys/times.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>

/**
 * 显示CPU时间统计
 */
void show_cpu_times(const struct tms *tms_buf, clock_t ticks) {
    long clk_tck = sysconf(_SC_CLK_TCK);  // 获取每秒滴答数
    
    printf("CPU时间统计:\n");
    printf("  用户态时间: %jd 滴答 (%.3f 秒)\n", 
           (intmax_t)tms_buf->tms_utime, 
           (double)tms_buf->tms_utime / clk_tck);
    printf("  系统态时间: %jd 滴答 (%.3f 秒)\n", 
           (intmax_t)tms_buf->tms_stime, 
           (double)tms_buf->tms_stime / clk_tck);
    printf("  子进程用户态时间: %jd 滴答 (%.3f 秒)\n", 
           (intmax_t)tms_buf->tms_cutime, 
           (double)tms_buf->tms_cutime / clk_tck);
    printf("  子进程系统态时间: %jd 滴答 (%.3f 秒)\n", 
           (intmax_t)tms_buf->tms_cstime, 
           (double)tms_buf->tms_cstime / clk_tck);
    printf("  总滴答数: %jd\n", (intmax_t)ticks);
    printf("  系统滴答率: %ld 滴答/秒\n", clk_tck);
}

/**
 * 演示基础times使用方法
 */
int demo_times_basic() {
    struct tms tms_start, tms_end;
    clock_t start_ticks, end_ticks;
    long clk_tck;
    
    printf("=== 基础times使用示例 ===\n");
    
    // 获取系统滴答率
    clk_tck = sysconf(_SC_CLK_TCK);
    if (clk_tck == -1) {
        perror("获取系统滴答率失败");
        return -1;
    }
    
    printf("系统滴答率: %ld 滴答/秒\n", clk_tck);
    
    // 获取初始时间统计
    start_ticks = times(&tms_start);
    if (start_ticks == (clock_t)-1) {
        perror("获取初始时间统计失败");
        return -1;
    }
    
    printf("\n1. 初始时间统计:\n");
    show_cpu_times(&tms_start, start_ticks);
    
    // 执行一些CPU密集型操作
    printf("\n2. 执行CPU密集型操作...\n");
    
    volatile long sum = 0;
    for (long i = 0; i < 100000000; i++) {
        sum += i * i;
        if (i % 20000000 == 0) {
            printf("  进度: %ld%%\n", i / 1000000);
        }
    }
    
    printf("  计算结果: %ld\n", sum);
    
    // 获取结束时间统计
    end_ticks = times(&tms_end);
    if (end_ticks == (clock_t)-1) {
        perror("获取结束时间统计失败");
        return -1;
    }
    
    printf("\n3. 结束时间统计:\n");
    show_cpu_times(&tms_end, end_ticks);
    
    // 计算时间差
    printf("\n4. 时间差统计:\n");
    clock_t ticks_diff = end_ticks - start_ticks;
    clock_t utime_diff = tms_end.tms_utime - tms_start.tms_utime;
    clock_t stime_diff = tms_end.tms_stime - tms_start.tms_stime;
    
    printf("  消耗滴答数: %jd\n", (intmax_t)ticks_diff);
    printf("  用户态时间差: %jd 滴答 (%.3f 秒)\n", 
           (intmax_t)utime_diff, (double)utime_diff / clk_tck);
    printf("  系统态时间差: %jd 滴答 (%.3f 秒)\n", 
           (intmax_t)stime_diff, (double)stime_diff / clk_tck);
    printf("  总CPU时间: %.3f 秒\n", 
           (double)(utime_diff + stime_diff) / clk_tck);
    
    // 计算CPU使用率
    if (ticks_diff > 0) {
        double cpu_utilization = (double)(utime_diff + stime_diff) / ticks_diff * 100;
        printf("  CPU使用率: %.2f%%\n", cpu_utilization);
    }
    
    return 0;
}

int main() {
    return demo_times_basic();
}

示例2:父子进程CPU时间统计

#include <sys/times.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.h>

/**
 * 子进程工作函数
 */
void child_work(int child_id, int work_duration) {
    printf("子进程 %d (PID: %d) 启动\n", child_id, getpid());
    
    struct tms tms_start, tms_current;
    clock_t start_ticks, current_ticks;
    long clk_tck = sysconf(_SC_CLK_TCK);
    
    start_ticks = times(&tms_start);
    
    // 执行工作
    volatile long sum = 0;
    time_t start_time = time(NULL);
    
    while (difftime(time(NULL), start_time) < work_duration) {
        // CPU密集型工作
        for (int i = 0; i < 1000000; i++) {
            sum += i;
        }
        
        // 定期报告进度
        if (difftime(time(NULL), start_time) > 0 && 
            fmod(difftime(time(NULL), start_time), 1.0) < 0.1) {
            current_ticks = times(&tms_current);
            if (current_ticks != (clock_t)-1) {
                clock_t utime_diff = tms_current.tms_utime - tms_start.tms_utime;
                printf("  子进程 %d: 用户态时间 %.3f 秒\n", 
                       child_id, (double)utime_diff / clk_tck);
            }
        }
    }
    
    printf("子进程 %d 完成,计算结果: %ld\n", child_id, sum);
    exit(child_id);
}

/**
 * 演示父子进程CPU时间统计
 */
int demo_parent_child_times() {
    struct tms tms_before, tms_after;
    clock_t ticks_before, ticks_after;
    pid_t children[3];
    int child_count = 3;
    long clk_tck = sysconf(_SC_CLK_TCK);
    
    printf("=== 父子进程CPU时间统计演示 ===\n");
    printf("系统滴答率: %ld 滴答/秒\n", clk_tck);
    
    // 获取父进程初始时间统计
    ticks_before = times(&tms_before);
    if (ticks_before == (clock_t)-1) {
        perror("获取初始时间统计失败");
        return -1;
    }
    
    printf("\n1. 父进程初始时间统计:\n");
    printf("  父进程用户态时间: %.3f 秒\n", 
           (double)tms_before.tms_utime / clk_tck);
    printf("  父进程系统态时间: %.3f 秒\n", 
           (double)tms_before.tms_stime / clk_tck);
    printf("  子进程累计时间: %.3f 秒 (用户态) + %.3f 秒 (系统态)\n",
           (double)tms_before.tms_cutime / clk_tck,
           (double)tms_before.tms_cstime / clk_tck);
    
    // 创建子进程
    printf("\n2. 创建子进程:\n");
    for (int i = 0; i < child_count; i++) {
        children[i] = fork();
        if (children[i] == 0) {
            // 子进程
            child_work(i + 1, 3 + i);  // 不同持续时间
        } else if (children[i] > 0) {
            printf("  创建子进程 %d: PID=%d\n", i + 1, children[i]);
        } else {
            perror("创建子进程失败");
            // 清理已创建的子进程
            for (int j = 0; j < i; j++) {
                kill(children[j], SIGKILL);
            }
            return -1;
        }
    }
    
    // 父进程等待子进程完成
    printf("\n3. 父进程等待子进程完成:\n");
    int completed_children = 0;
    
    while (completed_children < child_count) {
        int status;
        pid_t finished_pid = wait(&status);
        if (finished_pid > 0) {
            completed_children++;
            printf("  子进程 %d (PID=%d) 已完成,退出状态: %d\n", 
                   WEXITSTATUS(status), finished_pid, WEXITSTATUS(status));
        } else if (finished_pid == -1) {
            if (errno != EINTR) {
                perror("等待子进程失败");
                break;
            }
        }
    }
    
    // 获取父进程结束时间统计
    ticks_after = times(&tms_after);
    if (ticks_after == (clock_t)-1) {
        perror("获取结束时间统计失败");
        return -1;
    }
    
    printf("\n4. 父进程结束时间统计:\n");
    printf("  父进程用户态时间: %.3f 秒\n", 
           (double)tms_after.tms_utime / clk_tck);
    printf("  父进程系统态时间: %.3f 秒\n", 
           (double)tms_after.tms_stime / clk_tck);
    printf("  子进程累计时间: %.3f 秒 (用户态) + %.3f 秒 (系统态)\n",
           (double)tms_after.tms_cutime / clk_tck,
           (double)tms_after.tms_cstime / clk_tck);
    
    // 计算差异
    printf("\n5. 父子进程时间差异分析:\n");
    clock_t parent_utime_diff = tms_after.tms_utime - tms_before.tms_utime;
    clock_t parent_stime_diff = tms_after.tms_stime - tms_before.tms_stime;
    clock_t children_utime_diff = tms_after.tms_cutime - tms_before.tms_cutime;
    clock_t children_stime_diff = tms_after.tms_cstime - tms_before.tms_cstime;
    
    printf("  父进程CPU时间: %.3f 秒 (用户态) + %.3f 秒 (系统态) = %.3f 秒\n",
           (double)parent_utime_diff / clk_tck,
           (double)parent_stime_diff / clk_tck,
           (double)(parent_utime_diff + parent_stime_diff) / clk_tck);
    
    printf("  子进程CPU时间: %.3f 秒 (用户态) + %.3f 秒 (系统态) = %.3f 秒\n",
           (double)children_utime_diff / clk_tck,
           (double)children_stime_diff / clk_tck,
           (double)(children_utime_diff + children_stime_diff) / clk_tck);
    
    printf("  总CPU时间: %.3f 秒\n",
           (double)(parent_utime_diff + parent_stime_diff + 
                   children_utime_diff + children_stime_diff) / clk_tck);
    
    // 总体统计
    clock_t total_ticks = ticks_after - ticks_before;
    if (total_ticks > 0) {
        double total_cpu_time = (double)(parent_utime_diff + parent_stime_diff + 
                                       children_utime_diff + children_stime_diff) / clk_tck;
        double wall_clock_time = (double)total_ticks / clk_tck;
        double cpu_utilization = total_cpu_time / wall_clock_time * 100;
        
        printf("\n6. 总体性能统计:\n");
        printf("  墙钟时间: %.3f 秒\n", wall_clock_time);
        printf("  CPU时间: %.3f 秒\n", total_cpu_time);
        printf("  CPU利用率: %.2f%%\n", cpu_utilization);
        printf("  并行效率: %.2f%%\n", cpu_utilization / child_count);
    }
    
    return 0;
}

int main() {
    return demo_parent_child_times();
}

示例3:性能分析工具

#include <sys/times.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.h>
#include <math.h>

/**
 * 性能分析结果结构
 */
typedef struct {
    clock_t start_ticks;
    clock_t end_ticks;
    struct tms start_tms;
    struct tms end_tms;
    double wall_time_seconds;
    double cpu_time_seconds;
    double user_time_seconds;
    double system_time_seconds;
    double children_user_time_seconds;
    double children_system_time_seconds;
    double cpu_utilization_percent;
} performance_analysis_t;

/**
 * 初始化性能分析
 */
int init_performance_analysis(performance_analysis_t *analysis) {
    analysis->start_ticks = times(&analysis->start_tms);
    if (analysis->start_ticks == (clock_t)-1) {
        perror("初始化性能分析失败");
        return -1;
    }
    
    return 0;
}

/**
 * 完成性能分析
 */
int finish_performance_analysis(performance_analysis_t *analysis) {
    long clk_tck = sysconf(_SC_CLK_TCK);
    
    analysis->end_ticks = times(&analysis->end_tms);
    if (analysis->end_ticks == (clock_t)-1) {
        perror("完成性能分析失败");
        return -1;
    }
    
    // 计算各种时间统计
    clock_t ticks_diff = analysis->end_ticks - analysis->start_ticks;
    clock_t utime_diff = analysis->end_tms.tms_utime - analysis->start_tms.tms_utime;
    clock_t stime_diff = analysis->end_tms.tms_stime - analysis->start_tms.tms_stime;
    clock_t cutime_diff = analysis->end_tms.tms_cutime - analysis->start_tms.tms_cutime;
    clock_t cstime_diff = analysis->end_tms.tms_cstime - analysis->start_tms.tms_cstime;
    
    analysis->wall_time_seconds = (double)ticks_diff / clk_tck;
    analysis->user_time_seconds = (double)utime_diff / clk_tck;
    analysis->system_time_seconds = (double)stime_diff / clk_tck;
    analysis->children_user_time_seconds = (double)cutime_diff / clk_tck;
    analysis->children_system_time_seconds = (double)cstime_diff / clk_tck;
    analysis->cpu_time_seconds = analysis->user_time_seconds + analysis->system_time_seconds +
                                 analysis->children_user_time_seconds + analysis->children_system_time_seconds;
    
    if (ticks_diff > 0) {
        analysis->cpu_utilization_percent = (analysis->cpu_time_seconds / 
                                           analysis->wall_time_seconds) * 100;
    } else {
        analysis->cpu_utilization_percent = 0.0;
    }
    
    return 0;
}

/**
 * 显示性能分析结果
 */
void show_performance_analysis(const performance_analysis_t *analysis) {
    printf("=== 性能分析报告 ===\n");
    printf("时间统计:\n");
    printf("  墙钟时间: %.3f 秒\n", analysis->wall_time_seconds);
    printf("  用户态时间: %.3f 秒\n", analysis->user_time_seconds);
    printf("  系统态时间: %.3f 秒\n", analysis->system_time_seconds);
    printf("  子进程用户态时间: %.3f 秒\n", analysis->children_user_time_seconds);
    printf("  子进程系统态时间: %.3f 秒\n", analysis->children_system_time_seconds);
    printf("  总CPU时间: %.3f 秒\n", analysis->cpu_time_seconds);
    printf("  CPU利用率: %.2f%%\n", analysis->cpu_utilization_percent);
    
    // 详细分解
    printf("\n详细分解:\n");
    if (analysis->wall_time_seconds > 0) {
        printf("  用户态占比: %.1f%%\n", 
               (analysis->user_time_seconds / analysis->wall_time_seconds) * 100);
        printf("  系统态占比: %.1f%%\n", 
               (analysis->system_time_seconds / analysis->wall_time_seconds) * 100);
        printf("  子进程用户态占比: %.1f%%\n", 
               (analysis->children_user_time_seconds / analysis->wall_time_seconds) * 100);
        printf("  子进程系统态占比: %.1f%%\n", 
               (analysis->children_system_time_seconds / analysis->wall_time_seconds) * 100);
    }
}

/**
 * CPU密集型测试函数
 */
void cpu_intensive_test(const char *test_name, int iterations) {
    printf("执行CPU密集型测试: %s (%d 次迭代)\n", test_name, iterations);
    
    volatile double result = 0.0;
    for (int i = 0; i < iterations; i++) {
        // 执行数学计算
        for (int j = 1; j <= 1000; j++) {
            result += sin(j * 0.001) * cos(j * 0.001);
        }
        
        // 定期显示进度
        if (i > 0 && i % (iterations / 10) == 0) {
            printf("  %s 进度: %d%%\n", test_name, (i * 100) / iterations);
        }
    }
    
    printf("  %s 完成,结果: %.6f\n", test_name, result);
}

/**
 * I/O密集型测试函数
 */
void io_intensive_test(const char *test_name, int file_count) {
    printf("执行I/O密集型测试: %s (%d 个文件)\n", test_name, file_count);
    
    for (int i = 0; i < file_count; i++) {
        char filename[64];
        snprintf(filename, sizeof(filename), "/tmp/io_test_%s_%d.tmp", test_name, i);
        
        // 创建并写入文件
        FILE *fp = fopen(filename, "w");
        if (fp) {
            for (int j = 0; j < 1000; j++) {
                fprintf(fp, "测试数据行 %d.%d\n", i, j);
            }
            fclose(fp);
        }
        
        // 读取文件
        fp = fopen(filename, "r");
        if (fp) {
            char buffer[256];
            while (fgets(buffer, sizeof(buffer), fp)) {
                // 简单处理读取的数据
                volatile int dummy = strlen(buffer);
            }
            fclose(fp);
        }
        
        // 删除临时文件
        unlink(filename);
        
        if (i > 0 && i % (file_count / 10) == 0) {
            printf("  %s 进度: %d%%\n", test_name, (i * 100) / file_count);
        }
    }
    
    printf("  %s 完成\n", test_name);
}

/**
 * 演示性能分析工具
 */
int demo_performance_analyzer() {
    performance_analysis_t analysis;
    long clk_tck = sysconf(_SC_CLK_TCK);
    
    printf("=== 性能分析工具演示 ===\n");
    printf("系统滴答率: %ld 滴答/秒\n", clk_tck);
    
    // 初始化性能分析
    if (init_performance_analysis(&analysis) != 0) {
        return -1;
    }
    
    printf("\n开始性能测试...\n");
    
    // 测试1: CPU密集型操作
    printf("\n1. CPU密集型测试:\n");
    cpu_intensive_test("CPU测试1", 5000);
    
    // 测试2: I/O密集型操作
    printf("\n2. I/O密集型测试:\n");
    io_intensive_test("I/O测试1", 50);
    
    // 测试3: 混合操作
    printf("\n3. 混合操作测试:\n");
    for (int i = 0; i < 5; i++) {
        cpu_intensive_test("混合CPU测试", 1000);
        io_intensive_test("混合I/O测试", 10);
    }
    
    // 完成性能分析
    if (finish_performance_analysis(&analysis) != 0) {
        return -1;
    }
    
    // 显示分析结果
    printf("\n");
    show_performance_analysis(&analysis);
    
    // 详细性能建议
    printf("\n=== 性能优化建议 ===\n");
    
    if (analysis.cpu_utilization_percent > 80) {
        printf("📌 CPU使用率很高 (%.1f%%),可能存在CPU瓶颈\n", 
               analysis.cpu_utilization_percent);
        printf("   建议:\n");
        printf("   - 考虑算法优化\n");
        printf("   - 检查是否存在无限循环\n");
        printf("   - 考虑并行处理\n");
    } else if (analysis.cpu_utilization_percent > 50) {
        printf("ℹ CPU使用率中等 (%.1f%%)\n", analysis.cpu_utilization_percent);
        printf("   建议:\n");
        printf("   - 监控CPU使用趋势\n");
        printf("   - 优化热点代码\n");
    } else {
        printf("✓ CPU使用率正常 (%.1f%%)\n", analysis.cpu_utilization_percent);
    }
    
    // I/O性能分析
    double io_ratio = (analysis.children_user_time_seconds + 
                      analysis.children_system_time_seconds) / 
                     analysis.wall_time_seconds;
    if (io_ratio > 0.3) {
        printf("\n📌 I/O操作占比较高 (%.1f%%)\n", io_ratio * 100);
        printf("   建议:\n");
        printf("   - 考虑异步I/O操作\n");
        printf("   - 优化文件访问模式\n");
        printf("   - 使用缓冲减少I/O次数\n");
    }
    
    // 并行效率分析
    if (analysis.children_user_time_seconds + analysis.children_system_time_seconds > 0) {
        printf("\n📊 子进程性能分析:\n");
        printf("   子进程总CPU时间: %.3f 秒\n", 
               analysis.children_user_time_seconds + analysis.children_system_time_seconds);
        printf("   平均每个子进程CPU时间: %.3f 秒\n",
               (analysis.children_user_time_seconds + analysis.children_system_time_seconds) / 2);
    }
    
    return 0;
}

int main() {
    return demo_performance_analyzer();
}

示例4:实时CPU监控

#include <sys/times.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.h>
#include <signal.h>

/**
 * CPU监控数据结构
 */
typedef struct {
    time_t timestamp;
    clock_t ticks;
    struct tms tms_data;
    double cpu_usage_percent;
    double user_cpu_percent;
    double system_cpu_percent;
    double children_cpu_percent;
} cpu_monitor_data_t;

/**
 * CPU监控器结构
 */
typedef struct {
    cpu_monitor_data_t history[100];  // 历史数据
    int history_count;
    int max_history;
    long clk_tck;
    volatile int monitoring;
    pid_t target_pid;  // 监控特定进程(0表示当前进程)
} cpu_monitor_t;

/**
 * 初始化CPU监控器
 */
int init_cpu_monitor(cpu_monitor_t *monitor, pid_t target_pid) {
    memset(monitor, 0, sizeof(cpu_monitor_t));
    monitor->max_history = 100;
    monitor->clk_tck = sysconf(_SC_CLK_TCK);
    monitor->target_pid = target_pid;
    monitor->monitoring = 1;
    
    if (monitor->clk_tck == -1) {
        perror("获取系统滴答率失败");
        return -1;
    }
    
    printf("CPU监控器初始化完成\n");
    printf("  监控目标: %s\n", target_pid ? "特定进程" : "当前进程");
    printf("  系统滴答率: %ld 滴答/秒\n", monitor->clk_tck);
    
    return 0;
}

/**
 * 收集CPU使用数据
 */
int collect_cpu_data(cpu_monitor_t *monitor) {
    if (monitor->history_count >= monitor->max_history) {
        // 循环覆盖旧数据
        memmove(&monitor->history[0], &monitor->history[1], 
                sizeof(cpu_monitor_data_t) * (monitor->max_history - 1));
        monitor->history_count = monitor->max_history - 1;
    }
    
    cpu_monitor_data_t *current = &monitor->history[monitor->history_count];
    
    current->timestamp = time(NULL);
    current->ticks = times(&current->tms_data);
    
    if (current->ticks == (clock_t)-1) {
        perror("获取CPU时间失败");
        return -1;
    }
    
    // 计算CPU使用率(与前一个采样点比较)
    if (monitor->history_count > 0) {
        cpu_monitor_data_t *previous = &monitor->history[monitor->history_count - 1];
        clock_t ticks_diff = current->ticks - previous->ticks;
        
        if (ticks_diff > 0) {
            clock_t utime_diff = current->tms_data.tms_utime - previous->tms_data.tms_utime;
            clock_t stime_diff = current->tms_data.tms_stime - previous->tms_data.tms_stime;
            clock_t cutime_diff = current->tms_data.tms_cutime - previous->tms_data.tms_cutime;
            clock_t cstime_diff = current->tms_data.tms_cstime - previous->tms_data.tms_cstime;
            
            current->user_cpu_percent = (double)utime_diff / ticks_diff * 100;
            current->system_cpu_percent = (double)stime_diff / ticks_diff * 100;
            current->children_cpu_percent = (double)(cutime_diff + cstime_diff) / ticks_diff * 100;
            current->cpu_usage_percent = current->user_cpu_percent + 
                                        current->system_cpu_percent + 
                                        current->children_cpu_percent;
        } else {
            current->cpu_usage_percent = 0.0;
            current->user_cpu_percent = 0.0;
            current->system_cpu_percent = 0.0;
            current->children_cpu_percent = 0.0;
        }
    } else {
        // 第一次采样,无法计算使用率
        current->cpu_usage_percent = 0.0;
        current->user_cpu_percent = 0.0;
        current->system_cpu_percent = 0.0;
        current->children_cpu_percent = 0.0;
    }
    
    monitor->history_count++;
    return 0;
}

/**
 * 显示CPU监控数据
 */
void show_cpu_monitor_data(const cpu_monitor_t *monitor) {
    if (monitor->history_count == 0) {
        printf("暂无监控数据\n");
        return;
    }
    
    const cpu_monitor_data_t *latest = &monitor->history[monitor->history_count - 1];
    
    printf("=== CPU监控数据 ===\n");
    printf("采样时间: %s", ctime(&latest->timestamp));
    printf("CPU使用率: %.2f%%\n", latest->cpu_usage_percent);
    printf("  用户态: %.2f%%\n", latest->user_cpu_percent);
    printf("  系统态: %.2f%%\n", latest->system_cpu_percent);
    printf("  子进程: %.2f%%\n", latest->children_cpu_percent);
    
    // 显示详细时间信息
    printf("详细时间信息:\n");
    printf("  用户态时间: %.3f 秒\n", 
           (double)latest->tms_data.tms_utime / monitor->clk_tck);
    printf("  系统态时间: %.3f 秒\n", 
           (double)latest->tms_data.tms_stime / monitor->clk_tck);
    printf("  子进程用户态时间: %.3f 秒\n", 
           (double)latest->tms_data.tms_cutime / monitor->clk_tck);
    printf("  子进程系统态时间: %.3f 秒\n", 
           (double)latest->tms_data.tms_cstime / monitor->clk_tck);
}

/**
 * 显示历史趋势
 */
void show_cpu_trend(const cpu_monitor_t *monitor) {
    if (monitor->history_count < 2) {
        printf("数据不足,无法显示趋势\n");
        return;
    }
    
    printf("=== CPU使用率趋势 ===\n");
    printf("%-20s %-8s %-8s %-8s %-8s\n", 
           "时间", "总CPU%", "用户%", "系统%", "子进程%");
    printf("%-20s %-8s %-8s %-8s %-8s\n", 
           "----", "------", "----", "----", "-----");
    
    // 显示最近10个采样点
    int start_index = (monitor->history_count > 10) ? 
                     monitor->history_count - 10 : 0;
    
    for (int i = start_index; i < monitor->history_count; i++) {
        const cpu_monitor_data_t *data = &monitor->history[i];
        char time_str[20];
        strftime(time_str, sizeof(time_str), "%H:%M:%S", localtime(&data->timestamp));
        
        printf("%-20s %-8.1f %-8.1f %-8.1f %-8.1f\n",
               time_str,
               data->cpu_usage_percent,
               data->user_cpu_percent,
               data->system_cpu_percent,
               data->children_cpu_percent);
    }
}

/**
 * 模拟被监控的工作进程
 */
void work_process(int work_id) {
    printf("工作进程 %d (PID: %d) 启动\n", work_id, getpid());
    
    // 执行不同类型的工作
    for (int cycle = 0; cycle < 5; cycle++) {
        printf("工作进程 %d: 执行周期 %d\n", work_id, cycle + 1);
        
        // CPU密集型工作
        volatile long sum = 0;
        for (long i = 0; i < 50000000; i++) {
            sum += i;
        }
        printf("  CPU工作完成,结果: %ld\n", sum);
        
        // I/O工作
        char filename[64];
        snprintf(filename, sizeof(filename), "/tmp/work_%d_cycle_%d.tmp", work_id, cycle);
        FILE *fp = fopen(filename, "w");
        if (fp) {
            for (int i = 0; i < 10000; i++) {
                fprintf(fp, "工作数据 %d.%d\n", cycle, i);
            }
            fclose(fp);
            unlink(filename);
        }
        
        sleep(2);  // 休息一下
    }
    
    printf("工作进程 %d 完成\n", work_id);
    exit(work_id);
}

/**
 * 演示实时CPU监控
 */
int demo_real_time_cpu_monitoring() {
    cpu_monitor_t monitor;
    pid_t worker_pids[2];
    int worker_count = 2;
    
    printf("=== 实时CPU监控演示 ===\n");
    
    // 初始化监控器
    if (init_cpu_monitor(&monitor, 0) != 0) {
        return -1;
    }
    
    // 创建工作进程
    printf("创建 %d 个工作进程:\n", worker_count);
    for (int i = 0; i < worker_count; i++) {
        worker_pids[i] = fork();
        if (worker_pids[i] == 0) {
            work_process(i + 1);
        } else if (worker_pids[i] > 0) {
            printf("  工作进程 %d: PID=%d\n", i + 1, worker_pids[i]);
        } else {
            perror("创建工作进程失败");
            for (int j = 0; j < i; j++) {
                kill(worker_pids[j], SIGKILL);
            }
            return -1;
        }
    }
    
    // 开始监控
    printf("\n开始实时监控 (30秒):\n");
    time_t start_time = time(NULL);
    
    while (difftime(time(NULL), start_time) < 30) {
        // 收集CPU数据
        if (collect_cpu_data(&monitor) != 0) {
            printf("收集CPU数据失败\n");
            break;
        }
        
        // 每5秒显示一次详细信息
        if (((int)difftime(time(NULL), start_time)) % 5 == 0) {
            show_cpu_monitor_data(&monitor);
            
            // 每15秒显示一次趋势
            if (((int)difftime(time(NULL), start_time)) % 15 == 0) {
                show_cpu_trend(&monitor);
            }
            
            printf("---\n");
        }
        
        // 短暂休眠
        usleep(500000);  // 500ms
    }
    
    // 等待工作进程完成
    printf("等待工作进程完成:\n");
    for (int i = 0; i < worker_count; i++) {
        int status;
        pid_t finished_pid = waitpid(worker_pids[i], &status, 0);
        if (finished_pid > 0) {
            printf("  工作进程 %d (PID=%d) 已完成,退出状态: %d\n", 
                   WEXITSTATUS(status), finished_pid, WEXITSTATUS(status));
        }
    }
    
    // 显示最终监控结果
    printf("\n=== 最终监控结果 ===\n");
    
    // 收集最终数据
    collect_cpu_data(&monitor);
    show_cpu_monitor_data(&monitor);
    
    // 显示完整趋势
    printf("\n完整CPU使用率趋势:\n");
    show_cpu_trend(&monitor);
    
    // 统计分析
    if (monitor.history_count > 1) {
        double max_cpu = 0, min_cpu = 100, avg_cpu = 0;
        double total_cpu = 0;
        int valid_samples = 0;
        
        for (int i = 1; i < monitor.history_count; i++) {
            double cpu_usage = monitor.history[i].cpu_usage_percent;
            if (cpu_usage >= 0) {  // 有效数据
                if (cpu_usage > max_cpu) max_cpu = cpu_usage;
                if (cpu_usage < min_cpu) min_cpu = cpu_usage;
                total_cpu += cpu_usage;
                valid_samples++;
            }
        }
        
        if (valid_samples > 0) {
            avg_cpu = total_cpu / valid_samples;
            
            printf("\n=== 统计分析 ===\n");
            printf("CPU使用率统计:\n");
            printf("  最高使用率: %.2f%%\n", max_cpu);
            printf("  最低使用率: %.2f%%\n", min_cpu);
            printf("  平均使用率: %.2f%%\n", avg_cpu);
            
            if (avg_cpu > 80) {
                printf("  🚨 警告: 平均CPU使用率过高\n");
            } else if (avg_cpu > 60) {
                printf("  ⚠ 提醒: CPU使用率较高\n");
            } else {
                printf("  ✓ CPU使用率正常\n");
            }
        }
    }
    
    return 0;
}

int main() {
    return demo_real_time_cpu_monitoring();
}

示例5:进程资源使用统计

#include <sys/times.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/resource.h>

/**
 * 进程资源使用统计结构
 */
typedef struct {
    pid_t pid;
    char process_name[256];
    struct tms start_tms;
    struct tms end_tms;
    clock_t start_ticks;
    clock_t end_ticks;
    time_t start_time;
    time_t end_time;
    
    // CPU时间统计
    double user_time_seconds;
    double system_time_seconds;
    double children_user_time_seconds;
    double children_system_time_seconds;
    double total_cpu_time_seconds;
    double wall_clock_time_seconds;
    double cpu_utilization_percent;
    
    // 系统资源统计
    long max_rss_kb;      // 最大驻留集大小
    long page_faults;     // 页面错误次数
    long voluntary_ctxt_switches;   // 自愿上下文切换
    long nonvoluntary_ctxt_switches; // 非自愿上下文切换
} process_resource_stats_t;

/**
 * 初始化进程资源统计
 */
int init_process_resource_stats(process_resource_stats_t *stats, pid_t target_pid) {
    memset(stats, 0, sizeof(process_resource_stats_t));
    
    stats->pid = target_pid ? target_pid : getpid();
    stats->start_time = time(NULL);
    stats->start_ticks = times(&stats->start_tms);
    
    if (stats->start_ticks == (clock_t)-1) {
        perror("初始化进程资源统计失败");
        return -1;
    }
    
    // 获取进程名称
    char comm_path[256];
    snprintf(comm_path, sizeof(comm_path), "/proc/%d/comm", stats->pid);
    
    FILE *fp = fopen(comm_path, "r");
    if (fp) {
        if (fgets(stats->process_name, sizeof(stats->process_name), fp)) {
            // 移除换行符
            char *newline = strchr(stats->process_name, '\n');
            if (newline) *newline = '\0';
        }
        fclose(fp);
    } else {
        snprintf(stats->process_name, sizeof(stats->process_name), "process_%d", stats->pid);
    }
    
    printf("进程资源统计初始化:\n");
    printf("  进程ID: %d\n", stats->pid);
    printf("  进程名称: %s\n", stats->process_name);
    printf("  启动时间: %s", ctime(&stats->start_time));
    
    return 0;
}

/**
 * 完成进程资源统计
 */
int finish_process_resource_stats(process_resource_stats_t *stats) {
    long clk_tck = sysconf(_SC_CLK_TCK);
    
    stats->end_time = time(NULL);
    stats->end_ticks = times(&stats->end_tms);
    
    if (stats->end_ticks == (clock_t)-1) {
        perror("完成进程资源统计失败");
        return -1;
    }
    
    // 计算CPU时间
    clock_t utime_diff = stats->end_tms.tms_utime - stats->start_tms.tms_utime;
    clock_t stime_diff = stats->end_tms.tms_stime - stats->start_tms.tms_stime;
    clock_t cutime_diff = stats->end_tms.tms_cutime - stats->start_tms.tms_cutime;
    clock_t cstime_diff = stats->end_tms.tms_cstime - stats->start_tms.tms_cstime;
    
    stats->user_time_seconds = (double)utime_diff / clk_tck;
    stats->system_time_seconds = (double)stime_diff / clk_tck;
    stats->children_user_time_seconds = (double)cutime_diff / clk_tck;
    stats->children_system_time_seconds = (double)cstime_diff / clk_tck;
    stats->total_cpu_time_seconds = stats->user_time_seconds + 
                                   stats->system_time_seconds +
                                   stats->children_user_time_seconds + 
                                   stats->children_system_time_seconds;
    stats->wall_clock_time_seconds = (double)(stats->end_ticks - stats->start_ticks) / clk_tck;
    
    if (stats->wall_clock_time_seconds > 0) {
        stats->cpu_utilization_percent = (stats->total_cpu_time_seconds / 
                                         stats->wall_clock_time_seconds) * 100;
    }
    
    // 获取系统资源使用情况
    struct rusage usage;
    if (getrusage(RUSAGE_SELF, &usage) == 0) {
        stats->max_rss_kb = usage.ru_maxrss;  // 在Linux上以KB为单位
        stats->page_faults = usage.ru_majflt;
        stats->voluntary_ctxt_switches = usage.ru_nvcsw;
        stats->nonvoluntary_ctxt_switches = usage.ru_nivcsw;
    }
    
    return 0;
}

/**
 * 显示进程资源统计
 */
void show_process_resource_stats(const process_resource_stats_t *stats) {
    printf("=== 进程资源使用统计 ===\n");
    printf("进程信息:\n");
    printf("  进程ID: %d\n", stats->pid);
    printf("  进程名称: %s\n", stats->process_name);
    printf("  运行时间: %s 到 %s", 
           ctime(&stats->start_time), ctime(&stats->end_time));
    
    printf("\nCPU时间统计:\n");
    printf("  用户态时间: %.3f 秒\n", stats->user_time_seconds);
    printf("  系统态时间: %.3f 秒\n", stats->system_time_seconds);
    printf("  子进程用户态时间: %.3f 秒\n", stats->children_user_time_seconds);
    printf("  子进程系统态时间: %.3f 秒\n", stats->children_system_time_seconds);
    printf("  总CPU时间: %.3f 秒\n", stats->total_cpu_time_seconds);
    printf("  墙钟时间: %.3f 秒\n", stats->wall_clock_time_seconds);
    printf("  CPU利用率: %.2f%%\n", stats->cpu_utilization_percent);
    
    printf("\n系统资源统计:\n");
    printf("  最大内存使用: %ld KB (%.2f MB)\n", 
           stats->max_rss_kb, stats->max_rss_kb / 1024.0);
    printf("  主要页面错误: %ld\n", stats->page_faults);
    printf("  自愿上下文切换: %ld\n", stats->voluntary_ctxt_switches);
    printf("  非自愿上下文切换: %ld\n", stats->nonvoluntary_ctxt_switches);
    printf("  总上下文切换: %ld\n", stats->voluntary_ctxt_switches + 
           stats->nonvoluntary_ctxt_switches);
}

/**
 * 模拟不同类型的工作负载
 */
void simulate_workload(int workload_type, int intensity) {
    switch (workload_type) {
        case 1:  // CPU密集型
            printf("执行CPU密集型工作 (强度: %d)\n", intensity);
            volatile long sum = 0;
            for (long i = 0; i < intensity * 10000000L; i++) {
                sum += i * i;
            }
            printf("  CPU工作完成,结果: %ld\n", sum);
            break;
            
        case 2:  // I/O密集型
            printf("执行I/O密集型工作 (强度: %d)\n", intensity);
            for (int i = 0; i < intensity * 100; i++) {
                char filename[64];
                snprintf(filename, sizeof(filename), "/tmp/io_work_%d_%d.tmp", getpid(), i);
                
                FILE *fp = fopen(filename, "w");
                if (fp) {
                    for (int j = 0; j < 1000; j++) {
                        fprintf(fp, "测试数据 %d.%d\n", i, j);
                    }
                    fclose(fp);
                    unlink(filename);
                }
            }
            printf("  I/O工作完成\n");
            break;
            
        case 3:  // 内存密集型
            printf("执行内存密集型工作 (强度: %d)\n", intensity);
            size_t alloc_size = intensity * 1024 * 1024;  // MB
            char *buffer = malloc(alloc_size);
            if (buffer) {
                // 填充内存
                memset(buffer, 0xAA, alloc_size);
                // 访问内存
                volatile long checksum = 0;
                for (size_t i = 0; i < alloc_size; i += 1024) {
                    checksum += buffer[i];
                }
                printf("  内存工作完成,校验和: %ld\n", checksum);
                free(buffer);
            } else {
                printf("  内存分配失败\n");
            }
            break;
            
        default:
            printf("未知工作负载类型: %d\n", workload_type);
            break;
    }
}

/**
 * 演示进程资源使用统计
 */
int demo_process_resource_statistics() {
    process_resource_stats_t stats;
    long clk_tck = sysconf(_SC_CLK_TCK);
    
    printf("=== 进程资源使用统计演示 ===\n");
    printf("系统滴答率: %ld 滴答/秒\n", clk_tck);
    
    // 初始化统计
    if (init_process_resource_stats(&stats, 0) != 0) {
        return -1;
    }
    
    printf("\n开始执行不同类型的工作负载:\n");
    
    // 工作负载1: CPU密集型
    printf("\n1. CPU密集型工作:\n");
    simulate_workload(1, 5);
    
    // 工作负载2: I/O密集型
    printf("\n2. I/O密集型工作:\n");
    simulate_workload(2, 3);
    
    // 工作负载3: 内存密集型
    printf("\n3. 内存密集型工作:\n");
    simulate_workload(3, 100);
    
    // 混合工作负载
    printf("\n4. 混合工作负载:\n");
    for (int i = 0; i < 3; i++) {
        simulate_workload(1, 2);  // 轻量CPU工作
        simulate_workload(2, 1);   // 轻量I/O工作
        sleep(1);
    }
    
    // 完成统计
    if (finish_process_resource_stats(&stats) != 0) {
        return -1;
    }
    
    // 显示统计结果
    printf("\n");
    show_process_resource_stats(&stats);
    
    // 详细分析
    printf("\n=== 详细分析 ===\n");
    
    // CPU使用分析
    printf("CPU使用分析:\n");
    if (stats.cpu_utilization_percent > 80) {
        printf("  🚨 CPU使用率极高 (%.1f%%)\n", stats.cpu_utilization_percent);
        printf("     建议检查是否存在无限循环或算法效率问题\n");
    } else if (stats.cpu_utilization_percent > 50) {
        printf("  ⚠ CPU使用率较高 (%.1f%%)\n", stats.cpu_utilization_percent);
        printf("     建议优化热点代码\n");
    } else {
        printf("  ✓ CPU使用率正常 (%.1f%%)\n", stats.cpu_utilization_percent);
    }
    
    // 内存使用分析
    printf("\n内存使用分析:\n");
    if (stats.max_rss_kb > 1024 * 1024) {  // 超过1GB
        printf("  🚨 内存使用量巨大: %.2f GB\n", stats.max_rss_kb / (1024.0 * 1024.0));
        printf("     建议检查是否存在内存泄漏\n");
    } else if (stats.max_rss_kb > 100 * 1024) {  // 超过100MB
        printf("  ℹ 内存使用量较大: %.2f MB\n", stats.max_rss_kb / 1024.0);
        printf("     建议监控内存增长趋势\n");
    } else {
        printf("  ✓ 内存使用量正常: %.2f MB\n", stats.max_rss_kb / 1024.0);
    }
    
    // I/O效率分析
    printf("\nI/O效率分析:\n");
    double io_efficiency = (double)stats.voluntary_ctxt_switches / 
                          (stats.voluntary_ctxt_switches + stats.nonvoluntary_ctxt_switches + 1);
    if (io_efficiency > 0.8) {
        printf("  ✓ I/O效率良好 (%.1f%% 自愿切换)\n", io_efficiency * 100);
        printf("     表明程序很好地配合了I/O操作\n");
    } else {
        printf("  ℹ I/O效率一般 (%.1f%% 自愿切换)\n", io_efficiency * 100);
        printf("     可以考虑优化阻塞I/O操作\n");
    }
    
    // 性能建议
    printf("\n=== 性能优化建议 ===\n");
    printf("1. CPU优化:\n");
    printf("   - 分析CPU密集型代码段\n");
    printf("   - 考虑并行处理或算法优化\n");
    printf("   - 使用性能分析工具定位热点\n");
    
    printf("\n2. 内存优化:\n");
    printf("   - 监控内存使用峰值\n");
    printf("   - 及时释放不用的内存\n");
    printf("   - 考虑内存池或对象复用\n");
    
    printf("\n3. I/O优化:\n");
    printf("   - 使用缓冲减少I/O次数\n");
    printf("   - 考虑异步I/O操作\n");
    printf("   - 优化文件访问模式\n");
    
    return 0;
}

int main() {
    return demo_process_resource_statistics();
}

times 使用注意事项

系统要求:

  1. POSIX兼容: 支持POSIX标准的系统
  2. 权限要求: 通常不需要特殊权限
  3. 架构支持: 支持所有主流架构

精度考虑:

  1. 滴答精度: 受系统滴答率限制(通常100Hz)
  2. 累积误差: 长时间监控可能累积误差
  3. 采样频率: 高频采样可能影响被监控进程

错误处理:

  1. 返回值检查: 必须检查返回值和errno
  2. 系统资源: 可能在资源不足时失败
  3. 进程状态: 目标进程终止时的行为

性能考虑:

  1. 系统调用开销: 频繁调用有性能开销
  2. 内存使用: 历史数据存储需要内存
  3. 监控开销: 监控本身会消耗少量CPU资源

安全考虑:

  1. 权限检查: 监控其他进程需要适当权限
  2. 资源限制: 避免过度消耗系统资源
  3. 数据保护: 监控数据的隐私和安全

最佳实践:

  1. 合理采样: 选择适当的采样间隔
  2. 错误处理: 妥善处理各种错误情况
  3. 资源管理: 及时清理监控资源
  4. 数据持久化: 重要监控数据应持久化存储
  5. 报警机制: 设置合理的报警阈值

times函数特点

优点:

  1. 标准兼容: POSIX标准函数,广泛支持
  2. 信息全面: 提供完整的CPU时间统计
  3. 性能良好: 系统调用开销小
  4. 易于使用: API简单直观

限制:

  1. 精度限制: 受系统滴答率限制
  2. 实时性: 不是实时监控的最佳选择
  3. 跨进程: 监控其他进程需要权限
  4. 历史数据: 只能获取累积统计,不能获取瞬时值

相关函数对比

times vs clock:

// times(): 获取进程CPU时间统计
struct tms tms_buf;
clock_t ticks = times(&tms_buf);

// clock(): 获取进程CPU时间
clock_t cpu_time = clock();

times vs getrusage:

// times(): 基础CPU时间统计
struct tms tms_buf;
times(&tms_buf);

// getrusage(): 详细的资源使用情况
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);

常见使用场景

1. 性能分析:

// 分析程序CPU使用情况
struct tms start_tms, end_tms;
clock_t start_ticks = times(&start_tms);
// 执行程序
clock_t end_ticks = times(&end_tms);
// 计算CPU时间差

2. 资源监控:

// 监控进程资源使用
while (monitoring) {
    struct tms current_tms;
    clock_t current_ticks = times(&current_tms);
    // 分析CPU使用率
    sleep(1);
}

3. 系统管理:

// 系统负载监控
struct tms system_tms;
clock_t system_ticks = times(&system_tms);
// 分析系统整体性能

总结

times 函数是Linux系统中重要的进程资源监控工具,提供了:

  1. 全面的CPU时间统计: 包括用户态、系统态和子进程时间
  2. 标准兼容性: 符合POSIX标准,广泛支持
  3. 简单易用: API设计直观,易于集成
  4. 性能监控: 适用于各种性能分析场景

通过合理使用 times 函数,可以构建功能强大的性能监控和分析工具。在实际应用中,需要注意精度限制、错误处理和性能影响等问题,选择合适的监控策略和采样频率。

https://app-blog.csdn.net/csdn/aiChatNew

times 函数详解

1. 函数介绍

2. 函数原型

3. 功能

4. 参数

5. 返回值

6. 相似函数,或关联函数

7. 示例代码

示例1:基础times使用

示例2:父子进程CPU时间统计

示例3:性能分析工具

示例4:实时CPU监控

示例5:进程资源使用统计

times 使用注意事项

系统要求:

精度考虑:

错误处理:

性能考虑:

安全考虑:

最佳实践:

times函数特点

优点:

限制:

相关函数对比

times vs clock:

times vs getrusage:

常见使用场景

1. 性能分析:

2. 资源监控:

3. 系统管理:

总结

Markdown 27496 字数 1357 行数 当前行 1, 当前列 0

HTML 27105 字数 1120 段落

保存草稿 发布文章

发表在 linux文章 | 留下评论

tkill系统调用及示例

我们来深入学习 tkill 系统调用

1. 函数介绍

在 Linux 系统中,信号(Signal)是一种进程间通信(IPC)机制,允许一个进程(或内核)向另一个进程发送简短的异步通知。例如,当你在终端按下 Ctrl+C 时,系统会向当前前台进程发送 SIGINT 信号。

发送信号最常用的方法是 kill() 系统调用。kill(pid_t pid, int sig) 可以向指定的进程 ID (PID) 发送信号。

然而,在 Linux(特别是引入了线程之后),情况变得稍微复杂了一些。一个进程 (Process) 可以包含多个线程 (Threads)。这些线程共享同一个 PID,但每个线程都有自己的唯一线程 ID (TID)。在 Linux 内核的实现中,每个线程实际上都被视为一个独立的“任务”(task)。

这就引出了一个问题:如果我想向一个特定的线程发送信号,而不是整个进程,该怎么办?使用 kill() 只能指定 PID,内核会选择该进程中的某个线程来接收信号,但我们无法精确控制是哪一个。

tkill (Thread Kill) 系统调用就是为了解决这个问题而设计的。它的作用是向指定的线程 ID (TID) 发送信号

简单来说,tkill 就是 kill 的“精确打击”版本,它让你可以指定向哪个“小兵”(线程)开炮,而不是向整个“军队”(进程)开炮。

重要提示

  • tkill 是一个非常底层的系统调用。
  • 对于大多数应用程序开发,不推荐直接使用 tkill
  • POSIX 标准提供了更安全、更可移植的线程信号发送方法:pthread_kill()。这是你应该优先考虑使用的函数。
  • tkill 主要由线程库(如 NPTL)或高级调试/管理工具在内部使用。

2. 函数原型

// 标准 C 库通常不提供直接包装,需要通过 syscall 调用
#include <sys/syscall.h> // 包含系统调用号 SYS_tkill
#include <unistd.h>      // 包含 syscall 函数
#include <signal.h>      // 包含信号常量

long syscall(SYS_tkill, int tid, int sig);
// 注意:现代 glibc (2.30+) 提供了 tgkill,tkill 可能被弃用或不直接暴露

注意:用户空间标准 C 库通常不直接提供 tkill() 函数。你需要使用 syscall() 函数来直接调用系统调用号 SYS_tkill

3. 功能

向指定线程 ID (tid) 的线程发送指定的信号 (sig)。

4. 参数

  • tid:
    • int 类型。
    • 目标线程在内核中的唯一 ID (Thread ID)。这不是 POSIX 线程库 (pthread_t) 的 ID,而是内核级别的 TID。可以通过 syscall(SYS_gettid) 获取当前线程的 TID。
  • sig:
    • int 类型。
    • 要发送的信号编号,例如 SIGTERMSIGUSR1SIGSTOP 等。注意,SIGKILL 和 SIGSTOP 不能被捕获或忽略,但可以发送。

5. 返回值

  • 成功: 返回 0。
  • 失败: 返回 -1,并设置全局变量 errno 来指示具体的错误原因。

6. 错误码 (errno)

  • EINVALsig 参数无效(不是一个有效的信号号)。
  • EPERM: 调用者权限不足,无法向目标线程发送信号(例如,普通用户试图向 root 用户的线程发送信号)。
  • ESRCH: 找不到 tid 指定的线程。

7. 相似函数或关联函数

  • kill: 向指定进程 ID (PID) 发送信号。内核会选择进程中的一个线程来接收信号。
  • pthread_kill: POSIX 标准函数,用于向指定的 pthread_t 线程发送信号。这是用户空间多线程程序推荐使用的方法。
  • tgkill: 一个更安全的系统调用,用于向指定线程组 ID 和线程 ID 的线程发送信号 (tgkill(tgid, tid, sig))。它提供了额外的检查以避免向错误的线程发送信号。pthread_kill 在底层通常会调用 tgkill
  • gettid: 获取当前线程的内核 TID。需要通过 syscall(SYS_gettid) 调用。
  • pthread_self: 获取当前线程的 POSIX 线程 ID (pthread_t)。

8. 为什么 tkill 不推荐直接使用?

  1. 易错性:直接使用内核 TID (tid) 容易出错。如果 tid 恰好与系统中另一个不相关的进程的 PID 相同,tkill 可能会错误地向那个进程发送信号。
  2. 竞态条件:线程 ID 是可复用的。一个线程退出后,它的 TID 可能会被分配给一个新创建的、完全不相关的线程。如果在 ID 复用之间调用 tkill,可能会发送给错误的线程。
  3. 可移植性tkill 是 Linux 特有的系统调用。使用 POSIX 标准的 pthread_kill 可以让你的代码更容易移植到其他支持 POSIX 线程的系统上。
  4. 更好的抽象pthread_kill 工作在 POSIX 线程模型层面,更符合应用程序员的思维。

9. 示例代码

由于直接使用 tkill 比较危险且不推荐,下面的示例将演示:

  1. 如何获取线程的内核 TID。
  2. 如何(不推荐地)使用 tkill
  3. 如何(推荐地)使用 pthread_kill

警告:此示例用于教学目的,展示 tkill 的用法。在实际编程中,请使用 pthread_kill

#define _GNU_SOURCE // 启用 GNU 扩展以使用 syscall(SYS_gettid)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>   // POSIX 线程
#include <signal.h>    // 信号
#include <sys/syscall.h> // syscall, SYS_tkill, SYS_gettid
#include <errno.h>
#include <string.h>

// 全局变量用于线程间通信
volatile sig_atomic_t signal_received = 0;

// 信号处理函数
void signal_handler(int sig) {
    printf("Thread (TID %ld) received signal %d\n", syscall(SYS_gettid), sig);
    signal_received = 1;
}

// 线程函数
void* worker_thread(void *arg) {
    long thread_num = (long)arg;
    pid_t my_tid = syscall(SYS_gettid); // 获取内核 TID

    printf("Worker thread %ld started. Kernel TID: %d\n", thread_num, my_tid);

    // 设置信号处理掩码,解除对 SIGUSR1 的阻塞
    // (假设主线程已经阻塞了它)
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGUSR1);
    pthread_sigmask(SIG_UNBLOCK, &set, NULL);

    // 等待信号
    while (!signal_received) {
        printf("Worker thread %ld (TID %d) waiting for signal...\n", thread_num, my_tid);
        sleep(1);
    }

    printf("Worker thread %ld (TID %d) finishing.\n", thread_num, my_tid);
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    pid_t main_tid = syscall(SYS_gettid); // 获取主线程的 TID
    struct sigaction sa;

    printf("--- Demonstrating tkill vs pthread_kill ---\n");
    printf("Main thread PID: %d, Kernel TID: %d\n", getpid(), main_tid);

    // 1. 设置信号处理函数 (主线程)
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGUSR1, &sa, NULL) == -1) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    // 2. 阻塞 SIGUSR1 在主线程,稍后在线程中解除阻塞
    sigset_t block_set;
    sigemptyset(&block_set);
    sigaddset(&block_set, SIGUSR1);
    sigprocmask(SIG_BLOCK, &block_set, NULL);

    // 3. 创建工作线程
    if (pthread_create(&thread1, NULL, worker_thread, (void*)1) != 0 ||
        pthread_create(&thread2, NULL, worker_thread, (void*)2) != 0) {
        perror("pthread_create");
        exit(EXIT_FAILURE);
    }

    sleep(2); // 等待线程启动并打印 TID

    // --- 方法 1: 使用不推荐的 tkill ---
    printf("\n--- Using tkill (NOT RECOMMENDED) ---\n");
    // 假设我们 somehow 知道了 thread1 的内核 TID (这在现实中很难安全地做到)
    // 这里我们简化处理,直接使用
    pid_t worker1_tid = syscall(SYS_gettid); // 这是错误的!这是主线程的 TID
    // 为了演示,我们假设我们有一个正确的方法获取了 worker1 的 TID
    // 比如通过全局变量或线程自己报告
    // 让我们让 worker_thread 报告它的 TID
    // (在实际代码中,你需要一个安全的机制在线程间传递 TID)
    // 这里我们伪造一个值来演示,实际使用非常危险
    // pid_t fake_worker_tid = 99999; // 假设的 TID
    // printf("Attempting to send SIGUSR1 to worker thread using tkill(TID=%d)...\n", fake_worker_tid);
    // long result = syscall(SYS_tkill, fake_worker_tid, SIGUSR1);
    // if (result == -1) {
    //     perror("tkill");
    // } else {
    //     printf("tkill succeeded.\n");
    // }

    // 由于获取其他线程 TID 的安全方法复杂,我们跳过直接 tkill 演示
    // 而是重点演示推荐的方法

    // --- 方法 2: 使用推荐的 pthread_kill ---
    printf("\n--- Using pthread_kill (RECOMMENDED) ---\n");
    printf("Sending SIGUSR1 to worker thread 1 using pthread_kill()...\n");
    if (pthread_kill(thread1, SIGUSR1) != 0) {
        perror("pthread_kill thread1");
    } else {
        printf("pthread_kill(thread1, SIGUSR1) succeeded.\n");
    }

    sleep(2); // 等待线程处理信号

    printf("Sending SIGUSR1 to worker thread 2 using pthread_kill()...\n");
    if (pthread_kill(thread2, SIGUSR1) != 0) {
        perror("pthread_kill thread2");
    } else {
        printf("pthread_kill(thread2, SIGUSR1) succeeded.\n");
    }

    // 5. 等待线程结束
    if (pthread_join(thread1, NULL) != 0 ||
        pthread_join(thread2, NULL) != 0) {
        perror("pthread_join");
    }

    printf("\nMain thread finished.\n");
    return 0;
}

改进版示例:安全地在线程间传递 TID 并演示 tkill(仅供学习)

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/syscall.h>
#include <errno.h>
#include <stdatomic.h>

// 使用原子变量安全地在线程间共享 TID
_Atomic pid_t worker_tid = 0;

volatile sig_atomic_t worker_signal_received = 0;

void worker_signal_handler(int sig) {
    pid_t tid = syscall(SYS_gettid);
    printf("Worker (TID %d) received signal %d\n", tid, sig);
    worker_signal_received = 1;
}

void* worker_thread_v2(void *arg) {
    pid_t my_tid = syscall(SYS_gettid);
    printf("Worker thread started. Kernel TID: %d\n", my_tid);

    // 安全地将 TID 报告给主线程
    atomic_store(&worker_tid, my_tid);

    // 设置信号处理
    struct sigaction sa;
    sa.sa_handler = worker_signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGUSR2, &sa, NULL) == -1) { // 使用不同的信号以区分
        perror("sigaction worker");
        return NULL;
    }

    while (!worker_signal_received) {
        sleep(1);
    }
    printf("Worker (TID %d) exiting.\n", my_tid);
    return NULL;
}

int main() {
    pthread_t thread;
    pid_t main_tid = syscall(SYS_gettid);

    printf("--- Demonstrating tkill (Learning Purpose Only) ---\n");
    printf("Main thread PID: %d, Kernel TID: %d\n", getpid(), main_tid);

    if (pthread_create(&thread, NULL, worker_thread_v2, NULL) != 0) {
        perror("pthread_create");
        exit(EXIT_FAILURE);
    }

    // 等待 worker 线程报告其 TID
    pid_t target_tid;
    while ((target_tid = atomic_load(&worker_tid)) == 0) {
        usleep(100000); // 0.1 秒
    }
    printf("Main thread got worker TID: %d\n", target_tid);

    sleep(1); // 确保 worker 设置了信号处理函数

    // --- 现在演示 tkill (仅供学习,实际不推荐) ---
    printf("\n--- Using tkill (FOR LEARNING ONLY) ---\n");
    printf("Sending SIGUSR2 to worker thread (TID %d) using tkill()...\n", target_tid);
    long result = syscall(SYS_tkill, target_tid, SIGUSR2);
    if (result == -1) {
        perror("tkill");
        printf("This might fail due to permissions or the TID being invalid/reused.\n");
    } else {
        printf("tkill() returned 0 (success).\n");
    }

    pthread_join(thread, NULL);
    printf("Main thread finished.\n");
    return 0;
}

10. 编译和运行

# 假设代码保存在 tkill_example.c 中
# 需要链接 pthread 库
gcc -o tkill_example tkill_example.c -lpthread

# 运行程序
./tkill_example

11. 预期输出 (第二个示例)

--- Demonstrating tkill (Learning Purpose Only) ---
Main thread PID: 12345, Kernel TID: 12345
Worker thread started. Kernel TID: 12346
Main thread got worker TID: 12346

--- Using tkill (FOR LEARNING ONLY) ---
Sending SIGUSR2 to worker thread (TID 12346) using tkill()...
Worker (TID 12346) received signal 12
tkill() returned 0 (success).
Worker (TID 12346) exiting.
Main thread finished.

12. 总结

tkill 是一个底层的 Linux 系统调用,用于向指定的内核线程 ID (TID) 发送信号。

  • 优点:提供了向特定线程发送信号的能力。
  • 缺点/风险
    • 易于误用,可能导致向错误的进程/线程发送信号。
    • 存在竞态条件(TID 复用)。
    • 不是 POSIX 标准,可移植性差。
  • 推荐做法:在用户空间多线程程序中,应始终优先使用标准的 pthread_kill() 函数来向特定线程发送信号。它更安全、更可靠、更具可移植性。
  • tkill 的用途:主要供系统级程序、线程库实现或调试工具内部使用。

对于 Linux 编程新手,请记住:能用 pthread_kill 就别用 tkill

https://app-blog.csdn.net/csdn/aiChatNew

1. 函数介绍

2. 函数原型

3. 功能

4. 参数

5. 返回值

6. 错误码 (errno)

7. 相似函数或关联函数

8. 为什么 tkill 不推荐直接使用?

9. 示例代码

10. 编译和运行

11. 预期输出 (第二个示例)

12. 总结

Markdown 7782 字数 338 行数 当前行 1, 当前列 20 文章已保存22:13:08

HTML 7390 字数 253 段落

保存草稿 发布文章

发表在 linux文章 | 留下评论

truncate 系统调用及示例

truncate – 截断文件

函数介绍

truncate系统调用用于将文件截断到指定长度。如果指定长度小于文件当前长度,则文件末尾被截断;如果指定长度大于文件当前长度,则文件被扩展,扩展部分填充为零。

函数原型

#include <unistd.h>
#include <sys/types.h>

int truncate(const char *path, off_t length);

功能

根据文件路径将文件截断或扩展到指定长度。

参数

  • const char *path: 文件路径名
  • off_t length: 目标文件长度(字节)

返回值

  • 成功时返回0
  • 失败时返回-1,并设置errno:
    • EACCES: 权限不足
    • EFBIG: 长度参数过大
    • EIO: I/O错误
    • EISDIR: 路径指向目录
    • ELOOP: 符号链接循环
    • ENAMETOOLONG: 路径名过长
    • ENOENT: 文件不存在
    • ENOTDIR: 路径前缀不是目录
    • EPERM: 操作不被允许
    • EROFS: 文件在只读文件系统上
    • ETXTBSY: 文件是正在执行的程序

相似函数

  • ftruncate(): 通过文件描述符截断文件
  • open()配合O_TRUNC标志

示例代码

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

int main() {
    int fd;
    struct stat stat_buf;
    
    printf("=== Truncate函数示例 ===\n");
    
    // 示例1: 基本的文件截断操作
    printf("\n示例1: 基本的文件截断操作\n");
    
    // 创建测试文件并写入数据
    fd = open("test_truncate.txt", O_CREAT | O_RDWR | O_TRUNC, 0644);
    if (fd == -1) {
        perror("创建测试文件失败");
        exit(EXIT_FAILURE);
    }
    
    // 写入较长的数据
    const char *original_data = 
        "This is a long piece of text that will be used to demonstrate "
        "the truncate function. It contains multiple sentences and is "
        "quite lengthy to show how truncation works.";
    
    if (write(fd, original_data, strlen(original_data)) == -1) {
        perror("写入原始数据失败");
        close(fd);
        exit(EXIT_FAILURE);
    }
    
    printf("写入原始数据,长度: %ld 字节\n", (long)strlen(original_data));
    close(fd);
    
    // 获取原始文件状态
    if (stat("test_truncate.txt", &stat_buf) == -1) {
        perror("获取文件状态失败");
    } else {
        printf("原始文件大小: %ld 字节\n", stat_buf.st_size);
    }
    
    // 使用truncate截断文件到50字节
    printf("\n使用truncate将文件截断到50字节...\n");
    if (truncate("test_truncate.txt", 50) == -1) {
        perror("截断文件失败");
    } else {
        printf("文件截断成功\n");
    }
    
    // 检查截断后的文件大小
    if (stat("test_truncate.txt", &stat_buf) == -1) {
        perror("获取截断后文件状态失败");
    } else {
        printf("截断后文件大小: %ld 字节\n", stat_buf.st_size);
    }
    
    // 读取截断后的数据验证
    fd = open("test_truncate.txt", O_RDONLY);
    if (fd != -1) {
        char buffer[100];
        ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
        if (bytes_read > 0) {
            buffer[bytes_read] = '\0';
            printf("截断后文件内容: %s\n", buffer);
        }
        close(fd);
    }
    
    // 示例2: 扩展文件
    printf("\n示例2: 扩展文件\n");
    
    // 使用truncate将文件扩展到100字节
    printf("使用truncate将文件扩展到100字节...\n");
    if (truncate("test_truncate.txt", 100) == -1) {
        perror("扩展文件失败");
    } else {
        printf("文件扩展成功\n");
    }
    
    // 检查扩展后的文件大小
    if (stat("test_truncate.txt", &stat_buf) == -1) {
        perror("获取扩展后文件状态失败");
    } else {
        printf("扩展后文件大小: %ld 字节\n", stat_buf.st_size);
    }
    
    // 读取扩展后的数据
    fd = open("test_truncate.txt", O_RDONLY);
    if (fd != -1) {
        char buffer[150];
        ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
        if (bytes_read > 0) {
            printf("扩展后文件前%d字节内容:\n", (int)bytes_read);
            // 打印可见字符
            for (int i = 0; i < bytes_read && i < 60; i++) {
                if (buffer[i] >= 32 && buffer[i] <= 126) {
                    putchar(buffer[i]);
                } else {
                    printf("[%02x]", (unsigned char)buffer[i]);
                }
            }
            printf("\n");
        }
        close(fd);
    }
    
    // 示例3: 截断到0字节(清空文件)
    printf("\n示例3: 截断到0字节(清空文件)\n");
    
    printf("将文件截断到0字节...\n");
    if (truncate("test_truncate.txt", 0) == -1) {
        perror("清空文件失败");
    } else {
        printf("文件清空成功\n");
    }
    
    if (stat("test_truncate.txt", &stat_buf) == -1) {
        perror("获取清空后文件状态失败");
    } else {
        printf("清空后文件大小: %ld 字节\n", stat_buf.st_size);
    }
    
    // 示例4: 不同长度的截断演示
    printf("\n示例4: 不同长度的截断演示\n");
    
    // 重新创建文件并写入数据
    fd = open("test_truncate.txt", O_CREAT | O_RDWR | O_TRUNC, 0644);
    if (fd != -1) {
        const char *test_data = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        if (write(fd, test_data, strlen(test_data)) != -1) {
            printf("重新写入测试数据: %s\n", test_data);
        }
        close(fd);
    }
    
    // 演示不同长度的截断
    off_t lengths[] = {5, 15, 30, 50};
    for (int i = 0; i < 4; i++) {
        printf("截断到%ld字节: ", lengths[i]);
        if (truncate("test_truncate.txt", lengths[i]) == -1) {
            printf("失败 - %s\n", strerror(errno));
        } else {
            if (stat("test_truncate.txt", &stat_buf) == -1) {
                printf("获取状态失败\n");
            } else {
                printf("成功,新大小: %ld字节\n", stat_buf.st_size);
                
                // 读取并显示内容
                fd = open("test_truncate.txt", O_RDONLY);
                if (fd != -1) {
                    char buffer[100];
                    ssize_t bytes_read = read(fd, buffer, stat_buf.st_size);
                    if (bytes_read > 0) {
                        buffer[bytes_read] = '\0';
                        printf("  内容: %s\n", buffer);
                    }
                    close(fd);
                }
            }
        }
    }
    
    // 示例5: 错误处理演示
    printf("\n示例5: 错误处理演示\n");
    
    // 尝试截断不存在的文件
    if (truncate("nonexistent_file.txt", 100) == -1) {
        printf("截断不存在的文件: %s\n", strerror(errno));
    }
    
    // 尝试对只读文件系统上的文件操作
    // 这个测试可能需要特殊环境,我们只演示概念
    printf("对只读文件系统操作会返回EROFS错误\n");
    
    // 尝试使用负数长度
    if (truncate("test_truncate.txt", -10) == -1) {
        printf("使用负数长度: %s\n", strerror(errno));
    }
    
    // 尝试对目录操作
    if (truncate(".", 100) == -1) {
        printf("对目录截断: %s\n", strerror(errno));
    }
    
    // 示例6: 实际应用场景
    printf("\n示例6: 实际应用场景\n");
    
    // 场景1: 日志文件轮转
    printf("场景1: 日志文件轮转\n");
    int log_fd = open("application.log", O_CREAT | O_RDWR | O_APPEND, 0644);
    if (log_fd != -1) {
        // 模拟写入大量日志
        for (int i = 0; i < 100; i++) {
            char log_entry[100];
            sprintf(log_entry, "Log entry %d: Application is running normally\n", i);
            write(log_fd, log_entry, strlen(log_entry));
        }
        close(log_fd);
        
        // 检查日志文件大小
        if (stat("application.log", &stat_buf) == 0) {
            printf("日志文件大小: %ld 字节\n", stat_buf.st_size);
            
            // 如果文件太大,截断到1KB
            if (stat_buf.st_size > 1024) {
                printf("日志文件过大,截断到1KB...\n");
                if (truncate("application.log", 1024) == -1) {
                    perror("日志文件截断失败");
                } else {
                    printf("日志文件截断成功\n");
                }
            }
        }
        
        unlink("application.log");
    }
    
    // 场景2: 临时文件大小控制
    printf("场景2: 临时文件大小控制\n");
    int temp_fd = open("temp_file.dat", O_CREAT | O_RDWR, 0644);
    if (temp_fd != -1) {
        // 创建一个大文件
        char large_data[1000];
        memset(large_data, 'X', sizeof(large_data));
        for (int i = 0; i < 10; i++) {
            write(temp_fd, large_data, sizeof(large_data));
        }
        close(temp_fd);
        
        if (stat("temp_file.dat", &stat_buf) == 0) {
            printf("临时文件原始大小: %ld 字节\n", stat_buf.st_size);
            
            // 将文件大小调整为5KB
            printf("调整临时文件大小到5KB...\n");
            if (truncate("temp_file.dat", 5120) == -1) {
                perror("调整文件大小失败");
            } else {
                printf("文件大小调整成功\n");
                
                if (stat("temp_file.dat", &stat_buf) == 0) {
                    printf("调整后文件大小: %ld 字节\n", stat_buf.st_size);
                }
            }
        }
        
        unlink("temp_file.dat");
    }
    
    // 清理资源
    printf("\n清理资源...\n");
    if (unlink("test_truncate.txt") == -1) {
        perror("删除测试文件失败");
    } else {
        printf("成功删除测试文件\n");
    }
    
    return 0;
}
发表在 linux文章 | 留下评论

tuxcall系统调用及示例

tuxcall函数详解

1. 函数介绍

tuxcall函数是Linux内核中一个特殊的系统调用,主要用于TUX(Threaded linUX web server)Web服务器的内核级操作。TUX是一个实验性的高性能Web服务器,它将HTTP请求处理的某些部分直接在内核空间完成,以减少用户空间和内核空间之间的上下文切换开销。

可以把tuxcall想象成一个”内核级Web服务接口”,它允许用户空间程序与内核中的TUX Web服务器模块进行通信。通过tuxcall,应用程序可以执行一些原本需要在内核中处理的Web服务器操作,如缓存管理、连接处理等。

重要说明: tuxcall是一个非常特殊的函数,它:

  • 不是标准的POSIX系统调用
  • 主要用于特定的内核模块(TUX Web服务器)
  • 在现代Linux发行版中很少使用
  • 需要特定的内核配置和支持

使用场景:

  • 与TUX内核Web服务器交互
  • 高性能Web服务器开发
  • 内核模块与用户空间通信
  • 学习Linux内核网络子系统

2. 函数原型

#include <sys/syscall.h>
#include <unistd.h>

// tuxcall不是标准库函数,需要通过系统调用直接调用
long syscall(SYS_tuxcall, int subcall, void *arg1, void *arg2);

注意:tuxcall在标准的系统调用表中可能不存在,因为它是一个实验性功能。

3. 功能

tuxcall函数的主要功能是作为用户空间程序与TUX内核Web服务器模块之间的通信接口。它支持多种子调用,每种子调用执行不同的Web服务器相关操作:

  • 缓存管理: 管理内核中的HTTP内容缓存
  • 连接控制: 控制网络连接的状态
  • 统计信息: 获取Web服务器的运行统计
  • 配置管理: 配置内核Web服务器参数

4. 参数

  • subcall: 子调用类型
    • 类型:int
    • 含义:指定要执行的具体操作类型
    • 常用值(如果支持):
      • TUX_INIT:初始化TUX系统
      • TUX_CACHE_ADD:添加缓存项
      • TUX_CACHE_DEL:删除缓存项
      • TUX_CACHE_LOOKUP:查找缓存项
      • TUX_STATS_GET:获取统计信息
      • TUX_CONFIG_SET:设置配置参数
  • arg1: 第一个参数
    • 类型:void*
    • 含义:根据subcall类型而定的参数,通常是指向数据结构的指针
  • arg2: 第二个参数
    • 类型:void*
    • 含义:根据subcall类型而定的第二个参数,可能为NULL

5. 返回值

  • 成功: 返回0或具体操作的返回值
  • 失败: 返回-1,并设置errno错误码
    • ENOSYS:系统调用不支持
    • EINVAL:参数无效
    • EPERM:权限不足
    • ENODEV:设备或模块不存在

6. 相似函数或关联函数

  • syscall(): 通用系统调用接口
  • ioctl(): 设备控制接口
  • socketcall(): 套接字相关系统调用
  • TUX内核模块: 实际提供功能的内核组件
  • sendfile(): 高效文件传输函数
  • splice(): 管道数据传输函数

7. 示例代码

示例1:检测tuxcall支持

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include <string.h>

// 尝试定义tuxcall系统调用号(可能不存在)
#ifndef SYS_tuxcall
#define SYS_tuxcall 184  // 这是一个假设的系统调用号
#endif

// TUX子调用类型(假设定义)
#define TUX_NOP         0
#define TUX_INIT        1
#define TUX_VERSION     2
#define TUX_STATS       3

// 检测系统是否支持tuxcall
int check_tuxcall_support() {
    printf("检测tuxcall系统调用支持...\n");
    
    // 尝试调用一个无害的NOP操作
    long result = syscall(SYS_tuxcall, TUX_NOP, NULL, NULL);
    
    if (result == -1) {
        if (errno == ENOSYS) {
            printf("✗ tuxcall系统调用不被支持\n");
            printf("  错误: %s\n", strerror(errno));
            return 0;
        } else {
            printf("? tuxcall系统调用存在但调用失败\n");
            printf("  错误: %s\n", strerror(errno));
            return 1;  // 系统调用存在但参数错误是正常的
        }
    } else {
        printf("✓ tuxcall系统调用支持\n");
        return 1;
    }
}

// 获取TUX版本信息
int get_tux_version() {
    char version_buffer[256];
    long result = syscall(SYS_tuxcall, TUX_VERSION, version_buffer, sizeof(version_buffer));
    
    if (result == -1) {
        printf("获取TUX版本失败: %s\n", strerror(errno));
        return -1;
    }
    
    printf("TUX版本: %s\n", version_buffer);
    return 0;
}

int main() {
    printf("=== tuxcall函数检测示例 ===\n");
    printf("注意: tuxcall是一个实验性功能,可能不被当前系统支持\n\n");
    
    // 检测系统支持
    if (!check_tuxcall_support()) {
        printf("\n由于系统不支持tuxcall,演示程序结束\n");
        printf("这在现代Linux系统中是正常现象\n");
        return 0;
    }
    
    // 尝试初始化TUX(如果支持)
    printf("\n尝试初始化TUX系统...\n");
    long init_result = syscall(SYS_tuxcall, TUX_INIT, NULL, NULL);
    if (init_result == -1) {
        if (errno == EPERM) {
            printf("初始化失败: 权限不足(需要root权限)\n");
        } else if (errno == ENODEV) {
            printf("初始化失败: TUX模块未加载\n");
        } else {
            printf("初始化失败: %s\n", strerror(errno));
        }
    } else {
        printf("TUX系统初始化成功\n");
    }
    
    // 尝试获取版本信息
    printf("\n获取TUX版本信息...\n");
    get_tux_version();
    
    // 演示统计信息获取
    printf("\n获取TUX统计信息...\n");
    struct {
        unsigned long requests;
        unsigned long cache_hits;
        unsigned long cache_misses;
        unsigned long errors;
    } stats;
    
    long stats_result = syscall(SYS_tuxcall, TUX_STATS, &stats, sizeof(stats));
    if (stats_result == -1) {
        printf("获取统计信息失败: %s\n", strerror(errno));
    } else {
        printf("TUX统计信息:\n");
        printf("  总请求数: %lu\n", stats.requests);
        printf("  缓存命中: %lu\n", stats.cache_hits);
        printf("  缓存未命中: %lu\n", stats.cache_misses);
        printf("  错误数: %lu\n", stats.errors);
    }
    
    printf("\n=== tuxcall检测完成 ===\n");
    printf("注意: 如果看到'系统调用不被支持',这是正常现象\n");
    printf("现代Linux系统通常不包含TUX Web服务器支持\n");
    
    return 0;
}

示例2:模拟tuxcall接口(用于学习)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include <string.h>
#include <time.h>

// 模拟TUX相关的数据结构和常量
#define TUX_MAX_CACHE_ENTRIES 1000

// 模拟的缓存项结构
typedef struct {
    char url[256];
    char content[1024];
    time_t timestamp;
    int valid;
} tux_cache_entry_t;

// 模拟的统计结构
typedef struct {
    unsigned long total_requests;
    unsigned long cache_hits;
    unsigned long cache_misses;
    unsigned long errors;
    time_t start_time;
} tux_stats_t;

// 模拟的TUX系统状态
static tux_cache_entry_t cache[TUX_MAX_CACHE_ENTRIES];
static tux_stats_t stats = {0};
static int tux_initialized = 0;

// TUX子调用类型
#define TUX_NOP         0
#define TUX_INIT        1
#define TUX_SHUTDOWN    2
#define TUX_VERSION     3
#define TUX_CACHE_ADD   4
#define TUX_CACHE_DEL   5
#define TUX_CACHE_LOOKUP 6
#define TUX_STATS       7
#define TUX_CLEAR_CACHE 8

// 模拟的tuxcall实现
long simulate_tuxcall(int subcall, void *arg1, void *arg2) {
    switch (subcall) {
        case TUX_NOP:
            return 0;
            
        case TUX_INIT:
            if (!tux_initialized) {
                memset(&stats, 0, sizeof(stats));
                stats.start_time = time(NULL);
                memset(cache, 0, sizeof(cache));
                tux_initialized = 1;
                printf("[模拟] TUX系统初始化完成\n");
            }
            return 0;
            
        case TUX_SHUTDOWN:
            if (tux_initialized) {
                tux_initialized = 0;
                printf("[模拟] TUX系统已关闭\n");
            }
            return 0;
            
        case TUX_VERSION:
            if (arg1 && arg2) {
                snprintf((char*)arg1, (size_t)arg2, "TUX Web Server 2.0 (模拟版本)");
                return 0;
            }
            errno = EINVAL;
            return -1;
            
        case TUX_CACHE_ADD:
            if (arg1) {
                // 简化的缓存添加逻辑
                printf("[模拟] 添加缓存项\n");
                stats.total_requests++;
                return 0;
            }
            errno = EINVAL;
            return -1;
            
        case TUX_CACHE_DEL:
            if (arg1) {
                printf("[模拟] 删除缓存项: %s\n", (char*)arg1);
                return 0;
            }
            errno = EINVAL;
            return -1;
            
        case TUX_CACHE_LOOKUP:
            if (arg1 && arg2) {
                printf("[模拟] 查找缓存项: %s\n", (char*)arg1);
                stats.total_requests++;
                stats.cache_misses++;
                // 模拟未找到
                return -1;
            }
            errno = EINVAL;
            return -1;
            
        case TUX_STATS:
            if (arg1 && arg2) {
                if ((size_t)arg2 >= sizeof(tux_stats_t)) {
                    memcpy(arg1, &stats, sizeof(tux_stats_t));
                    return 0;
                }
            }
            errno = EINVAL;
            return -1;
            
        case TUX_CLEAR_CACHE:
            memset(cache, 0, sizeof(cache));
            printf("[模拟] 缓存已清空\n");
            return 0;
            
        default:
            errno = EINVAL;
            return -1;
    }
}

// 模拟的系统调用封装
long my_tuxcall(int subcall, void *arg1, void *arg2) {
    // 在实际系统中,这里会调用真正的syscall
    // return syscall(SYS_tuxcall, subcall, arg1, arg2);
    
    // 现在我们模拟这个调用
    return simulate_tuxcall(subcall, arg1, arg2);
}

// 工具函数:显示TUX状态
void show_tux_status() {
    printf("\n=== TUX系统状态 ===\n");
    printf("初始化状态: %s\n", tux_initialized ? "已初始化" : "未初始化");
    if (tux_initialized) {
        printf("运行时间: %ld 秒\n", time(NULL) - stats.start_time);
    }
    printf("==================\n\n");
}

int main() {
    printf("=== 模拟tuxcall接口示例 ===\n");
    printf("注意: 这是一个模拟实现,用于演示tuxcall的概念\n\n");
    
    // 显示初始状态
    show_tux_status();
    
    // 测试初始化
    printf("1. 测试TUX初始化:\n");
    if (my_tuxcall(TUX_INIT, NULL, NULL) == 0) {
        printf("✓ 初始化成功\n");
    } else {
        printf("✗ 初始化失败: %s\n", strerror(errno));
    }
    
    show_tux_status();
    
    // 测试版本获取
    printf("2. 测试版本获取:\n");
    char version[256];
    if (my_tuxcall(TUX_VERSION, version, sizeof(version)) == 0) {
        printf("✓ TUX版本: %s\n", version);
    } else {
        printf("✗ 获取版本失败: %s\n", strerror(errno));
    }
    
    // 测试缓存操作
    printf("\n3. 测试缓存操作:\n");
    
    // 添加缓存项
    const char* test_url = "/index.html";
    if (my_tuxcall(TUX_CACHE_ADD, (void*)test_url, NULL) == 0) {
        printf("✓ 添加缓存项: %s\n", test_url);
    } else {
        printf("✗ 添加缓存项失败: %s\n", strerror(errno));
    }
    
    // 查找缓存项
    if (my_tuxcall(TUX_CACHE_LOOKUP, (void*)test_url, NULL) == 0) {
        printf("✓ 缓存命中: %s\n", test_url);
    } else {
        printf("✗ 缓存未命中: %s\n", test_url);
    }
    
    // 删除缓存项
    if (my_tuxcall(TUX_CACHE_DEL, (void*)test_url, NULL) == 0) {
        printf("✓ 删除缓存项: %s\n", test_url);
    } else {
        printf("✗ 删除缓存项失败: %s\n", strerror(errno));
    }
    
    // 测试统计信息
    printf("\n4. 测试统计信息:\n");
    tux_stats_t current_stats;
    if (my_tuxcall(TUX_STATS, &current_stats, sizeof(current_stats)) == 0) {
        printf("✓ 获取统计信息成功:\n");
        printf("  总请求数: %lu\n", current_stats.total_requests);
        printf("  缓存命中: %lu\n", current_stats.cache_hits);
        printf("  缓存未命中: %lu\n", current_stats.cache_misses);
        printf("  错误数: %lu\n", current_stats.errors);
        printf("  运行时间: %ld 秒\n", time(NULL) - current_stats.start_time);
    } else {
        printf("✗ 获取统计信息失败: %s\n", strerror(errno));
    }
    
    // 测试缓存清空
    printf("\n5. 测试缓存清空:\n");
    if (my_tuxcall(TUX_CLEAR_CACHE, NULL, NULL) == 0) {
        printf("✓ 缓存清空成功\n");
    } else {
        printf("✗ 缓存清空失败: %s\n", strerror(errno));
    }
    
    // 测试关闭
    printf("\n6. 测试TUX关闭:\n");
    if (my_tuxcall(TUX_SHUTDOWN, NULL, NULL) == 0) {
        printf("✓ TUX系统关闭成功\n");
    } else {
        printf("✗ TUX系统关闭失败: %s\n", strerror(errno));
    }
    
    show_tux_status();
    
    // 测试错误处理
    printf("7. 测试错误处理:\n");
    if (my_tuxcall(999, NULL, NULL) == -1) {
        printf("✓ 无效子调用正确返回错误: %s\n", strerror(errno));
    }
    
    if (my_tuxcall(TUX_STATS, NULL, NULL) == -1) {
        printf("✓ 无效参数正确返回错误: %s\n", strerror(errno));
    }
    
    printf("\n=== 模拟演示完成 ===\n");
    printf("说明: 这是一个概念演示,展示了tuxcall可能的功能\n");
    printf("实际的tuxcall需要内核支持,现代系统通常不包含此功能\n");
    
    return 0;
}

示例3:tuxcall与Web服务器集成概念

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include <string.h>
#include <time.h>

// Web服务器配置结构
typedef struct {
    int port;
    int max_connections;
    int cache_size;
    char document_root[256];
    int enable_logging;
} web_config_t;

// HTTP请求结构
typedef struct {
    char method[16];
    char url[256];
    char version[16];
    char headers[1024];
} http_request_t;

// HTTP响应结构
typedef struct {
    int status_code;
    char status_text[64];
    char headers[512];
    char* body;
    size_t body_length;
} http_response_t;

// 模拟的TUX相关常量
#define TUX_WEB_INIT        10
#define TUX_WEB_CONFIGURE   11
#define TUX_WEB_HANDLE_REQ  12
#define TUX_WEB_SHUTDOWN    13
#define TUX_WEB_GET_METRICS 14

// 模拟的Web服务器状态
static int web_server_running = 0;
static web_config_t current_config = {0};
static unsigned long total_requests = 0;
static unsigned long served_pages = 0;
static unsigned long errors = 0;

// 模拟的tuxcall Web服务器接口
long web_tuxcall(int subcall, void *arg1, void *arg2) {
    switch (subcall) {
        case TUX_WEB_INIT:
            if (!web_server_running) {
                web_server_running = 1;
                total_requests = 0;
                served_pages = 0;
                errors = 0;
                printf("[Web服务器] 初始化完成\n");
                return 0;
            }
            return 0;
            
        case TUX_WEB_CONFIGURE:
            if (arg1 && web_server_running) {
                memcpy(&current_config, arg1, sizeof(web_config_t));
                printf("[Web服务器] 配置更新完成\n");
                printf("  端口: %d\n", current_config.port);
                printf("  最大连接数: %d\n", current_config.max_connections);
                printf("  文档根目录: %s\n", current_config.document_root);
                return 0;
            }
            errno = EINVAL;
            return -1;
            
        case TUX_WEB_HANDLE_REQ:
            if (arg1 && arg2 && web_server_running) {
                http_request_t *req = (http_request_t*)arg1;
                http_response_t *resp = (http_response_t*)arg2;
                
                total_requests++;
                
                printf("[Web服务器] 处理请求: %s %s\n", req->method, req->url);
                
                // 简单的请求处理逻辑
                if (strcmp(req->url, "/") == 0 || strcmp(req->url, "/index.html") == 0) {
                    resp->status_code = 200;
                    strcpy(resp->status_text, "OK");
                    resp->body = "<html><body><h1>Hello from TUX Web Server!</h1></body></html>";
                    resp->body_length = strlen(resp->body);
                    served_pages++;
                    return 0;
                } else if (strcmp(req->url, "/status") == 0) {
                    resp->status_code = 200;
                    strcpy(resp->status_text, "OK");
                    static char status_page[512];
                    snprintf(status_page, sizeof(status_page),
                             "<html><body><h1>Server Status</h1>"
                             "<p>Total Requests: %lu</p>"
                             "<p>Served Pages: %lu</p>"
                             "<p>Errors: %lu</p></body></html>",
                             total_requests, served_pages, errors);
                    resp->body = status_page;
                    resp->body_length = strlen(status_page);
                    served_pages++;
                    return 0;
                } else {
                    resp->status_code = 404;
                    strcpy(resp->status_text, "Not Found");
                    resp->body = "<html><body><h1>404 - Page Not Found</h1></body></html>";
                    resp->body_length = strlen(resp->body);
                    errors++;
                    return 0;
                }
            }
            errno = EINVAL;
            return -1;
            
        case TUX_WEB_SHUTDOWN:
            if (web_server_running) {
                web_server_running = 0;
                printf("[Web服务器] 已关闭\n");
                return 0;
            }
            return 0;
            
        case TUX_WEB_GET_METRICS:
            if (arg1 && arg2) {
                size_t *size = (size_t*)arg2;
                if (*size >= sizeof(unsigned long) * 3) {
                    unsigned long *metrics = (unsigned long*)arg1;
                    metrics[0] = total_requests;
                    metrics[1] = served_pages;
                    metrics[2] = errors;
                    return 0;
                }
            }
            errno = EINVAL;
            return -1;
            
        default:
            errno = EINVAL;
            return -1;
    }
}

// 模拟的系统调用封装
long my_web_tuxcall(int subcall, void *arg1, void *arg2) {
    return web_tuxcall(subcall, arg1, arg2);
}

// 创建测试请求
void create_test_request(http_request_t *req, const char* method, const char* url) {
    strncpy(req->method, method, sizeof(req->method) - 1);
    strncpy(req->url, url, sizeof(req->url) - 1);
    strcpy(req->version, "HTTP/1.1");
    strcpy(req->headers, "Host: localhost\r\nUser-Agent: tuxcall-test\r\n");
}

// 显示响应
void show_response(const http_response_t *resp) {
    printf("HTTP/%s %d %s\n", "1.1", resp->status_code, resp->status_text);
    printf("Content-Length: %zu\n", resp->body_length);
    printf("\n%s\n", resp->body ? resp->body : "");
}

int main() {
    printf("=== tuxcall Web服务器概念演示 ===\n");
    printf("说明: 演示tuxcall在Web服务器中的潜在应用\n\n");
    
    // 1. 初始化Web服务器
    printf("1. 初始化Web服务器:\n");
    if (my_web_tuxcall(TUX_WEB_INIT, NULL, NULL) == 0) {
        printf("✓ Web服务器初始化成功\n\n");
    } else {
        printf("✗ Web服务器初始化失败\n");
        return 1;
    }
    
    // 2. 配置Web服务器
    printf("2. 配置Web服务器:\n");
    web_config_t config = {
        .port = 8080,
        .max_connections = 1000,
        .cache_size = 100,
        .document_root = "/var/www",
        .enable_logging = 1
    };
    
    if (my_web_tuxcall(TUX_WEB_CONFIGURE, &config, NULL) == 0) {
        printf("✓ Web服务器配置完成\n\n");
    } else {
        printf("✗ Web服务器配置失败\n");
    }
    
    // 3. 处理HTTP请求
    printf("3. 处理HTTP请求:\n");
    
    http_request_t request;
    http_response_t response;
    
    // 测试主页请求
    printf("处理主页请求:\n");
    create_test_request(&request, "GET", "/");
    memset(&response, 0, sizeof(response));
    
    if (my_web_tuxcall(TUX_WEB_HANDLE_REQ, &request, &response) == 0) {
        show_response(&response);
    } else {
        printf("处理请求失败: %s\n", strerror(errno));
    }
    
    // 测试状态页面请求
    printf("处理状态页面请求:\n");
    create_test_request(&request, "GET", "/status");
    memset(&response, 0, sizeof(response));
    
    if (my_web_tuxcall(TUX_WEB_HANDLE_REQ, &request, &response) == 0) {
        show_response(&response);
    } else {
        printf("处理请求失败: %s\n", strerror(errno));
    }
    
    // 测试404页面请求
    printf("处理404页面请求:\n");
    create_test_request(&request, "GET", "/nonexistent.html");
    memset(&response, 0, sizeof(response));
    
    if (my_web_tuxcall(TUX_WEB_HANDLE_REQ, &request, &response) == 0) {
        show_response(&response);
    } else {
        printf("处理请求失败: %s\n", strerror(errno));
    }
    
    // 4. 获取服务器指标
    printf("4. 获取服务器指标:\n");
    unsigned long metrics[3];
    size_t metrics_size = sizeof(metrics);
    
    if (my_web_tuxcall(TUX_WEB_GET_METRICS, metrics, &metrics_size) == 0) {
        printf("服务器运行指标:\n");
        printf("  总请求数: %lu\n", metrics[0]);
        printf("  服务页面数: %lu\n", metrics[1]);
        printf("  错误数: %lu\n", metrics[2]);
    } else {
        printf("获取指标失败: %s\n", strerror(errno));
    }
    
    // 5. 性能测试
    printf("\n5. 性能测试:\n");
    printf("模拟处理1000个请求...\n");
    
    time_t start_time = time(NULL);
    
    for (int i = 0; i < 1000; i++) {
        create_test_request(&request, "GET", i % 3 == 0 ? "/" : 
                           (i % 3 == 1 ? "/status" : "/test"));
        my_web_tuxcall(TUX_WEB_HANDLE_REQ, &request, &response);
    }
    
    time_t end_time = time(NULL);
    printf("处理1000个请求耗时: %ld 秒\n", end_time - start_time);
    
    // 再次获取指标
    if (my_web_tuxcall(TUX_WEB_GET_METRICS, metrics, &metrics_size) == 0) {
        printf("更新后的指标:\n");
        printf("  总请求数: %lu\n", metrics[0]);
        printf("  服务页面数: %lu\n", metrics[1]);
        printf("  错误数: %lu\n", metrics[2]);
    }
    
    // 6. 关闭Web服务器
    printf("\n6. 关闭Web服务器:\n");
    if (my_web_tuxcall(TUX_WEB_SHUTDOWN, NULL, NULL) == 0) {
        printf("✓ Web服务器已关闭\n");
    } else {
        printf("✗ 关闭Web服务器失败\n");
    }
    
    printf("\n=== Web服务器演示完成 ===\n");
    printf("说明: 这展示了tuxcall在高性能Web服务器中的潜在应用\n");
    printf("实际使用需要内核支持TUX模块\n");
    
    return 0;
}

编译和运行

# 编译示例1
gcc -o tuxcall_example1 tuxcall_example1.c
./tuxcall_example1

# 编译示例2
gcc -o tuxcall_example2 tuxcall_example2.c
./tuxcall_example2

# 编译示例3
gcc -o tuxcall_example3 tuxcall_example3.c
./tuxcall_example3

重要注意事项

  1. 实验性功能: tuxcall是Linux内核的实验性功能,现代系统通常不支持
  2. 内核依赖: 需要特定的内核配置和TUX模块支持
  3. 系统调用号: tuxcall的系统调用号在不同内核版本中可能不同
  4. 权限要求: 某些操作可能需要root权限
  5. 兼容性: 不是标准POSIX接口,可移植性差
  6. 维护状态: TUX项目已经不再积极维护
  7. 替代方案: 现代高性能Web服务器通常使用用户空间解决方案

现代替代方案

由于tuxcall的局限性,现代高性能Web服务器通常采用:

  1. epoll/kqueue: 高效的I/O多路复用
  2. sendfile/splice: 零拷贝数据传输
  3. 异步I/O: 提高并发处理能力
  4. 用户空间Web服务器: 如Nginx、Apache等
  5. 内核旁路技术: 如DPDK等

通过这些示例,你可以理解tuxcall作为内核级Web服务器接口的概念,虽然在现代系统中很少使用,但它体现了Linux内核网络性能优化的设计思想。

发表在 linux文章 | 留下评论

umask系统调用及示例

我们来深入学习 umask 系统调用

1. 函数介绍

在 Linux 系统中,每个文件和目录都有与之相关的权限(Permissions),这些权限决定了谁(用户、组、其他人)可以对文件或目录执行什么操作(读、写、执行)。

当你创建一个新文件或目录时,系统需要决定这个新文件/目录的初始权限是什么。你可能会想当然地认为,比如用 touch newfile.txt 创建文件,这个文件的权限应该是 rw-rw-rw- (666),即所有用户都可读写。但实际上,Linux 为了安全,默认创建的文件权限会更严格一些。

umask (User File Creation Mask) 不是一个系统调用,而是一个 shell 内置命令 和一个 C 标准库函数。它用于设置或查询当前用户的文件权限掩码

这个“掩码”就像一个“过滤器”或“模具”。当你创建一个新文件或目录时,系统会先有一个“默认”的宽松权限(文件是 666,目录是 777),然后用 umask 的值来“过滤”掉(屏蔽掉)其中某些权限位,最终得到文件或目录的实际权限。

简单来说,umask 就是让你设置一个“权限过滤器”,决定了你新建的文件和目录默认有多“开放”。

典型应用场景

  • 用户自定义默认权限:用户可以通过 umask 命令设置自己的默认权限偏好。例如,设置 umask 077 可以让新建的文件和目录只有自己能访问,提高隐私性。
  • 程序设置安全默认值:编写程序时,可以在程序开始时调用 umask() 来设置一个安全的掩码,确保程序创建的临时文件等不会被其他用户意外访问。

2. 函数原型

#include <sys/stat.h> // 包含 umask 函数声明

// 设置文件权限掩码并返回旧的掩码
mode_t umask(mode_t mask);

3. 功能

设置调用进程(及其子进程)的文件权限创建掩码为 mask,并返回调用前的旧掩码。

4. 参数

  • mask:
    • mode_t 类型。
    • 指定新的文件权限掩码。这个值通常用八进制表示(以 0 开头,如 022077002)。
    • 掩码中的位为 1 表示对应的权限将被屏蔽(从默认权限中移除)。
    • 掩码中的位为 0 表示对应的权限不会被屏蔽(保留默认权限中的该位)。

5. 返回值

  • 总是返回调用 umask 之前的旧掩码。这使得程序可以临时改变掩码,用完后再恢复。

6. 权限计算方式

这是理解 umask 的关键:

  1. 确定默认权限
    • 新文件:默认权限是 666 (rw-rw-rw-)。
    • 新目录:默认权限是 777 (rwxrwxrwx)。
  2. 应用掩码:将默认权限与 umask 进行按位与非 (& ~) 操作。
    • 最终权限 = 默认权限 & (~ umask)

示例

  • umask 022:
    • 文件默认权限:666 (110 110 110)
    • umask:022 (000 010 010)
    • ~umask755 (111 101 101)
    • 文件最终权限:666 & 755 = 644 (rw-r–r–)
    • 目录默认权限:777 (111 111 111)
    • 目录最终权限:777 & 755 = 755 (rwxr-xr-x)
    • 效果:同组用户和其他用户失去了写权限。
  • umask 077:
    • 文件默认权限:666 (110 110 110)
    • umask:077 (000 111 111)
    • ~umask700 (111 000 000)
    • 文件最终权限:666 & 700 = 600 (rw——-)
    • 目录默认权限:777 (111 111 111)
    • 目录最终权限:777 & 700 = 700 (rwx——)
    • 效果:只有文件所有者有权限,同组和其他用户没有任何权限。这是非常私密的设置。
  • umask 002:
    • 文件默认权限:666 (110 110 110)
    • umask:002 (000 000 010)
    • ~umask775 (111 111 101)
    • 文件最终权限:666 & 775 = 664 (rw-rw-r–)
    • 目录默认权限:777 (111 111 111)
    • 目录最终权限:777 & 775 = 775 (rwxrwxr-x)
    • 效果:只有“其他人”失去了写权限,组内用户有完全权限。常用于协作环境。

7. 相似函数或关联函数

  • chmod: 用于更改已存在文件或目录的权限。
  • mkdir / open / creat: 这些创建文件或目录的函数会受到 umask 的影响。
  • umask shell 命令: 用于在 shell 中查看或设置当前 shell 会话的 umask 值。

8. 示例代码

下面的示例演示了如何在 C 程序中使用 umask() 函数来控制创建文件和目录的默认权限。

#define _GNU_SOURCE // 启用 GNU 扩展
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h> // 包含 umask, mkdir, stat
#include <fcntl.h>    // 包含 open, O_* flags
#include <string.h>
#include <errno.h>

// 辅助函数:将 mode_t 转换为字符串表示 (简化版)
void print_permissions(mode_t mode) {
    printf( (mode & S_IRUSR) ? "r" : "-");
    printf( (mode & S_IWUSR) ? "w" : "-");
    printf( (mode & S_IXUSR) ? "x" : "-");
    printf( (mode & S_IRGRP) ? "r" : "-");
    printf( (mode & S_IWGRP) ? "w" : "-");
    printf( (mode & S_IXGRP) ? "x" : "-");
    printf( (mode & S_IROTH) ? "r" : "-");
    printf( (mode & S_IWOTH) ? "w" : "-");
    printf( (mode & S_IXOTH) ? "x" : "-");
}

// 辅助函数:获取并打印文件/目录的权限
void check_permissions(const char* path) {
    struct stat sb;
    if (stat(path, &sb) == 0) {
        printf("Permissions for '%s': ", path);
        print_permissions(sb.st_mode);
        printf(" (%o)\n", sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
    } else {
        perror("stat");
    }
}

int main() {
    mode_t old_mask;
    int fd;

    printf("--- Demonstrating umask ---\n");
    printf("PID: %d\n", getpid());

    // 1. 查看当前的 umask 值
    // 通过设置 umask(0) 并立即恢复旧值来查询
    old_mask = umask(0);
    umask(old_mask); // 立即恢复
    printf("Initial umask: %03o\n", old_mask);

    // 2. 创建文件和目录,使用初始 umask
    printf("\n--- Creating files/dirs with initial umask ---\n");
    fd = open("file_with_initial_umask.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    if (fd != -1) close(fd);
    mkdir("dir_with_initial_umask", 0777);
    check_permissions("file_with_initial_umask.txt");
    check_permissions("dir_with_initial_umask");

    // 3. 改变 umask 为 077 (非常私密)
    printf("\n--- Changing umask to 077 ---\n");
    old_mask = umask(0077); // 返回旧的 umask
    printf("Old umask was: %03o\n", old_mask);
    printf("New umask is: 077\n");

    // 4. 再次创建文件和目录
    fd = open("file_with_umask_077.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    if (fd != -1) close(fd);
    mkdir("dir_with_umask_077", 0777);
    check_permissions("file_with_umask_077.txt");
    check_permissions("dir_with_umask_077");

    // 5. 改变 umask 为 002 (组协作)
    printf("\n--- Changing umask to 002 ---\n");
    old_mask = umask(0002);
    printf("Old umask was: %03o\n", old_mask);
    printf("New umask is: 002\n");

    // 6. 再次创建文件和目录
    fd = open("file_with_umask_002.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    if (fd != -1) close(fd);
    mkdir("dir_with_umask_002", 0777);
    check_permissions("file_with_umask_002.txt");
    check_permissions("dir_with_umask_002");

    // 7. 恢复原始 umask
    printf("\n--- Restoring original umask ---\n");
    umask(old_mask);
    printf("Restored umask to: %03o\n", old_mask);

    printf("\n--- Summary ---\n");
    printf("1. umask acts as a filter on default permissions (666 for files, 777 for dirs).\n");
    printf("2. Bits set to 1 in umask REMOVE the corresponding permission.\n");
    printf("3. umask 022: Owner has full access, Group/Others have read/execute (not write).\n");
    printf("4. umask 077: Only Owner has access (very private).\n");
    printf("5. umask 002: Owner/Group have full access, Others lack write (collaborative).\n");
    printf("6. The umask set in a program affects files/dirs it creates.\n");

    // 8. 清理 (可选)
    // unlink("file_with_initial_umask.txt");
    // rmdir("dir_with_initial_umask");
    // unlink("file_with_umask_077.txt");
    // rmdir("dir_with_umask_077");
    // unlink("file_with_umask_002.txt");
    // rmdir("dir_with_umask_002");

    return 0;
}

9. 编译和运行

# 假设代码保存在 umask_example.c 中
gcc -o umask_example umask_example.c

# 运行程序
./umask_example

10. 预期输出 (取决于你运行时的初始 umask)

假设你的初始 umask 是 022

--- Demonstrating umask ---
PID: 12345
Initial umask: 022

--- Creating files/dirs with initial umask ---
Permissions for 'file_with_initial_umask.txt': rw-r--r-- (644)
Permissions for 'dir_with_initial_umask': rwxr-xr-x (755)

--- Changing umask to 077 ---
Old umask was: 022
New umask is: 077
Permissions for 'file_with_umask_077.txt': rw------- (600)
Permissions for 'dir_with_umask_077': rwx------ (700)

--- Changing umask to 002 ---
Old umask was: 077
New umask is: 002
Permissions for 'file_with_umask_002.txt': rw-rw-r-- (664)
Permissions for 'dir_with_umask_002': rwxrwxr-x (775)

--- Restoring original umask ---
Restored umask to: 002

--- Summary ---
1. umask acts as a filter on default permissions (666 for files, 777 for dirs).
2. Bits set to 1 in umask REMOVE the corresponding permission.
3. umask 022: Owner has full access, Group/Others have read/execute (not write).
4. umask 077: Only Owner has access (very private).
5. umask 002: Owner/Group have full access, Others lack write (collaborative).
6. The umask set in a program affects files/dirs it creates.

11. 在 Shell 中使用 umask 命令

你也可以直接在终端中使用 umask 命令:

# 查看当前 umask
umask

# 设置 umask 为 077
umask 077

# 创建一个文件测试权限
touch test_file_umask_077.txt
ls -l test_file_umask_077.txt
# 输出类似:-rw------- 1 user user 0 date time test_file_umask_077.txt

# 恢复为常见的 022
umask 022
touch test_file_umask_022.txt
ls -l test_file_umask_022.txt
# 输出类似:-rw-r--r-- 1 user user 0 date time test_file_umask_022.txt

12. 总结

umask() 函数(以及 umask shell 命令)是 Linux 系统中控制新建文件和目录默认权限的重要工具。

  • 它通过一个“掩码”来过滤掉默认权限中的某些位。
  • 理解其计算方式(默认权限 & ~umask)是掌握它的关键。
  • 常见的 umask 值:
    • 022:最常见的默认值,保护文件不被同组和他人修改。
    • 077:最私密,只有所有者能访问。
    • 002:协作环境常用,保护文件不被他人修改,但同组用户有完全权限。
  • 在编写需要创建文件的程序时,合理设置 umask 可以增强程序的安全性。
  • 它只影响新创建的文件和目录,不影响已存在的文件。
发表在 linux文章 | 留下评论

umount2系统调用及示例

umount2 函数详解

1. 函数介绍

umount2 是Linux系统调用,用于卸载文件系统。它是 umount 函数的增强版本,支持更多的卸载选项和标志。通过 umount2,程序可以更精细地控制文件系统的卸载过程,包括强制卸载、延迟卸载等高级功能。

2. 函数原型

#include <sys/mount.h>
int umount2(const char *target, int flags);

3. 功能

umount2 卸载指定挂载点的文件系统,并支持多种卸载标志来控制卸载行为。它可以处理繁忙的文件系统、只读文件系统等情况,提供更灵活的卸载选项。

4. 参数

  • *const char target: 要卸载的文件系统挂载点路径
  • int flags: 卸载标志,控制卸载行为

5. 返回值

  • 成功: 返回0
  • 失败: 返回-1,并设置errno

6. 相似函数,或关联函数

  • umount: 基础卸载函数(等同于umount2(target, 0))
  • mount: 挂载文件系统
  • getmntent: 获取挂载信息
  • /proc/mounts: 挂载信息文件

7. 示例代码

示例1:基础umount2使用

#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

/**
 * 显示当前挂载信息
 */
void show_mount_info() {
    printf("=== 当前挂载信息 ===\n");
    system("cat /proc/mounts | head -10");  // 显示前10行挂载信息
    printf("\n");
}

/**
 * 创建测试挂载点
 */
int create_test_mountpoint(const char *mountpoint) {
    struct stat st;
    
    // 检查挂载点是否存在
    if (stat(mountpoint, &st) == 0) {
        printf("挂载点 %s 已存在\n", mountpoint);
        return 0;
    }
    
    // 创建挂载点目录
    if (mkdir(mountpoint, 0755) == -1) {
        perror("创建挂载点目录失败");
        return -1;
    }
    
    printf("创建挂载点: %s\n", mountpoint);
    return 0;
}

/**
 * 演示基础umount2使用方法
 */
int demo_umount2_basic() {
    const char *test_mountpoint = "/tmp/test_umount2";
    int result;
    
    printf("=== 基础umount2使用示例 ===\n");
    
    // 显示原始挂载信息
    printf("1. 原始挂载信息:\n");
    show_mount_info();
    
    // 创建测试挂载点
    printf("2. 创建测试挂载点:\n");
    if (create_test_mountpoint(test_mountpoint) != 0) {
        return -1;
    }
    
    // 尝试卸载不存在的挂载点(演示错误处理)
    printf("3. 尝试卸载不存在的挂载点:\n");
    printf("   卸载目标: %s\n", test_mountpoint);
    
    result = umount2(test_mountpoint, 0);
    if (result == -1) {
        printf("   ✓ 卸载失败(预期结果): %s\n", strerror(errno));
        if (errno == EINVAL) {
            printf("   原因:指定的挂载点不存在\n");
        } else if (errno == EPERM) {
            printf("   原因:权限不足\n");
        } else if (errno == EBUSY) {
            printf("   原因:挂载点正忙\n");
        }
    } else {
        printf("   ✗ 卸载意外成功\n");
    }
    
    // 演示不同卸载标志
    printf("\n4. 卸载标志说明:\n");
    printf("   0: 普通卸载\n");
    printf("   MNT_FORCE: 强制卸载\n");
    printf("   MNT_DETACH: 延迟卸载\n");
    printf("   MNT_EXPIRE: 标记为过期\n");
    
    // 清理测试挂载点
    printf("\n5. 清理测试挂载点:\n");
    if (rmdir(test_mountpoint) == 0) {
        printf("   ✓ 测试挂载点清理成功\n");
    } else {
        printf("   ✗ 测试挂载点清理失败: %s\n", strerror(errno));
    }
    
    return 0;
}

int main() {
    return demo_umount2_basic();
}

示例2:文件系统挂载和卸载管理

#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mntent.h>

/**
 * 挂载点管理器结构
 */
typedef struct {
    char mountpoint[256];
    char filesystem[32];
    char device[256];
    int is_mounted;
    unsigned long mount_options;
} mount_manager_t;

/**
 * 初始化挂载点管理器
 */
int init_mount_manager(mount_manager_t *manager, const char *mountpoint, 
                      const char *device, const char *filesystem) {
    strncpy(manager->mountpoint, mountpoint, sizeof(manager->mountpoint) - 1);
    manager->mountpoint[sizeof(manager->mountpoint) - 1] = '\0';
    
    strncpy(manager->device, device, sizeof(manager->device) - 1);
    manager->device[sizeof(manager->device) - 1] = '\0';
    
    strncpy(manager->filesystem, filesystem, sizeof(manager->filesystem) - 1);
    manager->filesystem[sizeof(manager->filesystem) - 1] = '\0';
    
    manager->is_mounted = 0;
    manager->mount_options = 0;
    
    printf("挂载点管理器初始化:\n");
    printf("  挂载点: %s\n", manager->mountpoint);
    printf("  设备: %s\n", manager->device);
    printf("  文件系统: %s\n", manager->filesystem);
    
    return 0;
}

/**
 * 检查挂载点是否存在
 */
int is_mountpoint_exists(const char *mountpoint) {
    FILE *fp = setmntent("/proc/mounts", "r");
    if (!fp) {
        return -1;
    }
    
    struct mntent *mnt;
    int exists = 0;
    
    while ((mnt = getmntent(fp)) != NULL) {
        if (strcmp(mnt->mnt_dir, mountpoint) == 0) {
            exists = 1;
            break;
        }
    }
    
    endmntent(fp);
    return exists;
}

/**
 * 挂载文件系统
 */
int mount_filesystem(mount_manager_t *manager) {
    // 创建挂载点
    struct stat st;
    if (stat(manager->mountpoint, &st) == -1) {
        if (mkdir(manager->mountpoint, 0755) == -1) {
            perror("创建挂载点失败");
            return -1;
        }
        printf("创建挂载点: %s\n", manager->mountpoint);
    }
    
    // 执行挂载
    printf("挂载文件系统:\n");
    printf("  设备: %s\n", manager->device);
    printf("  挂载点: %s\n", manager->mountpoint);
    printf("  文件系统: %s\n", manager->filesystem);
    
    // 注意:实际挂载需要root权限和有效设备
    // 这里仅演示调用方式
    printf("  注意:实际挂载需要root权限和有效设备\n");
    
    manager->is_mounted = 1;
    return 0;
}

/**
 * 卸载文件系统(使用umount2)
 */
int unmount_filesystem(mount_manager_t *manager, int flags) {
    printf("卸载文件系统:\n");
    printf("  挂载点: %s\n", manager->mountpoint);
    printf("  卸载标志: 0x%x\n", flags);
    
    // 检查挂载点是否存在
    if (!is_mountpoint_exists(manager->mountpoint)) {
        printf("  挂载点不存在,无需卸载\n");
        manager->is_mounted = 0;
        return 0;
    }
    
    // 执行卸载
    int result = umount2(manager->mountpoint, flags);
    if (result == 0) {
        printf("  ✓ 文件系统卸载成功\n");
        manager->is_mounted = 0;
        
        // 清理挂载点目录
        if (rmdir(manager->mountpoint) == 0) {
            printf("  ✓ 挂载点目录清理成功\n");
        } else {
            printf("  ✗ 挂载点目录清理失败: %s\n", strerror(errno));
        }
    } else {
        printf("  ✗ 文件系统卸载失败: %s\n", strerror(errno));
        if (errno == EBUSY) {
            printf("    原因:文件系统正忙\n");
        } else if (errno == EINVAL) {
            printf("    原因:无效的挂载点\n");
        } else if (errno == EPERM) {
            printf("    原因:权限不足\n");
        }
    }
    
    return result;
}

/**
 * 演示文件系统挂载和卸载管理
 */
int demo_filesystem_management() {
    mount_manager_t manager;
    const char *test_mountpoint = "/tmp/test_fs_manager";
    const char *test_device = "/dev/loop0";  // 示例设备
    const char *test_filesystem = "ext4";
    
    printf("=== 文件系统挂载和卸载管理演示 ===\n");
    
    // 初始化管理器
    printf("1. 初始化挂载点管理器:\n");
    if (init_mount_manager(&manager, test_mountpoint, test_device, test_filesystem) != 0) {
        return -1;
    }
    
    // 显示当前挂载状态
    printf("\n2. 当前挂载状态检查:\n");
    int exists = is_mountpoint_exists(manager.mountpoint);
    if (exists == 1) {
        printf("  挂载点已存在\n");
    } else if (exists == 0) {
        printf("  挂载点不存在\n");
    } else {
        printf("  无法检查挂载状态\n");
    }
    
    // 模拟挂载操作
    printf("\n3. 模拟挂载操作:\n");
    if (mount_filesystem(&manager) != 0) {
        printf("挂载操作失败\n");
        return -1;
    }
    
    // 演示不同卸载方式
    printf("\n4. 演示不同卸载方式:\n");
    
    // 方式1:普通卸载
    printf("  方式1:普通卸载 (MNT_UMOUNT):\n");
    unmount_filesystem(&manager, 0);
    
    // 方式2:强制卸载
    printf("\n  方式2:强制卸载 (MNT_FORCE):\n");
    unmount_filesystem(&manager, MNT_FORCE);
    
    // 方式3:延迟卸载
    printf("\n  方式3:延迟卸载 (MNT_DETACH):\n");
    unmount_filesystem(&manager, MNT_DETACH);
    
    // 方式4:过期卸载
    printf("\n  方式4:过期卸载 (MNT_EXPIRE):\n");
    unmount_filesystem(&manager, MNT_EXPIRE);
    
    // 显示最终状态
    printf("\n5. 最终状态:\n");
    printf("  挂载点状态: %s\n", manager.is_mounted ? "已挂载" : "未挂载");
    
    return 0;
}

int main() {
    return demo_filesystem_management();
}

示例3:安全卸载工具

#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mntent.h>
#include <signal.h>
#include <sys/wait.h>

/**
 * 安全卸载结果结构
 */
typedef struct {
    char mountpoint[256];
    int attempts;
    int success;
    int force_used;
    int detach_used;
    int final_status;
    char error_message[256];
} safe_unmount_result_t;

/**
 * 检查挂载点是否正在使用
 */
int is_mountpoint_busy(const char *mountpoint) {
    // 检查是否有进程在使用该挂载点
    char command[512];
    snprintf(command, sizeof(command), "lsof %s 2>/dev/null | wc -l", mountpoint);
    
    FILE *fp = popen(command, "r");
    if (fp) {
        char buffer[16];
        if (fgets(buffer, sizeof(buffer), fp)) {
            int count = atoi(buffer);
            pclose(fp);
            return count > 0;
        }
        pclose(fp);
    }
    
    return 0;  // 默认认为不忙
}

/**
 * 显示挂载点信息
 */
void show_mountpoint_info(const char *mountpoint) {
    FILE *fp = setmntent("/proc/mounts", "r");
    if (!fp) {
        printf("无法读取挂载信息\n");
        return;
    }
    
    struct mntent *mnt;
    printf("挂载点详细信息:\n");
    
    while ((mnt = getmntent(fp)) != NULL) {
        if (strcmp(mnt->mnt_dir, mountpoint) == 0) {
            printf("  设备: %s\n", mnt->mnt_fsname);
            printf("  挂载点: %s\n", mnt->mnt_dir);
            printf("  文件系统: %s\n", mnt->mnt_type);
            printf("  选项: %s\n", mnt->mnt_opts);
            break;
        }
    }
    
    endmntent(fp);
}

/**
 * 安全卸载文件系统
 */
int safe_unmount_filesystem(const char *mountpoint, safe_unmount_result_t *result) {
    int attempt = 0;
    const int max_attempts = 5;
    int result_code = 0;
    
    // 初始化结果结构
    strncpy(result->mountpoint, mountpoint, sizeof(result->mountpoint) - 1);
    result->mountpoint[sizeof(result->mountpoint) - 1] = '\0';
    result->attempts = 0;
    result->success = 0;
    result->force_used = 0;
    result->detach_used = 0;
    result->final_status = 0;
    result->error_message[0] = '\0';
    
    printf("=== 安全卸载文件系统 ===\n");
    printf("目标挂载点: %s\n", mountpoint);
    
    // 检查挂载点是否存在
    if (!is_mountpoint_exists(mountpoint)) {
        printf("挂载点不存在,无需卸载\n");
        result->success = 1;
        return 0;
    }
    
    // 显示挂载点信息
    show_mountpoint_info(mountpoint);
    
    // 检查挂载点是否正在使用
    printf("检查挂载点使用状态...\n");
    if (is_mountpoint_busy(mountpoint)) {
        printf("警告:挂载点正在使用中\n");
    } else {
        printf("挂载点当前未被使用\n");
    }
    
    // 尝试多次卸载
    while (attempt < max_attempts) {
        attempt++;
        result->attempts = attempt;
        printf("第 %d 次卸载尝试:\n", attempt);
        
        // 根据尝试次数选择不同的卸载策略
        int flags = 0;
        if (attempt > 1) {
            printf("  挂载点可能正忙,等待片刻...\n");
            sleep(1);
        }
        
        if (attempt == 2) {
            // 第二次尝试:发送SIGTERM给可能使用该挂载点的进程
            printf("  尝试通知使用该挂载点的进程...\n");
        } else if (attempt == 3) {
            flags = MNT_FORCE;  // 强制卸载
            result->force_used = 1;
            printf("  使用强制卸载模式\n");
        } else if (attempt == 4) {
            flags = 0;  // 再次尝试普通卸载
            printf("  再次尝试普通卸载\n");
        } else if (attempt == 5) {
            flags = MNT_DETACH;  // 延迟卸载
            result->detach_used = 1;
            printf("  使用延迟卸载模式\n");
        }
        
        // 执行卸载
        result_code = umount2(mountpoint, flags);
        if (result_code == 0) {
            printf("  ✓ 卸载成功\n");
            result->success = 1;
            result->final_status = 0;
            break;
        } else {
            printf("  ✗ 卸载失败: %s\n", strerror(errno));
            result->final_status = errno;
            strncpy(result->error_message, strerror(errno), sizeof(result->error_message) - 1);
            result->error_message[sizeof(result->error_message) - 1] = '\0';
            
            // 根据错误类型决定是否继续尝试
            if (errno == EINVAL) {
                printf("  无效的挂载点,停止尝试\n");
                break;
            } else if (errno == EPERM) {
                printf("  权限不足,停止尝试\n");
                break;
            }
        }
    }
    
    // 显示最终结果
    printf("\n=== 卸载结果 ===\n");
    printf("挂载点: %s\n", result->mountpoint);
    printf("尝试次数: %d\n", result->attempts);
    printf("卸载状态: %s\n", result->success ? "成功" : "失败");
    
    if (result->success) {
        printf("卸载方式: ");
        if (result->force_used) {
            printf("强制卸载\n");
        } else if (result->detach_used) {
            printf("延迟卸载\n");
        } else {
            printf("普通卸载\n");
        }
    } else {
        printf("失败原因: %s\n", result->error_message);
        printf("最终错误码: %d\n", result->final_status);
    }
    
    return result->success ? 0 : -1;
}

/**
 * 演示安全卸载工具
 */
int demo_safe_unmount_tool() {
    safe_unmount_result_t result;
    const char *test_mountpoint = "/mnt/test_safe_unmount";
    
    printf("=== 安全卸载工具演示 ===\n");
    
    // 检查权限
    uid_t uid = getuid();
    printf("权限检查:\n");
    printf("  当前用户ID: %d\n", uid);
    if (uid == 0) {
        printf("  ✓ 具有root权限\n");
    } else {
        printf("  ✗ 没有root权限,卸载操作可能失败\n");
        printf("  提示:文件系统卸载通常需要root权限\n");
    }
    
    // 显示当前挂载信息
    printf("\n当前挂载信息:\n");
    system("cat /proc/mounts | grep -E '(tmp|mnt)' | head -5");
    
    // 演示安全卸载
    printf("\n演示安全卸载:\n");
    printf("目标挂载点: %s\n", test_mountpoint);
    
    // 注意:实际演示中避免卸载真实的重要文件系统
    // 这里仅演示调用方式和错误处理
    
    // 模拟卸载不存在的挂载点
    printf("\n1. 卸载不存在的挂载点:\n");
    if (safe_unmount_filesystem(test_mountpoint, &result) != 0) {
        printf("卸载不存在的挂载点(预期失败)\n");
    }
    
    // 演示卸载过程中的错误处理
    printf("\n2. 卸载错误处理演示:\n");
    
    // 尝试卸载根目录(应该失败)
    printf("尝试卸载根目录:\n");
    safe_unmount_filesystem("/", &result);
    
    // 尝试卸载无效路径
    printf("\n尝试卸载无效路径:\n");
    safe_unmount_filesystem("/invalid/mount/point", &result);
    
    // 显示安全卸载建议
    printf("\n=== 安全卸载建议 ===\n");
    printf("1. 卸载前检查:\n");
    printf("   ✓ 确认具有足够权限\n");
    printf("   ✓ 检查挂载点是否存在\n");
    printf("   ✓ 确认没有进程使用该挂载点\n");
    printf("   ✓ 备份重要数据\n");
    
    printf("\n2. 卸载策略:\n");
    printf("   ✓ 首先尝试普通卸载\n");
    printf("   ✓ 失败后等待并重试\n");
    printf("   ✓ 必要时使用强制卸载\n");
    printf("   ✓ 最后考虑延迟卸载\n");
    
    printf("\n3. 错误处理:\n");
    printf("   ✓ 检查返回值和errno\n");
    printf("   ✓ 根据错误类型采取不同措施\n");
    printf("   ✓ 记录卸载操作日志\n");
    printf("   ✓ 提供友好的错误信息\n");
    
    printf("\n4. 安全考虑:\n");
    printf("   ✓ 避免强制卸载重要文件系统\n");
    printf("   ✓ 确保数据一致性\n");
    printf("   ✓ 监控卸载后的系统状态\n");
    printf("   ✓ 准备恢复方案\n");
    
    return 0;
}

int main() {
    return demo_safe_unmount_tool();
}

示例4:批量卸载管理器

#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mntent.h>
#include <fnmatch.h>

/**
 * 批量卸载条目结构
 */
typedef struct {
    char mountpoint[256];
    char filesystem[32];
    char device[256];
    int selected_for_unmount;
    int unmount_result;
    char result_message[128];
} batch_unmount_entry_t;

/**
 * 批量卸载管理器结构
 */
typedef struct {
    batch_unmount_entry_t entries[64];
    int entry_count;
    int selected_count;
    int successful_count;
    int failed_count;
} batch_unmount_manager_t;

/**
 * 初始化批量卸载管理器
 */
void init_batch_unmount_manager(batch_unmount_manager_t *manager) {
    memset(manager, 0, sizeof(batch_unmount_manager_t));
    printf("批量卸载管理器初始化完成\n");
}

/**
 * 从/proc/mounts加载挂载信息
 */
int load_mount_entries(batch_unmount_manager_t *manager) {
    FILE *fp = setmntent("/proc/mounts", "r");
    if (!fp) {
        printf("无法读取挂载信息: %s\n", strerror(errno));
        return -1;
    }
    
    struct mntent *mnt;
    int count = 0;
    
    printf("加载挂载信息:\n");
    
    while ((mnt = getmntent(fp)) != NULL && count < 64) {
        // 过滤系统挂载点
        if (strncmp(mnt->mnt_dir, "/proc", 5) == 0 ||
            strncmp(mnt->mnt_dir, "/sys", 4) == 0 ||
            strncmp(mnt->mnt_dir, "/dev", 4) == 0) {
            continue;  // 跳过系统挂载点
        }
        
        batch_unmount_entry_t *entry = &manager->entries[count];
        strncpy(entry->mountpoint, mnt->mnt_dir, sizeof(entry->mountpoint) - 1);
        entry->mountpoint[sizeof(entry->mountpoint) - 1] = '\0';
        
        strncpy(entry->filesystem, mnt->mnt_type, sizeof(entry->filesystem) - 1);
        entry->filesystem[sizeof(entry->filesystem) - 1] = '\0';
        
        strncpy(entry->device, mnt->mnt_fsname, sizeof(entry->device) - 1);
        entry->device[sizeof(entry->device) - 1] = '\0';
        
        entry->selected_for_unmount = 0;
        entry->unmount_result = 0;
        entry->result_message[0] = '\0';
        
        printf("  %s (%s on %s)\n", entry->mountpoint, entry->filesystem, entry->device);
        count++;
    }
    
    endmntent(fp);
    manager->entry_count = count;
    printf("共加载 %d 个挂载点\n", count);
    
    return 0;
}

/**
 * 根据模式选择挂载点
 */
int select_mountpoints_by_pattern(batch_unmount_manager_t *manager, const char *pattern) {
    int selected = 0;
    
    printf("根据模式选择挂载点: %s\n", pattern);
    
    for (int i = 0; i < manager->entry_count; i++) {
        batch_unmount_entry_t *entry = &manager->entries[i];
        
        if (fnmatch(pattern, entry->mountpoint, 0) == 0) {
            entry->selected_for_unmount = 1;
            selected++;
            printf("  选中: %s\n", entry->mountpoint);
        }
    }
    
    manager->selected_count = selected;
    printf("共选中 %d 个挂载点\n", selected);
    
    return selected;
}

/**
 * 执行批量卸载
 */
int execute_batch_unmount(batch_unmount_manager_t *manager, int flags) {
    printf("=== 执行批量卸载 ===\n");
    printf("卸载标志: 0x%x\n", flags);
    printf("选中挂载点数量: %d\n", manager->selected_count);
    
    manager->successful_count = 0;
    manager->failed_count = 0;
    
    for (int i = 0; i < manager->entry_count; i++) {
        batch_unmount_entry_t *entry = &manager->entries[i];
        
        if (!entry->selected_for_unmount) {
            continue;
        }
        
        printf("\n卸载 %s:\n", entry->mountpoint);
        
        // 执行卸载
        int result = umount2(entry->mountpoint, flags);
        entry->unmount_result = result;
        
        if (result == 0) {
            printf("  ✓ 卸载成功\n");
            manager->successful_count++;
            strncpy(entry->result_message, "成功", sizeof(entry->result_message) - 1);
        } else {
            printf("  ✗ 卸载失败: %s\n", strerror(errno));
            manager->failed_count++;
            strncpy(entry->result_message, strerror(errno), sizeof(entry->result_message) - 1);
            entry->result_message[sizeof(entry->result_message) - 1] = '\0';
        }
    }
    
    printf("\n=== 批量卸载结果 ===\n");
    printf("成功: %d\n", manager->successful_count);
    printf("失败: %d\n", manager->failed_count);
    printf("总计: %d\n", manager->successful_count + manager->failed_count);
    
    // 显示详细结果
    printf("\n详细结果:\n");
    for (int i = 0; i < manager->entry_count; i++) {
        batch_unmount_entry_t *entry = &manager->entries[i];
        if (entry->selected_for_unmount) {
            printf("  %s: %s (%s)\n", 
                   entry->mountpoint,
                   entry->unmount_result == 0 ? "✓" : "✗",
                   entry->result_message);
        }
    }
    
    return (manager->failed_count == 0) ? 0 : -1;
}

/**
 * 显示批量卸载摘要
 */
void show_batch_unmount_summary(const batch_unmount_manager_t *manager) {
    printf("=== 批量卸载摘要 ===\n");
    printf("总挂载点数: %d\n", manager->entry_count);
    printf("选中卸载数: %d\n", manager->selected_count);
    printf("成功卸载数: %d\n", manager->successful_count);
    printf("失败卸载数: %d\n", manager->failed_count);
    printf("成功率: %.1f%%\n", 
           manager->selected_count > 0 ? 
           (double)manager->successful_count / manager->selected_count * 100 : 0);
    
    if (manager->failed_count > 0) {
        printf("\n失败详情:\n");
        for (int i = 0; i < manager->entry_count; i++) {
            const batch_unmount_entry_t *entry = &manager->entries[i];
            if (entry->selected_for_unmount && entry->unmount_result != 0) {
                printf("  %s: %s\n", entry->mountpoint, entry->result_message);
            }
        }
    }
}

/**
 * 演示批量卸载管理器
 */
int demo_batch_unmount_manager() {
    batch_unmount_manager_t manager;
    
    printf("=== 批量卸载管理器演示 ===\n");
    
    // 初始化管理器
    printf("1. 初始化批量卸载管理器:\n");
    init_batch_unmount_manager(&manager);
    
    // 加载挂载信息
    printf("\n2. 加载挂载信息:\n");
    if (load_mount_entries(&manager) != 0) {
        printf("加载挂载信息失败\n");
        return -1;
    }
    
    // 显示可用的卸载选项
    printf("\n3. 可用挂载点:\n");
    for (int i = 0; i < manager.entry_count && i < 10; i++) {
        const batch_unmount_entry_t *entry = &manager.entries[i];
        printf("  %d. %s (%s)\n", i + 1, entry->mountpoint, entry->filesystem);
    }
    
    if (manager.entry_count > 10) {
        printf("  ... (还有 %d 个挂载点)\n", manager.entry_count - 10);
    }
    
    // 演示模式匹配选择
    printf("\n4. 模式匹配选择演示:\n");
    
    // 选择/tmp目录下的挂载点
    select_mountpoints_by_pattern(&manager, "/tmp/*");
    
    // 选择/media目录下的挂载点
    select_mountpoints_by_pattern(&manager, "/media/*");
    
    // 选择所有ext4文件系统
    printf("\n根据文件系统类型选择:\n");
    int ext4_selected = 0;
    for (int i = 0; i < manager.entry_count; i++) {
        batch_unmount_entry_t *entry = &manager.entries[i];
        if (strcmp(entry->filesystem, "ext4") == 0) {
            entry->selected_for_unmount = 1;
            ext4_selected++;
            printf("  选中ext4文件系统: %s\n", entry->mountpoint);
        }
    }
    printf("共选中 %d 个ext4文件系统\n", ext4_selected);
    
    // 显示选中结果
    printf("\n5. 选中挂载点列表:\n");
    for (int i = 0; i < manager.entry_count; i++) {
        const batch_unmount_entry_t *entry = &manager.entries[i];
        if (entry->selected_for_unmount) {
            printf("  %s (%s on %s)\n", 
                   entry->mountpoint, entry->filesystem, entry->device);
        }
    }
    
    // 演示不同卸载模式
    printf("\n6. 不同卸载模式演示:\n");
    
    // 模式1:普通卸载
    printf("模式1:普通卸载\n");
    printf("注意:实际演示中跳过真实卸载操作以避免影响系统\n");
    
    // 模式2:强制卸载
    printf("\n模式2:强制卸载\n");
    printf("卸载标志: MNT_FORCE (0x%x)\n", MNT_FORCE);
    
    // 模式3:延迟卸载
    printf("\n模式3:延迟卸载\n");
    printf("卸载标志: MNT_DETACH (0x%x)\n", MNT_DETACH);
    
    // 模式4:过期卸载
    printf("\n模式4:过期卸载\n");
    printf("卸载标志: MNT_EXPIRE (0x%x)\n", MNT_EXPIRE);
    
    // 显示批量卸载策略
    printf("\n=== 批量卸载策略 ===\n");
    printf("1. 选择策略:\n");
    printf("   ✓ 支持通配符模式匹配\n");
    printf("   ✓ 支持文件系统类型筛选\n");
    printf("   ✓ 支持设备类型筛选\n");
    printf("   ✓ 支持交互式选择\n");
    
    printf("\n2. 卸载策略:\n");
    printf("   ✓ 优先尝试普通卸载\n");
    printf("   ✓ 失败后尝试强制卸载\n");
    printf("   ✓ 最后考虑延迟卸载\n");
    printf("   ✓ 支持批量重试机制\n");
    
    printf("\n3. 错误处理:\n");
    printf("   ✓ 详细记录每个卸载操作结果\n");
    printf("   ✓ 提供失败原因分析\n");
    printf("   ✓ 支持部分成功处理\n");
    printf("   ✓ 生成卸载报告\n");
    
    printf("\n4. 安全考虑:\n");
    printf("   ✓ 避免卸载系统关键挂载点\n");
    printf("   ✓ 检查挂载点使用状态\n");
    printf("   ✓ 提供确认机制\n");
    printf("   ✓ 支持回滚操作\n");
    
    return 0;
}

int main() {
    return demo_batch_unmount_manager();
}

示例5:文件系统监控和管理

#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mntent.h>
#include <time.h>
#include <sys/statvfs.h>

/**
 * 文件系统统计信息结构
 */
typedef struct {
    char mountpoint[256];
    char filesystem[32];
    char device[256];
    unsigned long long total_size_kb;
    unsigned long long used_size_kb;
    unsigned long long available_size_kb;
    double usage_percent;
    time_t last_check_time;
    int is_mounted;
    int readonly;
} filesystem_stats_t;

/**
 * 文件系统监控器结构
 */
typedef struct {
    filesystem_stats_t filesystems[32];
    int fs_count;
    time_t last_update_time;
    int monitoring_enabled;
} fs_monitor_t;

/**
 * 更新文件系统统计信息
 */
int update_filesystem_stats(filesystem_stats_t *fs) {
    struct statvfs buf;
    
    if (statvfs(fs->mountpoint, &buf) != 0) {
        printf("获取文件系统统计信息失败: %s\n", strerror(errno));
        return -1;
    }
    
    // 计算空间使用情况
    unsigned long long block_size = buf.f_frsize ? buf.f_frsize : buf.f_bsize;
    fs->total_size_kb = (unsigned long long)buf.f_blocks * block_size / 1024;
    fs->available_size_kb = (unsigned long long)buf.f_bavail * block_size / 1024;
    fs->used_size_kb = fs->total_size_kb - (unsigned long long)buf.f_bfree * block_size / 1024;
    
    if (fs->total_size_kb > 0) {
        fs->usage_percent = (double)fs->used_size_kb / fs->total_size_kb * 100;
    } else {
        fs->usage_percent = 0.0;
    }
    
    fs->last_check_time = time(NULL);
    
    // 检查是否为只读
    fs->readonly = (buf.f_flag & ST_RDONLY) ? 1 : 0;
    
    return 0;
}

/**
 * 从/proc/mounts加载文件系统信息
 */
int load_filesystem_info(fs_monitor_t *monitor) {
    FILE *fp = setmntent("/proc/mounts", "r");
    if (!fp) {
        printf("无法读取挂载信息: %s\n", strerror(errno));
        return -1;
    }
    
    struct mntent *mnt;
    int count = 0;
    
    while ((mnt = getmntent(fp)) != NULL && count < 32) {
        // 跳过某些系统挂载点
        if (strncmp(mnt->mnt_dir, "/proc", 5) == 0 ||
            strncmp(mnt->mnt_dir, "/sys", 4) == 0 ||
            strncmp(mnt->mnt_dir, "/dev", 4) == 0) {
            continue;
        }
        
        filesystem_stats_t *fs = &monitor->filesystems[count];
        strncpy(fs->mountpoint, mnt->mnt_dir, sizeof(fs->mountpoint) - 1);
        fs->mountpoint[sizeof(fs->mountpoint) - 1] = '\0';
        
        strncpy(fs->filesystem, mnt->mnt_type, sizeof(fs->filesystem) - 1);
        fs->filesystem[sizeof(fs->filesystem) - 1] = '\0';
        
        strncpy(fs->device, mnt->mnt_fsname, sizeof(fs->device) - 1);
        fs->device[sizeof(fs->device) - 1] = '\0';
        
        fs->is_mounted = 1;
        
        // 更新统计信息
        update_filesystem_stats(fs);
        
        count++;
    }
    
    endmntent(fp);
    monitor->fs_count = count;
    monitor->last_update_time = time(NULL);
    
    printf("加载了 %d 个文件系统信息\n", count);
    return 0;
}

/**
 * 显示文件系统统计信息
 */
void show_filesystem_stats(const filesystem_stats_t *fs) {
    char time_str[64];
    strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&fs->last_check_time));
    
    printf("文件系统: %s\n", fs->mountpoint);
    printf("  设备: %s\n", fs->device);
    printf("  类型: %s\n", fs->filesystem);
    printf("  总空间: %.2f GB\n", fs->total_size_kb / (1024.0 * 1024.0));
    printf("  已用空间: %.2f GB (%.1f%%)\n", 
           fs->used_size_kb / (1024.0 * 1024.0), fs->usage_percent);
    printf("  可用空间: %.2f GB\n", fs->available_size_kb / (1024.0 * 1024.0));
    printf("  只读模式: %s\n", fs->readonly ? "是" : "否");
    printf("  最后检查: %s\n", time_str);
}

/**
 * 监控文件系统使用情况
 */
int monitor_filesystem_usage(fs_monitor_t *monitor, const char *mountpoint, double threshold) {
    for (int i = 0; i < monitor->fs_count; i++) {
        filesystem_stats_t *fs = &monitor->filesystems[i];
        
        if (strcmp(fs->mountpoint, mountpoint) == 0) {
            // 更新统计信息
            update_filesystem_stats(fs);
            
            printf("监控文件系统 %s:\n", mountpoint);
            show_filesystem_stats(fs);
            
            // 检查使用率阈值
            if (fs->usage_percent > threshold) {
                printf("⚠ 警告: 文件系统使用率过高 (%.1f%% > %.1f%%)\n", 
                       fs->usage_percent, threshold);
                
                // 根据使用率严重程度提供建议
                if (fs->usage_percent > 95) {
                    printf("  🚨 严重: 立即清理磁盘空间\n");
                } else if (fs->usage_percent > 90) {
                    printf("  ⚠ 警告: 尽快清理磁盘空间\n");
                } else if (fs->usage_percent > 80) {
                    printf("  ℹ 提示: 考虑清理磁盘空间\n");
                }
                
                return 1;  // 超过阈值
            } else {
                printf("✓ 文件系统使用率正常 (%.1f%%)\n", fs->usage_percent);
                return 0;  // 正常
            }
        }
    }
    
    printf("未找到指定的挂载点: %s\n", mountpoint);
    return -1;  // 未找到
}

/**
 * 演示文件系统监控和管理
 */
int demo_filesystem_monitoring() {
    fs_monitor_t monitor = {0};
    uid_t uid = getuid();
    
    printf("=== 文件系统监控和管理演示 ===\n");
    
    // 权限检查
    printf("权限检查:\n");
    printf("  当前用户ID: %d\n", uid);
    if (uid == 0) {
        printf("  ✓ 具有root权限\n");
    } else {
        printf("  ℹ 普通用户权限(部分功能可能受限)\n");
    }
    
    // 加载文件系统信息
    printf("\n1. 加载文件系统信息:\n");
    if (load_filesystem_info(&monitor) != 0) {
        printf("加载文件系统信息失败\n");
        return -1;
    }
    
    // 显示所有文件系统信息
    printf("\n2. 文件系统统计信息:\n");
    for (int i = 0; i < monitor.fs_count && i < 5; i++) {
        printf("\n文件系统 %d:\n", i + 1);
        show_filesystem_stats(&monitor.filesystems[i]);
    }
    
    if (monitor.fs_count > 5) {
        printf("\n... (还有 %d 个文件系统)\n", monitor.fs_count - 5);
    }
    
    // 演示使用率监控
    printf("\n3. 文件系统使用率监控演示:\n");
    
    // 监控各个文件系统
    for (int i = 0; i < monitor.fs_count && i < 3; i++) {
        filesystem_stats_t *fs = &monitor.filesystems[i];
        printf("\n监控 %s:\n", fs->mountpoint);
        
        // 不同阈值的监控
        monitor_filesystem_usage(&monitor, fs->mountpoint, 80.0);  // 警告阈值
        monitor_filesystem_usage(&monitor, fs->mountpoint, 90.0);  // 严重阈值
    }
    
    // 演示umount2在监控中的应用
    printf("\n4. umount2在监控中的应用:\n");
    
    // 模拟需要卸载的情况
    printf("模拟文件系统维护场景:\n");
    
    for (int i = 0; i < monitor.fs_count && i < 2; i++) {
        filesystem_stats_t *fs = &monitor.filesystems[i];
        printf("\n检查 %s 是否需要维护:\n", fs->mountpoint);
        
        // 检查使用率和只读状态
        if (fs->usage_percent > 95) {
            printf("  文件系统使用率过高 (%.1f%%)\n", fs->usage_percent);
            printf("  建议: 卸载后进行文件系统检查\n");
            
            // 演示不同卸载选项
            printf("  卸载选项:\n");
            printf("    1. 普通卸载: umount2(\"%s\", 0)\n", fs->mountpoint);
            printf("    2. 强制卸载: umount2(\"%s\", MNT_FORCE)\n", fs->mountpoint);
            printf("    3. 延迟卸载: umount2(\"%s\", MNT_DETACH)\n", fs->mountpoint);
        } else if (fs->readonly) {
            printf("  文件系统为只读模式\n");
            printf("  可能需要重新挂载为读写模式\n");
        } else {
            printf("  文件系统状态正常\n");
        }
    }
    
    // 显示监控策略和最佳实践
    printf("\n=== 文件系统监控策略 ===\n");
    printf("1. 监控频率:\n");
    printf("   ✓ 关键系统: 每分钟检查\n");
    printf("   ✓ 重要数据: 每5分钟检查\n");
    printf("   ✓ 一般用途: 每小时检查\n");
    
    printf("\n2. 阈值设置:\n");
    printf("   ✓ 警告阈值: 80%% 使用率\n");
    printf("   ✓ 严重阈值: 90%% 使用率\n");
    printf("   ✓ 紧急阈值: 95%% 使用率\n");
    
    printf("\n3. 响应策略:\n");
    printf("   ✓ 自动告警通知\n");
    printf("   ✓ 日志记录\n");
    printf("   ✓ 自动清理临时文件\n");
    printf("   ✓ 邮件/SMS通知\n");
    
    printf("\n4. umount2使用场景:\n");
    printf("   ✓ 系统维护时的安全卸载\n");
    printf("   ✓ 文件系统检查前的准备\n");
    printf("   ✓ 紧急情况下的强制卸载\n");
    printf("   ✓ 资源回收时的延迟卸载\n");
    
    // 显示安全考虑
    printf("\n=== 安全考虑 ===\n");
    printf("1. 权限管理:\n");
    printf("   ✓ 文件系统操作需要适当权限\n");
    printf("   ✓ 避免普通用户执行危险操作\n");
    printf("   ✓ 使用sudo进行权限提升\n");
    
    printf("\n2. 数据安全:\n");
    printf("   ✓ 卸载前确保数据已同步\n");
    printf("   ✓ 避免强制卸载重要数据\n");
    printf("   ✓ 备份重要文件系统\n");
    
    printf("\n3. 系统稳定性:\n");
    printf("   ✓ 避免卸载系统关键挂载点\n");
    printf("   ✓ 监控卸载操作的影响\n");
    printf("   ✓ 准备系统恢复方案\n");
    
    return 0;
}

int main() {
    return demo_filesystem_monitoring();
}

umount2 使用注意事项

系统要求:

  1. 内核版本: 支持umount2的Linux内核
  2. 权限要求: 通常需要root权限或适当的挂载权限
  3. 架构支持: 支持所有主流架构

卸载标志详解:

  1. 0: 普通卸载(默认行为)
  2. MNT_FORCE: 强制卸载(即使文件系统正忙)
  3. MNT_DETACH: 延迟卸载(立即返回,后台清理)
  4. MNT_EXPIRE: 标记为过期(如果未被使用则卸载)

错误处理:

  1. EBUSY: 文件系统正忙,无法卸载
  2. EINVAL: 无效的挂载点
  3. EPERM: 权限不足
  4. EACCES: 访问被拒绝
  5. ENOMEM: 内存不足

安全考虑:

  1. 权限验证: 确保具有足够的权限
  2. 挂载点验证: 验证挂载点的有效性
  3. 使用状态检查: 检查文件系统是否正在使用
  4. 数据同步: 确保数据已正确同步

最佳实践:

  1. 渐进式卸载: 优先尝试普通卸载,失败后再尝试强制卸载
  2. 状态检查: 卸载前后检查系统状态
  3. 日志记录: 记录所有卸载操作
  4. 错误恢复: 准备适当的错误恢复机制
  5. 用户通知: 及时通知用户操作结果

umount2标志详细说明

MNT_FORCE (1):

  • 功能: 强制卸载文件系统
  • 使用场景: 文件系统正忙时的紧急卸载
  • 风险: 可能导致数据丢失或文件系统损坏

MNT_DETACH (2):

  • 功能: 延迟卸载(懒卸载)
  • 使用场景: 立即返回,后台清理资源
  • 优势: 不阻塞调用进程

MNT_EXPIRE (4):

  • 功能: 标记挂载点为过期
  • 使用场景: 如果没有进程使用则卸载
  • 特点: 非阻塞操作

相关函数和工具

系统调用:

// 基础卸载函数
int umount(const char *target);

// 挂载函数
int mount(const char *source, const char *target,
          const char *filesystemtype, unsigned long mountflags,
          const void *data);

命令行工具:

# 普通卸载
umount /mnt/point

# 强制卸载
umount -f /mnt/point

# 延迟卸载
umount -l /mnt/point

# 查看挂载信息
cat /proc/mounts
mount | grep point

常见使用场景

1. 系统维护:

// 维护前安全卸载文件系统
umount2("/mnt/data", 0);

2. 紧急处理:

// 紧急情况下强制卸载
umount2("/mnt/critical", MNT_FORCE);

3. 资源管理:

// 延迟卸载以避免阻塞
umount2("/mnt/temp", MNT_DETACH);

4. 自动化脚本:

// 批量卸载操作
for (int i = 0; i < count; i++) {
    umount2(mountpoints[i], 0);
}

总结

umount2 是Linux系统中强大的文件系统卸载工具,提供了:

  1. 灵活的卸载选项: 支持普通、强制、延迟等多种卸载模式
  2. 完善的错误处理: 详细的错误码和错误信息
  3. 安全的卸载机制: 多种安全检查和保护措施
  4. 标准兼容性: 符合POSIX标准,广泛支持

通过合理使用 umount2,可以构建安全可靠的文件系统管理工具。在实际应用中,需要注意权限要求、错误处理和系统稳定性等关键问题,遵循最佳实践确保系统的安全和稳定运行。

发表在 linux文章 | 留下评论

uname系统调用及示例

uname – 获取系统信息

函数介绍

uname系统调用用于获取当前Linux系统的详细信息,包括内核名称、版本、硬件架构等。这些信息对于系统管理和程序兼容性检查非常有用。

函数原型

#include <sys/utsname.h>

int uname(struct utsname *buf);

功能

获取系统标识信息,包括内核名称、网络节点名、内核版本、硬件架构等。

参数

  • struct utsname *buf: 指向utsname结构体的指针,用于存储系统信息struct utsname { char sysname[]; // 系统名称 (如 "Linux") char nodename[]; // 网络节点名 (主机名) char release[]; // 内核发行版本 char version[]; // 内核版本 char machine[]; // 硬件架构 char domainname[]; // 域名 (NIS/YP) };

返回值

  • 成功时返回0
  • 失败时返回-1,并设置errno

相似函数

  • sysinfo(): 获取系统统计信息
  • 命令行uname工具

示例代码

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <errno.h>
#include <string.h>

int main() {
    struct utsname system_info;
    
    printf("=== Uname函数示例 ===\n");
    
    // 调用uname获取系统信息
    if (uname(&system_info) == -1) {
        perror("uname调用失败");
        exit(EXIT_FAILURE);
    }
    
    // 打印系统信息
    printf("系统名称 (sysname): %s\n", system_info.sysname);
    printf("网络节点名 (nodename): %s\n", system_info.nodename);
    printf("内核发行版本 (release): %s\n", system_info.release);
    printf("内核版本 (version): %s\n", system_info.version);
    printf("硬件架构 (machine): %s\n", system_info.machine);
    
    #ifdef _GNU_SOURCE
    printf("域名 (domainname): %s\n", system_info.domainname);
    #endif
    
    // 示例应用:根据系统类型执行不同操作
    printf("\n=== 实际应用示例 ===\n");
    
    // 检查操作系统类型
    if (strcmp(system_info.sysname, "Linux") == 0) {
        printf("检测到Linux系统\n");
    } else {
        printf("检测到其他系统: %s\n", system_info.sysname);
    }
    
    // 检查硬件架构
    if (strcmp(system_info.machine, "x86_64") == 0) {
        printf("运行在64位x86架构上\n");
    } else if (strcmp(system_info.machine, "aarch64") == 0) {
        printf("运行在64位ARM架构上\n");
    } else {
        printf("运行在%s架构上\n", system_info.machine);
    }
    
    // 检查内核版本(简单比较)
    printf("内核版本信息: %s\n", system_info.release);
    
    // 解析版本号示例
    int major, minor, patch;
    if (sscanf(system_info.release, "%d.%d.%d", &major, &minor, &patch) == 3) {
        printf("解析的内核版本: %d.%d.%d\n", major, minor, patch);
        
        // 根据内核版本做兼容性检查
        if (major >= 4) {
            printf("内核版本 >= 4.0,支持较新特性\n");
        } else {
            printf("内核版本较低,可能需要特殊处理\n");
        }
    }
    
    // 获取主机名
    printf("主机名: %s\n", system_info.nodename);
    
    return 0;
}

uname函数详解

1. 函数介绍

uname函数是Linux系统中用于获取系统信息的标准函数,它的名字来源于”Unix name”。这个函数就像系统的”身份证”一样,能够提供关于当前运行系统的详细信息,包括操作系统名称、版本、硬件架构等。

可以把uname想象成一个”系统信息查询员”,当你需要了解当前系统的基本信息时,它能够快速提供准确的答案。无论是在程序中需要根据系统类型执行不同逻辑,还是在调试时需要确认系统环境,uname都是一个非常实用的工具。

使用场景:

  • 程序的系统兼容性检查
  • 系统信息显示和日志记录
  • 根据系统类型执行特定代码
  • 系统管理和监控工具
  • 软件安装程序的环境检测

2. 函数原型

#include <sys/utsname.h>

int uname(struct utsname *buf);

3. 功能

uname函数的主要功能是获取当前系统的标识信息。它填充一个utsname结构体,其中包含以下系统信息:

  • 操作系统名称
  • 网络节点名称(主机名)
  • 操作系统发行版本
  • 操作系统版本
  • 硬件架构类型

4. 参数

  • buf: 系统信息缓冲区
    • 类型:struct utsname*
    • 含义:指向utsname结构体的指针,用于存储系统信息
    • 该结构体包含以下字段:
      • sysname[]: 操作系统名称
      • nodename[]: 网络节点名称(主机名)
      • release[]: 操作系统发行版本
      • version[]: 操作系统版本
      • machine[]: 硬件架构类型
      • domainname[]: 网络域名(某些系统支持)

5. 返回值

  • 成功: 返回0
  • 失败: 返回-1,并设置errno错误码
    • EFAULT:buf参数指向无效内存地址
    • EINVAL:参数无效(理论上不会发生)

6. 相似函数或关联函数

  • gethostname(): 获取主机名
  • sysconf(): 获取系统配置信息
  • getdomainname(): 获取网络域名
  • uname命令: 命令行下的uname工具
  • /proc/version: 系统版本信息文件
  • system(): 执行系统命令

7. 示例代码

示例1:基础uname使用 – 获取系统信息

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <string.h>
#include <errno.h>

int main() {
    struct utsname system_info;
    
    printf("=== 基础uname使用示例 ===\n");
    
    // 调用uname函数获取系统信息
    if (uname(&system_info) == -1) {
        perror("uname调用失败");
        exit(EXIT_FAILURE);
    }
    
    // 显示系统信息
    printf("系统信息:\n");
    printf("----------------------------\n");
    printf("操作系统名称: %s\n", system_info.sysname);
    printf("网络节点名:   %s\n", system_info.nodename);
    printf("内核发行版:   %s\n", system_info.release);
    printf("内核版本:     %s\n", system_info.version);
    printf("硬件架构:     %s\n", system_info.machine);
    
    // 如果支持域名信息
    #ifdef _GNU_SOURCE
    printf("网络域名:     %s\n", system_info.domainname);
    #endif
    
    printf("----------------------------\n");
    
    // 分析系统类型
    printf("\n系统类型分析:\n");
    if (strcmp(system_info.sysname, "Linux") == 0) {
        printf("✓ 这是一个Linux系统\n");
    } else if (strcmp(system_info.sysname, "Darwin") == 0) {
        printf("✓ 这是一个macOS系统\n");
    } else {
        printf("? 这是一个%s系统\n", system_info.sysname);
    }
    
    // 分析硬件架构
    printf("硬件架构分析:\n");
    if (strcmp(system_info.machine, "x86_64") == 0) {
        printf("✓ 64位x86架构\n");
    } else if (strcmp(system_info.machine, "i386") == 0 || 
               strcmp(system_info.machine, "i686") == 0) {
        printf("✓ 32位x86架构\n");
    } else if (strncmp(system_info.machine, "arm", 3) == 0) {
        printf("✓ ARM架构\n");
    } else if (strncmp(system_info.machine, "aarch64", 7) == 0) {
        printf("✓ 64位ARM架构\n");
    } else {
        printf("? %s架构\n", system_info.machine);
    }
    
    return 0;
}

示例2:详细的系统信息分析

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <string.h>
#include <ctype.h>

// 判断是否为Linux系统
int is_linux_system(const char* sysname) {
    return (strcmp(sysname, "Linux") == 0);
}

// 判断是否为64位系统
int is_64bit_system(const char* machine) {
    return (strcmp(machine, "x86_64") == 0 || 
            strcmp(machine, "aarch64") == 0 ||
            strcmp(machine, "ppc64") == 0 ||
            strcmp(machine, "s390x") == 0 ||
            strncmp(machine, "mips64", 6) == 0);
}

// 判断是否为ARM架构
int is_arm_architecture(const char* machine) {
    return (strncmp(machine, "arm", 3) == 0 || 
            strncmp(machine, "aarch64", 7) == 0);
}

// 分析内核版本
void analyze_kernel_version(const char* release) {
    printf("内核版本分析:\n");
    
    // Linux内核版本通常是 x.y.z 格式
    int major, minor, patch;
    if (sscanf(release, "%d.%d.%d", &major, &minor, &patch) == 3) {
        printf("  主版本号: %d\n", major);
        printf("  次版本号: %d\n", minor);
        printf("  修订版本: %d\n", patch);
        
        // 根据主版本号判断内核新旧
        if (major >= 5) {
            printf("  ✓ 现代Linux内核 (5.x 或更新)\n");
        } else if (major == 4) {
            printf("  ✓ 较新的Linux内核 (4.x)\n");
        } else if (major == 3) {
            printf("  ⚠ 较旧的Linux内核 (3.x)\n");
        } else {
            printf("  ⚠ 非常旧的Linux内核 (%d.x)\n", major);
        }
    } else {
        printf("  无法解析版本格式: %s\n", release);
    }
}

// 分析主机名
void analyze_hostname(const char* nodename) {
    printf("主机名分析:\n");
    printf("  主机名: %s\n", nodename);
    
    // 检查主机名长度
    size_t len = strlen(nodename);
    printf("  长度: %zu 字符\n", len);
    
    // 检查是否包含特殊字符
    int has_special = 0;
    for (size_t i = 0; i < len; i++) {
        if (!isalnum(nodename[i]) && nodename[i] != '-' && nodename[i] != '.') {
            has_special = 1;
            break;
        }
    }
    
    if (has_special) {
        printf("  ⚠ 主机名包含特殊字符\n");
    } else {
        printf("  ✓ 主机名格式规范\n");
    }
}

// 显示系统兼容性信息
void show_compatibility_info(const struct utsname* info) {
    printf("系统兼容性信息:\n");
    
    // 可执行文件格式
    if (is_64bit_system(info->machine)) {
        printf("  可执行格式: 64位 ELF\n");
    } else {
        printf("  可执行格式: 32位 ELF\n");
    }
    
    // 库兼容性
    if (is_linux_system(info->sysname)) {
        printf("  系统调用: Linux ABI\n");
    }
    
    // 字节序信息(通过架构推断)
    if (strcmp(info->machine, "x86_64") == 0 || 
        strcmp(info->machine, "i386") == 0) {
        printf("  字节序: 小端序 (Little Endian)\n");
    }
}

int main() {
    struct utsname system_info;
    
    printf("=== 详细系统信息分析 ===\n\n");
    
    // 获取系统信息
    if (uname(&system_info) == -1) {
        perror("uname调用失败");
        exit(EXIT_FAILURE);
    }
    
    // 基本信息显示
    printf("1. 基本系统信息:\n");
    printf("   操作系统: %s\n", system_info.sysname);
    printf("   主机名:   %s\n", system_info.nodename);
    printf("   内核版本: %s\n", system_info.release);
    printf("   构建版本: %s\n", system_info.version);
    printf("   硬件架构: %s\n", system_info.machine);
    
    // 详细分析
    printf("\n2. 详细分析:\n");
    analyze_hostname(system_info.nodename);
    printf("\n");
    analyze_kernel_version(system_info.release);
    printf("\n");
    show_compatibility_info(&system_info);
    
    // 系统分类
    printf("\n3. 系统分类:\n");
    if (is_linux_system(system_info.sysname)) {
        printf("   ✓ Linux系统家族\n");
        
        // 进一步分类Linux发行版(基于内核版本等信息)
        if (strstr(system_info.version, "Ubuntu")) {
            printf("   ✓ 可能是Ubuntu发行版\n");
        } else if (strstr(system_info.version, "Debian")) {
            printf("   ✓ 可能是Debian发行版\n");
        } else if (strstr(system_info.version, "CentOS") || 
                   strstr(system_info.version, "Red Hat")) {
            printf("   ✓ 可能是Red Hat系列发行版\n");
        } else {
            printf("   ✓ 其他Linux发行版\n");
        }
    }
    
    if (is_64bit_system(system_info.machine)) {
        printf("   ✓ 64位系统\n");
    } else {
        printf("   ✓ 32位系统\n");
    }
    
    if (is_arm_architecture(system_info.machine)) {
        printf("   ✓ ARM架构系统\n");
    }
    
    // 生成系统指纹(用于唯一标识)
    printf("\n4. 系统指纹:\n");
    printf("   指纹字符串: %s-%s-%s\n", 
           system_info.sysname, 
           system_info.release, 
           system_info.machine);
    
    // 应用场景示例
    printf("\n5. 应用场景适配:\n");
    
    // 根据系统类型决定编译选项
    if (is_linux_system(system_info.sysname)) {
        printf("   编译建议: 使用Linux特定优化\n");
    }
    
    // 根据架构决定二进制分发
    if (is_64bit_system(system_info.machine)) {
        printf("   分发建议: 提供64位版本\n");
    } else {
        printf("   分发建议: 提供32位版本\n");
    }
    
    if (is_arm_architecture(system_info.machine)) {
        printf("   优化建议: 针对ARM架构优化\n");
    }
    
    return 0;
}

示例3:系统信息比较和兼容性检查

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <string.h>
#include <time.h>

// 系统信息结构体
typedef struct {
    struct utsname info;
    time_t timestamp;
} system_snapshot_t;

// 保存系统快照
int save_system_snapshot(system_snapshot_t* snapshot) {
    if (uname(&snapshot->info) == -1) {
        return -1;
    }
    snapshot->timestamp = time(NULL);
    return 0;
}

// 比较两个系统快照
void compare_system_snapshots(const system_snapshot_t* snap1, 
                             const system_snapshot_t* snap2) {
    printf("=== 系统信息比较 ===\n");
    printf("快照1时间: %s", ctime(&snap1->timestamp));
    printf("快照2时间: %s", ctime(&snap2->timestamp));
    
    printf("比较结果:\n");
    
    // 比较操作系统名称
    if (strcmp(snap1->info.sysname, snap2->info.sysname) == 0) {
        printf("✓ 操作系统名称相同: %s\n", snap1->info.sysname);
    } else {
        printf("✗ 操作系统名称不同: %s vs %s\n", 
               snap1->info.sysname, snap2->info.sysname);
    }
    
    // 比较主机名
    if (strcmp(snap1->info.nodename, snap2->info.nodename) == 0) {
        printf("✓ 主机名相同: %s\n", snap1->info.nodename);
    } else {
        printf("⚠ 主机名不同: %s vs %s\n", 
               snap1->info.nodename, snap2->info.nodename);
    }
    
    // 比较内核版本
    if (strcmp(snap1->info.release, snap2->info.release) == 0) {
        printf("✓ 内核版本相同: %s\n", snap1->info.release);
    } else {
        printf("⚠ 内核版本不同: %s vs %s\n", 
               snap1->info.release, snap2->info.release);
    }
    
    // 比较硬件架构
    if (strcmp(snap1->info.machine, snap2->info.machine) == 0) {
        printf("✓ 硬件架构相同: %s\n", snap1->info.machine);
    } else {
        printf("✗ 硬件架构不同: %s vs %s\n", 
               snap1->info.machine, snap2->info.machine);
    }
}

// 检查系统兼容性
int check_system_compatibility(const struct utsname* info) {
    printf("=== 系统兼容性检查 ===\n");
    int compatible = 1;
    
    // 检查操作系统
    if (strcmp(info->sysname, "Linux") != 0) {
        printf("✗ 不支持的操作系统: %s\n", info->sysname);
        compatible = 0;
    } else {
        printf("✓ 支持的操作系统: %s\n", info->sysname);
    }
    
    // 检查内核版本(假设需要3.0以上)
    int major, minor;
    if (sscanf(info->release, "%d.%d", &major, &minor) >= 2) {
        if (major >= 3) {
            printf("✓ 支持的内核版本: %s\n", info->release);
        } else {
            printf("✗ 内核版本过低: %s (需要3.0+)\n", info->release);
            compatible = 0;
        }
    } else {
        printf("? 无法确定内核版本格式\n");
    }
    
    // 检查硬件架构(假设支持x86_64和ARM64)
    if (strcmp(info->machine, "x86_64") == 0 || 
        strcmp(info->machine, "aarch64") == 0) {
        printf("✓ 支持的硬件架构: %s\n", info->machine);
    } else {
        printf("⚠ 可能不支持的硬件架构: %s\n", info->machine);
        // 这里可以根据需要决定是否标记为不兼容
    }
    
    return compatible;
}

// 生成系统报告
void generate_system_report(const struct utsname* info) {
    printf("\n=== 系统详细报告 ===\n");
    
    // 基本信息
    printf("【基本信息】\n");
    printf("  操作系统: %s\n", info->sysname);
    printf("  主机名称: %s\n", info->nodename);
    printf("  硬件架构: %s\n", info->machine);
    
    // 内核信息
    printf("【内核信息】\n");
    printf("  发行版本: %s\n", info->release);
    printf("  构建信息: %s\n", info->version);
    
    // 系统特征
    printf("【系统特征】\n");
    
    // 架构特征
    if (strcmp(info->machine, "x86_64") == 0) {
        printf("  架构类型: 64位Intel/AMD x86\n");
        printf("  指令集: 支持SSE, AVX等扩展指令\n");
    } else if (strcmp(info->machine, "aarch64") == 0) {
        printf("  架构类型: 64位ARM\n");
        printf("  指令集: ARMv8-A架构\n");
    } else if (strncmp(info->machine, "arm", 3) == 0) {
        printf("  架构类型: 32位ARM\n");
        printf("  指令集: ARM架构\n");
    } else {
        printf("  架构类型: %s\n", info->machine);
    }
    
    // 操作系统特征
    if (strcmp(info->sysname, "Linux") == 0) {
        printf("  系统类型: 类Unix操作系统\n");
        printf("  系统调用: POSIX兼容\n");
        printf("  文件系统: 支持ext4, xfs, btrfs等\n");
    }
    
    // 版本特征
    printf("【版本特征】\n");
    if (strstr(info->version, "Ubuntu")) {
        printf("  发行版: Ubuntu系列\n");
    } else if (strstr(info->version, "Debian")) {
        printf("  发行版: Debian系列\n");
    } else if (strstr(info->version, "CentOS") || 
               strstr(info->version, "Red Hat")) {
        printf("  发行版: Red Hat系列\n");
    } else if (strstr(info->version, "SUSE")) {
        printf("  发行版: SUSE系列\n");
    }
    
    // 安全特征
    printf("【安全特征】\n");
    printf("  用户权限: 支持多用户权限管理\n");
    printf("  进程隔离: 支持进程间隔离\n");
    printf("  内存保护: 支持内存保护机制\n");
}

int main() {
    struct utsname current_info;
    system_snapshot_t snapshot1, snapshot2;
    
    printf("=== 系统信息综合应用示例 ===\n\n");
    
    // 获取当前系统信息
    if (uname(&current_info) == -1) {
        perror("uname调用失败");
        exit(EXIT_FAILURE);
    }
    
    // 保存快照
    if (save_system_snapshot(&snapshot1) == -1) {
        perror("保存快照1失败");
        exit(EXIT_FAILURE);
    }
    
    printf("1. 当前系统信息:\n");
    printf("   操作系统: %s\n", current_info.sysname);
    printf("   内核版本: %s\n", current_info.release);
    printf("   硬件架构: %s\n", current_info.machine);
    
    // 模拟系统变化(实际中可能需要等待系统更新)
    sleep(1);
    
    if (save_system_snapshot(&snapshot2) == -1) {
        perror("保存快照2失败");
        exit(EXIT_FAILURE);
    }
    
    // 比较快照
    printf("\n2. 系统快照比较:\n");
    compare_system_snapshots(&snapshot1, &snapshot2);
    
    // 兼容性检查
    printf("\n3. 系统兼容性检查:\n");
    int compatible = check_system_compatibility(&current_info);
    if (compatible) {
        printf("✓ 系统兼容性检查通过\n");
    } else {
        printf("✗ 系统兼容性检查未通过\n");
    }
    
    // 生成详细报告
    printf("\n4. 生成系统详细报告:\n");
    generate_system_report(&current_info);
    
    // 应用场景演示
    printf("\n5. 应用场景演示:\n");
    
    // 根据系统信息选择不同的处理逻辑
    if (strcmp(current_info.sysname, "Linux") == 0) {
        printf("   执行Linux特定代码路径\n");
        
        // 根据架构选择优化
        if (strcmp(current_info.machine, "x86_64") == 0) {
            printf("   启用x86_64优化选项\n");
        } else if (strcmp(current_info.machine, "aarch64") == 0) {
            printf("   启用ARM64优化选项\n");
        }
        
        // 根据内核版本启用特性
        int major, minor;
        if (sscanf(current_info.release, "%d.%d", &major, &minor) >= 2) {
            if (major >= 4) {
                printf("   启用现代内核特性\n");
            }
        }
    }
    
    printf("\n=== 演示完成 ===\n");
    
    return 0;
}

示例4:跨平台系统信息工具

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <string.h>
#include <time.h>

#ifdef __APPLE__
#include <sys/sysctl.h>
#endif

// 系统信息结构体
typedef struct {
    char os_name[256];
    char hostname[256];
    char kernel_version[256];
    char architecture[256];
    char distribution[256];
    long uptime_seconds;
    int cpu_count;
} extended_system_info_t;

// 获取扩展系统信息
int get_extended_system_info(extended_system_info_t* info) {
    struct utsname basic_info;
    
    // 获取基本系统信息
    if (uname(&basic_info) == -1) {
        return -1;
    }
    
    // 复制基本信息
    strncpy(info->os_name, basic_info.sysname, sizeof(info->os_name) - 1);
    strncpy(info->hostname, basic_info.nodename, sizeof(info->hostname) - 1);
    strncpy(info->kernel_version, basic_info.release, sizeof(info->kernel_version) - 1);
    strncpy(info->architecture, basic_info.machine, sizeof(info->architecture) - 1);
    
    // 初始化其他字段
    strcpy(info->distribution, "Unknown");
    info->uptime_seconds = 0;
    info->cpu_count = 1;
    
    // 根据不同系统获取额外信息
    if (strcmp(basic_info.sysname, "Linux") == 0) {
        // Linux系统特有信息
        
        // 尝试读取发行版信息
        FILE* fp = fopen("/etc/os-release", "r");
        if (fp) {
            char line[256];
            while (fgets(line, sizeof(line), fp)) {
                if (strncmp(line, "PRETTY_NAME=", 12) == 0) {
                    char* start = strchr(line, '"');
                    if (start) {
                        char* end = strchr(start + 1, '"');
                        if (end) {
                            *end = '\0';
                            strncpy(info->distribution, start + 1, sizeof(info->distribution) - 1);
                            break;
                        }
                    }
                }
            }
            fclose(fp);
        }
        
        // 获取系统运行时间
        fp = fopen("/proc/uptime", "r");
        if (fp) {
            double uptime;
            if (fscanf(fp, "%lf", &uptime) == 1) {
                info->uptime_seconds = (long)uptime;
            }
            fclose(fp);
        }
        
        // 获取CPU数量
        fp = fopen("/proc/cpuinfo", "r");
        if (fp) {
            char line[256];
            int cpu_count = 0;
            while (fgets(line, sizeof(line), fp)) {
                if (strncmp(line, "processor", 9) == 0) {
                    cpu_count++;
                }
            }
            if (cpu_count > 0) {
                info->cpu_count = cpu_count;
            }
            fclose(fp);
        }
        
    } 
#ifdef __APPLE__
    else if (strcmp(basic_info.sysname, "Darwin") == 0) {
        // macOS系统特有信息
        strcpy(info->distribution, "macOS");
        
        // 获取CPU数量
        int mib[2] = {CTL_HW, HW_NCPU};
        size_t len = sizeof(info->cpu_count);
        sysctl(mib, 2, &info->cpu_count, &len, NULL, 0);
    }
#endif
    
    return 0;
}

// 格式化显示时间
void format_uptime(long seconds, char* buffer, size_t buffer_size) {
    long days = seconds / 86400;
    long hours = (seconds % 86400) / 3600;
    long minutes = (seconds % 3600) / 60;
    
    if (days > 0) {
        snprintf(buffer, buffer_size, "%ld天 %ld小时 %ld分钟", days, hours, minutes);
    } else if (hours > 0) {
        snprintf(buffer, buffer_size, "%ld小时 %ld分钟", hours, minutes);
    } else {
        snprintf(buffer, buffer_size, "%ld分钟", minutes);
    }
}

// 显示系统信息
void display_system_info(const extended_system_info_t* info) {
    printf("╔══════════════════════════════════════════════════════════════╗\n");
    printf("║                    系统信息报告                              ║\n");
    printf("╠══════════════════════════════════════════════════════════════╣\n");
    printf("║ 操作系统: %-48s ║\n", info->os_name);
    printf("║ 主机名称: %-48s ║\n", info->hostname);
    printf("║ 内核版本: %-48s ║\n", info->kernel_version);
    printf("║ 硬件架构: %-48s ║\n", info->architecture);
    printf("║ 发行版本: %-48s ║\n", info->distribution);
    
    // 显示系统运行时间
    if (info->uptime_seconds > 0) {
        char uptime_str[64];
        format_uptime(info->uptime_seconds, uptime_str, sizeof(uptime_str));
        printf("║ 运行时间: %-48s ║\n", uptime_str);
    }
    
    printf("║ CPU核心数: %-47d ║\n", info->cpu_count);
    printf("╚══════════════════════════════════════════════════════════════╝\n");
}

// 生成JSON格式的系统信息
void generate_json_info(const extended_system_info_t* info) {
    printf("\nJSON格式系统信息:\n");
    printf("{\n");
    printf("  \"os_name\": \"%s\",\n", info->os_name);
    printf("  \"hostname\": \"%s\",\n", info->hostname);
    printf("  \"kernel_version\": \"%s\",\n", info->kernel_version);
    printf("  \"architecture\": \"%s\",\n", info->architecture);
    printf("  \"distribution\": \"%s\",\n", info->distribution);
    printf("  \"uptime_seconds\": %ld,\n", info->uptime_seconds);
    printf("  \"cpu_count\": %d\n", info->cpu_count);
    printf("}\n");
}

// 系统健康检查
void system_health_check(const extended_system_info_t* info) {
    printf("\n系统健康检查:\n");
    printf("----------------\n");
    
    // 检查系统类型
    if (strcmp(info->os_name, "Linux") == 0) {
        printf("✓ Linux系统环境\n");
    } else {
        printf("ℹ 非Linux系统: %s\n", info->os_name);
    }
    
    // 检查架构
    if (strcmp(info->architecture, "x86_64") == 0) {
        printf("✓ 64位x86架构\n");
    } else if (strcmp(info->architecture, "aarch64") == 0) {
        printf("✓ 64位ARM架构\n");
    } else {
        printf("ℹ 其他架构: %s\n", info->architecture);
    }
    
    // 检查CPU数量
    if (info->cpu_count >= 4) {
        printf("✓ 多核心系统 (%d核心)\n", info->cpu_count);
    } else if (info->cpu_count >= 2) {
        printf("✓ 双核心系统\n");
    } else {
        printf("ℹ 单核心系统\n");
    }
    
    // 检查运行时间
    if (info->uptime_seconds > 0) {
        if (info->uptime_seconds > 86400) {  // 超过一天
            printf("✓ 系统稳定运行中\n");
        } else {
            printf("ℹ 系统运行时间较短\n");
        }
    }
}

int main() {
    extended_system_info_t sys_info;
    
    printf("=== 跨平台系统信息工具 ===\n\n");
    
    // 获取扩展系统信息
    if (get_extended_system_info(&sys_info) == -1) {
        perror("获取系统信息失败");
        exit(EXIT_FAILURE);
    }
    
    // 显示系统信息
    display_system_info(&sys_info);
    
    // 系统健康检查
    system_health_check(&sys_info);
    
    // 生成JSON格式信息
    generate_json_info(&sys_info);
    
    // 应用场景示例
    printf("\n应用场景适配:\n");
    printf("----------------\n");
    
    // 根据系统类型选择不同的处理
    if (strcmp(sys_info.os_name, "Linux") == 0) {
        printf("→ 启用Linux优化模式\n");
        
        // 根据发行版调整配置
        if (strstr(sys_info.distribution, "Ubuntu")) {
            printf("→ 应用Ubuntu特定配置\n");
        } else if (strstr(sys_info.distribution, "CentOS") || 
                   strstr(sys_info.distribution, "Red Hat")) {
            printf("→ 应用Red Hat特定配置\n");
        }
        
    } else if (strcmp(sys_info.os_name, "Darwin") == 0) {
        printf("→ 启用macOS优化模式\n");
    } else {
        printf("→ 使用通用配置\n");
    }
    
    // 根据CPU数量调整并行度
    printf("→ 建议并行任务数: %d\n", sys_info.cpu_count);
    
    printf("\n=== 工具执行完成 ===\n");
    
    return 0;
}

编译和运行

# 编译示例1
gcc -o uname_example1 uname_example1.c
./uname_example1

# 编译示例2
gcc -o uname_example2 uname_example2.c
./uname_example2

# 编译示例3
gcc -o uname_example3 uname_example3.c
./uname_example3

# 编译示例4
gcc -o uname_example4 uname_example4.c
./uname_example4

重要注意事项

  1. 结构体大小utsname结构体的大小在不同系统中可能不同
  2. 域名支持domainname字段不是所有系统都支持
  3. 权限要求: 通常不需要特殊权限即可调用
  4. 线程安全: uname函数是线程安全的
  5. 错误处理: 失败时主要返回EFAULT错误
  6. 字符编码: 返回的字符串通常是ASCII编码
  7. 缓冲区: 传入的结构体必须由调用者分配

常见应用场景

  1. 系统兼容性检测: 程序启动时检查运行环境
  2. 日志记录: 在日志中记录系统环境信息
  3. 调试信息: 帮助开发者了解运行环境
  4. 配置管理: 根据系统类型选择不同配置
  5. 性能优化: 根据硬件架构选择优化策略

通过这些示例,你可以理解uname函数在获取系统信息方面的强大功能,它为程序提供了识别和适应不同运行环境的能力。

发表在 linux文章 | 留下评论