Take Linux0.11 source code analysis, from the process 2 to create and destroy for example. The code posted here does not understand it does not matter, I will try to put the process clearly, see understand that is the best, the programmer’s language is not the code ~ 😂

After the Linux kernel is loaded into memory, the main function in main.c is executed to create process 0, process 0 creates process 1, and process 1 creates process 2

void main(void) { ... if (! fork()) { init(); // Execute in the new child process (task 1). }... }Copy the code

Fokk creates process 1, and in the child process (process 1)fork returns 0. Init () starts with process 1.

void init(void) { ... if (! (pid=fork())) { ... Process 2 execution block... If (pid>0) while (pid! = wait(&i)) ... }Copy the code

Pid = 0 indicates the child process, pid > 0 indicates the parent process, so the parent process (process 1) calls wait

Wait is defined in the lib/wait.c file,

#define __LIBRARY__
#include <unistd.h>
#include <sys/wait.h>

_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
pid_t wait(int * wait_stat)
{
	return waitpid(-1,wait_stat,0);
}
Copy the code

_sySCall3 is declared in the unistd.h header file. The final call to wait is sys_WAITPID

#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ type name(atype a,btype b,ctype c) \ { \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \ if (__res>=0) \ return (type) __res; \ errno=-__res; \ return -1; The \}Copy the code

When sys_WAITPID finds the process, it sets the state of the process to the interrupted wait state and reschedules the schedule() process. If the wait state is interrupted when the process is found, the process will not be executed and needs to wait for the next schedule.

int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) { int flag, code; // flag is used later to indicate that the selected child process is ready or asleep. struct task_struct ** p; verify_area(stat_addr,4); repeat: flag=0; . If flag is set after scanning the task array above, it indicates that there are child processes that meet the waiting requirements and are not in the exit or // zombie state. If the WNOHANG option is set (return immediately if no child processes are in the exit or termination state), return 0 immediately to exit. Otherwise, the current process is put into interruptible wait state and rescheduled. When the process starts again, // if the process receives no signal other than SIGCHLD, the process is repeated. Otherwise, return error code 'interrupt system call' // and exit. The user program should continue calling this function for this error number and wait for the child process. If (flag) {if (options & WNOHANG) // options = WNOHANG, return immediately. return 0; current->state=TASK_INTERRUPTIBLE; // Set the current process to the interruptible wait state schedule(); // re-schedule. if (! (current->signal &= ~(1<<(SIGCHLD-1)))) goto repeat; else return -EINTR; } // If no child is found, an error is returned (the child does not exist). return -ECHILD; }Copy the code

After wait is called, process 1 is no longer executing on the CPU, and process 2 is in the runnable state. After process 2 has finished executing, process 2 will execute _exit (sys_exit)

int sys_exit(int error_code)
{
	return do_exit((error_code&0xff)<<8);
}
Copy the code

Tell_father (current->father); Notify the parent process, send a signal to the parent process task [I] – > signal | = (1 < < (SIGCHLD – 1)); It does not mean that the parent will wake up and wait for the next schedule();

int do_exit(long code) { ... ·· current->state = TASK_ZOMBIE; current->exit_code = code; // Tell the parent, i.e. signal SIGCHLD to the parent that the child will stop or terminate. tell_father(current->father); schedule(); // reschedule the process to allow the parent process to handle any other cleanup. return (-1); }Copy the code
static void tell_father(int pid) { int i; If (pid) // Scans the entry array table for the specified process PID and sends SIGCHLD to it that the child process will stop or terminate. for (i=0; i<NR_TASKS; i++) { if (! task[i]) continue; if (task[i]->pid ! = pid) continue; task[i]->signal |= (1<<(SIGCHLD-1)); return; } /* if we don't find any fathers, we just release ourselves */ /* This is not really OK. Must change it to make father 1 */ printk("BAD BAD - no father found\n\r"); release(current); // If the parent process is not found, it is released by itself}Copy the code

Here the child process released their own memory page data, but also in the process list takes up process structure, why don’t the release of finished, because the parent process also need to know the child’s return value, the return value is in the process of structure, the child is the zombie state, this is never going to run, after waiting for the next process scheduling, When the parent process detects that it has received the SIGCHLD signal and is in an interruptible wait state, the parent process wakes up and executes at the last wait code, the sys_waitPID method mentioned above, which finds the TASK_ZOMBIE child and releases the item occupied by the child.

If the parent process does not call wait and the child process terminates, the parent process does not know whether the child process is dead or not and cannot release the child process. The child process releases its occupied memory pages, but cannot release the occupied process structure, and the child process becomes a zombie process.

case TASK_ZOMBIE: current->cutime += (*p)->utime; current->cstime += (*p)->stime; flag = (*p)->pid; Pid code = (*p)->exit_code; Release (*p); Put_fs_long (code,stat_addr); // Set status information to exit code value return flag; // Returns the pid of the child processCopy the code