There are many way to manage each process's pid. Here is the way I do it.

I decided to make minimal modification to $OS161_SRC/kern/thread/thread.c, in case anything is ruined. So I only add two things to the thread module. One is I add a t_pid field to struct thread so that getpid system call is trivial. Another is I add a call of pid_alloc in thread_alloc to initialize new thread's t_pid. That's it. No more touch on the thread module.

The process Structure

In os161, we stick to the 1:1 process:thread model. That is, a process has and only has one thread. Thus process and thread are basically the same thing in this scenario. However, I still decided to use a struct process to do process bookkeeping stuff. It's independent to struct thread and outside the thread module. Thus when a thread exits and its thread structure is destroyed. I still have its meta-data (e.g. exitcode) stored in the process structure.

So, what should we record about a process? As we already have the struct thread to record most of the information about a thread, we just use a pointer to struct thread to get all these information. What we do in struct process is mainly for our waitpid and exit system call. So we should keep the information of:

  • Its parent's (if any) pid

  • Whether a process has exited

  • If this process has exited, then the exitcode

  • Synchronous facilities to protect the exit status (lock, cv, samophore, etc)

  • Of course a pointer to struct thread

So the structure looks like:

struct process { 
    pid_t ppid; 
    struct semphore* exitsem; 
    bool exited; 
    int exitcode; 
    struct thread* self; 
};

Pid allocation

For convenience and simplicity, I decided to support a maximum number of MAX_RUNNING_PROCS (256) processes in the OS, regardless the __PID_MAX (32767) macro in $OS161_SRC/kern/inlude/kern/limits.h. So I just use a global static array of struct process* to maintain all the processes in system. Of course it's very dumb but hope it's sufficient for a toy OS like 161.

Then allocate a pid is very easy, just scan the process array and find a available slot (NULL). One important thing to note is that leave pid=0 alone and do not use it. Since in /kern/include/kern/wait.h, there are two special MACROs:

#define WAIT_ANY (-1) 
#define WAIT_MYPGRP (0)

That is, pid = 0 has a special meaning. So we'd better not use it, staring allocate pid from 1. We can also see this from the __PID_MIN (2) macro in $OS161_SRC/kern/inlude/kern/limits.h.

Once a available slot is found, we need to create a struct process and initialize it appropriately, especially it's ppid (-1 or other invalid value).