Linux内核学习笔记——6.操作系统进程销毁

syscall_、do_xxxx——基本上都是中断调用的函数

1.内核的销毁流程

        1.1 exit是销毁函数——一个系统调用——do_exit

                首先该函数会释放进程的代码段和数据段占用的内存

        1.2 关闭进程打开的所有文件,对当前的目录和inode进行同步(文件操作)

        1.3 如果当前要销毁的进程有子进程,那么就让1号进程作为新的父进程(init进程)

        1.4 如果当前进程是一个会话头进程,则会终止会话中的所有进程

        1.5 改变当前进程的运行状态,变成TASK_ZOMBIE僵死状态,并且向其父进程发送SIGCHLD信号

        2.1 父进程在运行子进程的时候,一般都会运行wait、waitpid这两个函数(父进程等待某个子进程终止的)

                当父进程收到SIGCHLD信号时父进程会终止僵死状态的子进程

        2.2 首先父进程会把子进程的运行时间累加到自己的进程变量中

        2.3 把对应的子进程的进程描述结构体进行释放,置空任务数组中的空槽

        

void release(struct task_struct * p)

完成清空了任务描述表中的对应进程表项,释放对应的内存页(代码段、数据段、堆栈)

static inline int send_sig(long sig, struct task_struct * p, int priv)

给指定的p进程发送对应的sig信号

static void kill_session(void)

终止会话,终止当前进程的会话,给其发送SIGHUP

int sys_kill(int pid, int sig)

kill -不是杀死的意思,向对应的进程号或者进程组号发送任何信号

pid(
    pid > 0  给对应的pid发送sig
    pid = 0  给当前进程的进程组发送sig
    pid = -1 给任何进程发送
    pid < -1 给进程组号为-pid的进程组发送信号
    )
// 如果pid=0,那么信号就会被发送给当前进程的进程组中的所有进程。
  if (!pid)
    while (--p > &FIRST_TASK)
	{
		if (*p && (*p)->pgrp == current->pid)
		  if (err = send_sig (sig, *p, 1))
			retval = err;
	}
// 如果pid 值>0,则信号被发送给pid。
  else if (pid > 0)
    while (--p > &FIRST_TASK)
    {
	if (*p && (*p)->pid == pid)
	  if (err = send_sig (sig, *p, 0))
	    retval = err;
    }
// 如果pid=-1,则信号sig 就会发送给除第一个进程外的所有进程。
  else if (pid == -1)
    while (--p > &FIRST_TASK)
      if (err = send_sig (sig, *p, 0))
		retval = err;
// 如果pid < -1,则信号sig 将发送给进程组-pid 的所有进程。
  else
	while (--p > &FIRST_TASK)
	  if (*p && (*p)->pgrp == -pid)
		if (err = send_sig (sig, *p, 0))
		  retval = err;

子进程向父进程发送SIGCHLD信号

static void tell_father(int pid)

int do_exit(long code)(重要!)
        current->pid就是当前关闭的进程

 程序退出处理程序。在系统调用的中断处理程序中被调用。
int do_exit (long code)		// code 是错误码。
{
  int i;

// 1.释放当前进程代码段和数据段所占的内存页(free_page_tables()在mm/memory.c,105 行)。
  free_page_tables (get_base (current->ldt[1]), get_limit (0x0f));
  free_page_tables (get_base (current->ldt[2]), get_limit (0x17));
// 2.如果当前进程有子进程,就将子进程的father 置为1(其父进程改为进程1)。如果该子进程已经
// 处于僵死(ZOMBIE)状态,则向进程1 发送子进程终止信号SIGCHLD。
  for (i = 0; i < NR_TASKS; i++)
    if (task[i] && task[i]->father == current->pid)
      {
	task[i]->father = 1;
	if (task[i]->state == TASK_ZOMBIE)
/* assumption task[1] is always init */
	  (void) send_sig (SIGCHLD, task[1], 1);
      }
// 3.关闭当前进程打开着的所有文件。
  for (i = 0; i < NR_OPEN; i++)
    if (current->filp[i])
      sys_close (i);
// 4.对当前进程工作目录pwd、根目录root 以及运行程序的i 节点进行同步操作,并分别置空。
  iput (current->pwd);
  current->pwd = NULL;
  iput (current->root);
  current->root = NULL;
  iput (current->executable);
  current->executable = NULL;
// 5.如果当前进程是领头(leader)进程并且其有控制的终端,则释放该终端。
  if (current->leader && current->tty >= 0)
    tty_table[current->tty].pgrp = 0;
// 6.如果当前进程上次使用过协处理器,则将last_task_used_math 置空。
  if (last_task_used_math == current)
    last_task_used_math = NULL;
// 7.如果当前进程是leader 进程,则终止所有相关进程。
  if (current->leader)
    kill_session ();
// 8.把当前进程置为僵死状态,并设置退出码。
  current->state = TASK_ZOMBIE;
  current->exit_code = code;
// 9.通知父进程,也即向父进程发送信号SIGCHLD -- 子进程将停止或终止。
  tell_father (current->father);
// 10.重新调度进程的运行。
  schedule ();			
  return (-1);			/* just to suppress warnings */
}

       

        2.1 父进程在运行子进程的时候,一般都会运行wait、waitpid这两个函数(父进程等待某个子进程终止的)

                当父进程收到SIGCHLD信号时父进程会终止僵死状态的子进程

        2.2 首先父进程会把子进程的运行时间累加到自己的进程变量中

int sys_waitpid (pid_t pid, unsigned long *stat_addr, int options)
    current->cutime += (*p)->utime;	// 更新当前进程的子进程用户
	current->cstime += (*p)->stime;	// 态和核心态运行时间。

        2.3 把对应的子进程的进程描述结构体进行释放,置空任务数组中的空槽

release (*p);		// 释放该子进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值