Back to docs

Technical note

AI system

操作系统的四大模块包括内存管理、进程管理、文件系统管理和输入输出设备管理。每周进行一个CSAPP实验,推荐观看中文视频以节省时间。学习资源包括CSAPP、MIT的操作系统工程和计算机网络课程,以及分布式系统的相关课程。

工作
AI system
操作系统:MIT 6.S081: Operating System Engineering

M1: 打印进程树 (pstree)-拉了

#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <ctype.h>
#include <string.h>

/* 进程信息结构体:从 /proc/<pid>/status 中提取的三个字段 */
typedef struct{
  char name[32];  /* 进程名,来自 status 的 Name: 字段 */
  pid_t pid;      /* 进程 ID */
  pid_t ppid;     /* 父进程 ID,来自 status 的 PPid: 字段 */
}proc;

/**
 * print_tree - 递归打印进程树(默认模式,不排序)
 * @parent_pid: 当前要打印其子进程的父 PID
 * @procs:      所有进程信息的数组
 * @count:      进程总数
 * @level:      当前递归深度(用于缩进)
 *
 * 遍历全局进程数组,找出 ppid == parent_pid 的所有子进程,
 * 按在 /proc 中发现的顺序打印,然后递归到每个子进程。
 */
void print_tree(pid_t parent_pid, proc *procs,int count,int level){
  for(int i = 0; i <count;i++){
    if(procs[i].ppid == parent_pid){
      for(int j = 0; j < level; j++){
        printf("--");
      }
      printf("%s(%d)\n",procs[i].name,procs[i].pid);
      print_tree(procs[i].pid,procs,count,level+1);
    }
  }
}

/* qsort 比较函数:按 pid 升序排列 */
int cmp_pid(const void *a, const void *b) {
        const proc *pa = a;
        const proc *pb = b;
        return pa->pid - pb->pid;
}

/**
 * print_tree_s - 递归打印进程树(排序模式)
 * @parent_pid: 当前要打印其子进程的父 PID
 * @procs:      所有进程信息的数组
 * @count:      进程总数
 * @level:      当前递归深度(用于缩进)
 * @mode:       输出模式:0 = 只显示名字,1 = 显示名字(PID)
 *
 * 与 print_tree 不同:先收集当前父进程的所有子进程到临时数组,
 * 按 pid 排序后再打印,保证同层子进程输出顺序固定。
 */
void print_tree_s(pid_t parent_pid, proc *procs,int count,int level,int mode){
  int size_temp = count/2;           /* 临时数组上限:一个父进程的子进程数不会超过总进程数的一半 */
  proc temp[size_temp];
  int idx = 0;                       /* 实际找到的子进程数 */
  for(int i = 0; i <count;i++){
    if(procs[i].ppid == parent_pid){
      temp[idx++] = procs[i];
    }
  }
  qsort(temp,idx, sizeof(proc), cmp_pid);  /* 按 pid 排序当前层 */
  if(mode == 0){
    for(int i = 0; i < idx; i++){
      for(int j = 0; j < level; j++){
        printf("--");
      }
      printf("%s\n",temp[i].name);         /* 只输出进程名 */
      print_tree_s(temp[i].pid,procs,count,level+1,mode);
    }
  }
  if(mode == 1){
    for(int i = 0; i < idx; i++){
      for(int j = 0; j < level; j++){
          printf("--");
        }
        printf("%s(%d)\n",temp[i].name,procs[i].pid);  /* 输出 名字(PID) */
        print_tree_s(temp[i].pid,procs,count,level+1,mode);
      }
  }
}

int main(int argc, char *argv[]) {
  /* 调试输出:打印所有命令行参数(用于开发时确认参数解析) */
  for (int i = 0; i < argc; i++) {
    assert(argv[i]);
    printf("argv[%d] = %s\n", i, argv[i]);
  }
  assert(!argv[argc]);                 /* 验证 argv 以 NULL 结尾 */

  /* 动态数组:存储所有进程的信息 */
  proc *procs = (proc *)malloc(256*sizeof(proc));
  int count = 0;                       /* 已收集的进程数 */
  int capacity = 256;                  /* 当前数组容量 */

  /* 遍历 /proc 目录,枚举所有进程 */
  DIR *dir = opendir("/proc");
  assert(dir);
  struct dirent *entry;
  if(dir==NULL) {                      /* opendir 失败时退出(assert 已保证不触发) */
    perror("opendir");
    exit(EXIT_FAILURE);
  }

  while ((entry = readdir(dir)) != NULL) {
    if(isdigit(entry->d_name[0])) {    /* /proc 下数字开头的 entry 即为进程目录 */

      count++;
      if(count > capacity) {           /* 数组扩容(翻倍) */
        capacity *= 2;
        procs = realloc(procs, capacity * sizeof(proc));
      }

      /* 构造 /proc/<pid>/status 路径并打开 */
      char path[4096];
      snprintf(path, sizeof(path), "/proc/%s/status", entry->d_name);
      FILE *status_file = fopen(path, "r");

      if (status_file) {
        char name[32] = {0};
        pid_t ppid = -1;
        char line[256];
        /* 逐行扫描 status 文件,提取 Name 和 PPid */
        while (fgets(line, sizeof(line), status_file)) {
        if (ppid == -1) sscanf(line, "PPid:\t%d", &ppid);      /* 未拿到 PPid 时尝试匹配 */
        if (name[0] == '\0') sscanf(line, "Name:\t%31s", name); /* 未拿到 Name 时尝试匹配 */
        if (ppid != -1 && name[0] != '\0') break;               /* 两个字段都拿到了,提前结束 */
        }
        /* 填充 proc 结构体 */
        procs[count-1].pid = atoi(entry->d_name);
        procs[count-1].ppid = ppid;
        strncpy(procs[count-1].name, name, 31);  /* 复制名字,最多 31 字符 */
        procs[count-1].name[31] = '\0';           /* 确保以 \0 结尾 */

        fclose(status_file);
      } 
      else {
        perror("fopen");
        exit(EXIT_FAILURE);
      }
    }
  }

  /* 解析命令行参数 —— 线性扫描,设置对应的标志位 */
  int show_pid = 0;        /* -p / --show-pids:显示 PID */
  int numeric_sort = 0;    /* -n / --numeric-sort:按 pid 排序输出 */

    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
            printf("老铁666\n");
            return 0;                          /* -V 优先级最高:打印后立即退出 */
        }
        if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--show-pids") == 0) {
            show_pid = 1;
        }
        if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--numeric-sort") == 0) {
            numeric_sort = 1;
        }
    }

    /* 根据标志位组合选择打印策略 */
    printf("systemd(1)\n");
    if (show_pid && numeric_sort)
        print_tree_s(1, procs, count, 1, 1);   /* 显示 PID + 排序 */
    else if (numeric_sort)
        print_tree_s(1, procs, count, 1, 0);   /* 排序但不显示 PID */
    else if (show_pid)
        print_tree(1, procs, count, 1);        /* 显示 PID 但不排序 */
    else
        print_tree(1, procs, count, 1);        /* 默认:显示 PID 但不排序 */

  
  closedir(dir);
  free(procs);
  return 0;
}
计算机网络:USTC Computer Networking:A Top-Down Approach

会有的….

CSAPP-深入理解计算机系统

再说….有点忙

分布式系统: MIT6.824: Distributed System

包学的….

Now Playing

暂无歌曲

请添加播放列表