浏览代码

bugfix: 修复进程pcb被回收时,未将其从链表中删除的问题 (#87)

* bugfix: 修复进程pcb被回收时,未将其从链表中删除的问题
new: pcb相关api文档

* 将文档加入目录
login 2 年之前
父节点
当前提交
3d729e2069

+ 2 - 1
docs/kernel/process_management/index.rst

@@ -4,4 +4,5 @@
 .. toctree::
    :maxdepth: 1
 
-   kthread
+   kthread
+   pcb

+ 27 - 0
docs/kernel/process_management/pcb.md

@@ -0,0 +1,27 @@
+# PCB 进程控制块
+
+PCB的全称为process control block, 它是每个进程/线程的核心控制结构。定义于`kernel/src/process/proc-types.h`中。
+
+## PCB详解
+
+Todo:
+
+## 与PCB的管理相关的API
+
+### 根据pid寻找pcb
+
+**process_find_pcb_by_pid**
+
+该API提供了根据pid寻找pcb的功能,定义在`kernel/src/process/process.h`中。
+
+当找到目标的pcb时,返回对应的pcb,否则返回NULL。
+
+#### 参数
+
+**pid**
+    进程id
+
+#### 返回值
+
+**struct process_control_block**
+    目标pcb

+ 2 - 2
kernel/src/process/proc-types.h

@@ -84,7 +84,7 @@ struct process_control_block
     // 进程切换时保存的状态信息
     struct thread_struct *thread;
 
-    // 连接各个pcb的双向链表
+    // pcb加入调度队列时,所使用的链表节点
     struct List list;
 
     //todo:给pcb中加一个spinlock_t成员
@@ -105,7 +105,7 @@ struct process_control_block
     struct vfs_file_t *fds[PROC_MAX_FD_NUM];
 
     // 链表中的下一个pcb
-    struct process_control_block *next_pcb;
+    struct process_control_block *prev_pcb, *next_pcb;
     // 父进程的pcb
     struct process_control_block *parent_pcb;
 

+ 16 - 4
kernel/src/process/process.c

@@ -676,7 +676,7 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
     struct process_control_block *tsk = NULL;
 
     // 为新的进程分配栈空间,并将pcb放置在底部
-    tsk = (struct process_control_block *)kmalloc(STACK_SIZE, 0);
+    tsk = (struct process_control_block *)kzalloc(STACK_SIZE, 0);
     barrier();
 
     if (tsk == NULL)
@@ -717,6 +717,9 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
     tsk->pid = process_global_pid++;
     barrier();
     // 加入到进程链表中
+    // todo: 对pcb_list_lock加锁
+    tsk->prev_pcb = &initial_proc_union.pcb;
+    barrier();
     tsk->next_pcb = initial_proc_union.pcb.next_pcb;
     barrier();
     initial_proc_union.pcb.next_pcb = tsk;
@@ -779,13 +782,14 @@ copy_flags_failed:;
 }
 
 /**
- * @brief 根据pid获取进程的pcb
+ * @brief 根据pid获取进程的pcb。存在对应的pcb时,返回对应的pcb的指针,否则返回NULL
  *
  * @param pid
  * @return struct process_control_block*
  */
-struct process_control_block *process_get_pcb(long pid)
+struct process_control_block *process_find_pcb_by_pid(pid_t pid)
 {
+    // todo: 当进程管理模块拥有pcblist_lock之后,对其加锁
     struct process_control_block *pcb = initial_proc_union.pcb.next_pcb;
 
     // 使用蛮力法搜索指定pid的pcb
@@ -797,6 +801,7 @@ struct process_control_block *process_get_pcb(long pid)
     }
     return NULL;
 }
+
 /**
  * @brief 将进程加入到调度器的就绪队列中
  *
@@ -1174,8 +1179,15 @@ int process_release_pcb(struct process_control_block *pcb)
 {
     // 释放子进程的页表
     process_exit_mm(pcb);
-    if ((pcb->flags & PF_KTHREAD))  // 释放内核线程的worker private结构体
+    if ((pcb->flags & PF_KTHREAD)) // 释放内核线程的worker private结构体
         free_kthread_struct(pcb);
+    
+    // 将pcb从pcb链表中移除
+    // todo: 对相关的pcb加锁
+    pcb->prev_pcb->next_pcb = pcb->next_pcb;
+    pcb->next_pcb->prev_pcb = pcb->prev_pcb;
+    
+    // 释放当前pcb
     kfree(pcb);
     return 0;
 }

+ 3 - 3
kernel/src/process/process.h

@@ -27,7 +27,7 @@
     {                                                                                                                  \
         .state = PROC_UNINTERRUPTIBLE, .flags = PF_KTHREAD, .preempt_count = 0, .signal = 0, .cpu_id = 0,              \
         .mm = &initial_mm, .thread = &initial_thread, .addr_limit = 0xffffffffffffffff, .pid = 0, .priority = 2,       \
-        .virtual_runtime = 0, .fds = {0}, .next_pcb = &proc, .parent_pcb = &proc, .exit_code = 0,                      \
+        .virtual_runtime = 0, .fds = {0}, .next_pcb = &proc, .prev_pcb = &proc, .parent_pcb = &proc, .exit_code = 0,    \
         .wait_child_proc_exit = 0, .worker_private = NULL, .policy = SCHED_NORMAL                                      \
     }
 
@@ -95,12 +95,12 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
                       unsigned long stack_size);
 
 /**
- * @brief 根据pid获取进程的pcb
+ * @brief 根据pid获取进程的pcb。存在对应的pcb时,返回对应的pcb的指针,否则返回NULL
  *
  * @param pid
  * @return struct process_control_block*
  */
-struct process_control_block *process_get_pcb(long pid);
+struct process_control_block *process_find_pcb_by_pid(pid_t pid);
 
 /**
  * @brief 将进程加入到调度器的就绪队列中

+ 2 - 9
kernel/src/syscall/syscall.c

@@ -518,14 +518,8 @@ uint64_t sys_wait4(struct pt_regs *regs)
     // 查找pid为指定值的进程
     // ps: 这里判断子进程的方法没有按照posix 2008来写。
     // todo: 根据进程树判断是否为当前进程的子进程
-    for (proc = &initial_proc_union.pcb; proc->next_pcb != &initial_proc_union.pcb; proc = proc->next_pcb)
-    {
-        if (proc->next_pcb->pid == pid)
-        {
-            child_proc = proc->next_pcb;
-            break;
-        }
-    }
+    
+    child_proc = process_find_pcb_by_pid(pid);
 
     if (child_proc == NULL)
         return -ECHILD;
@@ -542,7 +536,6 @@ uint64_t sys_wait4(struct pt_regs *regs)
     if (likely(status != NULL))
         *status = child_proc->exit_code;
     // copy_to_user(status, (void*)child_proc->exit_code, sizeof(int));
-    proc->next_pcb = child_proc->next_pcb;
 
     process_release_pcb(child_proc);
     return 0;