🔗 https://jyywiki.cn/OS/2024/labs/M1.md
實作上不一定正確,也有可能隨著不斷的學習來修改實作,寫下這個權當對實驗內容的整理和複習,僅供自己參考。
我先嘗試從 1 號行程輸出一個 pstree,不考慮命令列中的 option.
問題可以被分成幾個部分:
- 如何得到 pid.
- 如何得到 ppid.
- 以什麼樣的方式儲存 pid 和 ppid.
- 如何輸出樹。
- 以及最後需要考慮的問題,如何解析命令列參數。
如何儲存 pid 和 ppid
選擇把 pid 、ppid 和行程名稱 name 定義在一個結構體中。
c
#define MAX_NAME_LEN 256
typedef struct Process{
pid_t pid;
pid_t ppid;
char name[MAX_NAME_LEN];
}The GNU C Library 對 pid_t 的官方文件解釋。
The pid_t data type is a signed integer type which is capableof representing a process ID. In the GNU C Library, this is an int.將所有行程存放在陣列中,每個元素都是 Process 結構體。並且定義行程數量。
c
#define MAX_PROC 1024
struct Process processes[MAX_PROC];
int process_count = 0;得到 pid 和 ppid
如實驗指導所言, Everying is a file(說明相關的 C 中的函式和 API 一定是相當重要的),我們可以透過 /proc 資料夾下以數字命名的目錄來取得行程:
c
//traverse /proc directory, get all process information
void get_process_list() {
// read each entry in the proc directory
struct dirent *entry;
DIR *dp = opendir("/proc"); // open /proc dir
if(dp==NULL){
perror("opendir: /proc");
exit(1);
}
while((entry = readdir(dp)) != NULL){
if (isdigit(*entry->d_name)){
//printf("Process ID:%s\n", entry->d_name);
pid_t pid = atoi(entry->d_name);
if (pid > 0) {
pid_t ppid;
char name[MAX_NAME_LEN];
// read the status file of the process
if (read_status_file(pid, &ppid, name) == 0) {
processes[process_count].pid = pid;
processes[process_count].ppid = ppid;
strncpy(processes[process_count].name, name, MAX_NAME_LEN);
process_count++;
}
}
}
}
closedir(dp);
}struct dirent 的官方解釋。
我自己直接搜 members of dirent structure 還借助了 stack overflow 上的回答。
DIR data type 的官方解釋。
c
int read_status_file(pid_t pid, pid_t *ppid, char *name) {
char path[64], buffer[256];
FILE *file;
sprintf(path, "/proc/%d/status", pid);
file = fopen(path, "r");
if (file == NULL) {
return -1; //file can't be opened, maybe process already exits
}
while (fgets(buffer, sizeof(buffer), file)) {
if (strncmp(buffer, "Name:", 5) == 0) {
sscanf(buffer, "Name:\t%s", name);
}
else if (strncmp(buffer, "PPid:", 5) == 0) {
sscanf(buffer, "PPid:\t%d", ppid);
}
}
fclose(file);
return 0;
}在 read_status_file 函式中,sprintf、fgets、strncmp 以及 sscanf 的用法對我來說都是比較陌生的,但 ChatGPT 告訴我這些函式在讀取和解析檔案內容中都是很常用的。
輸出樹
最容易想到的方法應該就是遞迴了,將目前行程的 pid 與行程陣列中各元素的 ppid ,進行比對來作為是否可以進入遞迴函式的條件。不再贅述。
解析命令列參數
getopt_long 真的很好用。
C parse short option and long option in the command line.
jyy 老師在實驗指導最後提出的問題自己還不能做出解答,繼續深入往下學習吧。