linux-0.11内核源码分析——(四)操作系统进程销毁

首先先说一下在linux中凡是syscall_XXX或者do_XXX  都是中断调用的函数。

exit()是一个销毁函数,当中会调用 do_exit() 这个中断函数(系统调用),首先我们先看一下内核销毁进程的流程。

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

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

(3)如果当前要销毁的进程有子进程,那么就让1号进程作为新的父进程(init进程),如 果当前进程是一个会话头进程,则会终止会话中的所有进程

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

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

(6)父进程一直在wait_pid,直到子进程发来信号后,父进程才将其task_struct等变量清除,终止进程的僵死状态。

(7)首先父进程会把子进程的运行时间累加到自己的进程变量中,ctime,stime。

(8)把对应的子进程的进程描述结构体进行释放,置空任务数组中的空槽(task链表)

首先来看一下exit.c中的release函数

void release(struct task_struct * p)
{
	int i;

	if (!p) 
		return;
	for (i=1 ; i<NR_TASKS ; i++)  /*在整个任务链表中找到对应的task_struct,将任务槽清空并释放其占用的内存*/
		if (task[i]==p) {
			task[i]=NULL;
			free_page((long)p);
			schedule();  	/*重新调度进程*/
			return;
		}
	panic("trying to release non-existent task");
}

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

exit.c中的send_sig函数

static inline int send_sig(long sig,struct task_struct * p,int priv)
{
	if (!p || sig<1 || sig>32) /*信号不在范围内则退出*/
		return -EINVAL;
	if (priv || (current->euid==p->euid) || suser()) /*如果权限为1||当前进程的有效用户id等于所指定进程的id||超级用户*/
		p->signal |= (1<<(sig-1)); /*向指定进程task_struct的信号中写入发送的信号*/
	else
		return -EPERM;
	return 0;
}

该函数用来向进程发送信号,用于进程间通信或子进程和父进程之间。

(current->euid==p->euid) || suser()

这段代码的意思是如果你要向某个进程发送信号时,要么你是那个目标进程的使用者,要么你是系统的管理者。

exit.c中的kill_session函数

static void kill_session(void) 
{
	struct task_struct **p = NR_TASKS + task;
	
	while (--p > &FIRST_TASK) { /*关闭对话的扫描不包括0号进程*/
		if (*p && (*p)->session == current->session)
			(*p)->signal |= 1<<(SIGHUP-1);  /*发送结束回话的信号*/
	}
}

终止当前进程的会话(进程与进程之间的通信)

exit.c中的sys_kill(int pid,int sig)函数,可向任何进程或者进程组发送任何信号。但该函数并没有杀死进程的意思。kill -x 就是向进程发送信号的意思。

int sys_kill(int pid,int sig) 
{
	struct task_struct **p = NR_TASKS + task;/*将指针指到整个task链表的最后*/
	int err, retval = 0;

	if (!pid) /*pid=0给当前进程的进程组发送sig*/
		while (--p > &FIRST_TASK) { /*从后往前找到对应的进程*/
		if (*p && (*p)->pgrp == current->pid) 
			if (err=send_sig(sig,*p,1))
				retval = err;
			} 
	else if (pid>0) /*pid>0给对应的pid发送sig*/
		while (--p > &FIRST_TASK) { /*从后往前找到对应的进程*/
		if (*p && (*p)->pid == pid)  
			if (err=send_sig(sig,*p,0))  /*发送指定信号*/
				retval = err;
			} 
	else if (pid == -1) 	/*pid=-1给任何进程发送  (相当于kill all)*/
		while (--p > &FIRST_TASK) /*从后往前找到对应的进程*/
		if (err = send_sig(sig,*p,0))
			retval = err;
	else 		/*pid<-1 给进程组号为-pid的进程组发送信号*/
		while (--p > &FIRST_TASK) /*从后往前找到对应的进程*/
		if (*p && (*p)->pgrp == -pid)
			if (err = send_sig(sig,*p,0))
				retval = err;
	return retval;
}

这个函数传入参数中的pid很有讲究

1.pid>0给对应的pid发送sig

2.pid=0给当前进程的进程组发送sig

3.pid=-1给任何进程发送  (相当于kill all)

4.pid<-1 给进程组号为-pid的进程组发送信号,例如pid=-4则向租号为4的进程组发送

下面我们就来看看最重要的do_exit() 函数

int do_exit(long code)
{
	int i;

	free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); /*释放ldt段*/
	free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
	for (i=0 ; i<NR_TASKS ; i++)
		if (task[i] && task[i]->father == current->pid) {
			task[i]->father = 1; /*如果当前要销毁的进程有子进程,那么就让1号进程作为新的父进程(init进程*/			
			if (task[i]->state == TASK_ZOMBIE)/*如果进程僵死,则让发送信号给其父进程1号进程*/
				/* assumption task[1] is always init */
				(void) send_sig(SIGCHLD, task[1], 1);
		}
	for (i=0 ; i<NR_OPEN ; i++) /*每个进程能打开的最大文件数是NR_OPEN*/
		if (current->filp[i])/*如果当前进程有打开的文件,则关闭*/  
			sys_close(i);
	/*对当前的目录和i节点进行同步(文件操作)*/
	iput(current->pwd);   
	current->pwd=NULL;
	iput(current->root);
	current->root=NULL;
	iput(current->executable);
	current->executable=NULL;


	if (current->leader && current->tty >= 0)  /*如果进程打开了控制台*/
		tty_table[current->tty].pgrp = 0;    /*将控制台清空*/
	if (last_task_used_math == current)   	/*使用了协处理器*/
		last_task_used_math = NULL; 		/*将协处理器清空*/
	if (current->leader)		 			/*如果进程时会话头进程,则关闭会话*/			
		kill_session();

	current->state = TASK_ZOMBIE;   		/*当前进程设置为僵死状态*/
	current->exit_code = code;				/* 设置任务执行停止的退出码,其父进程会取。*/
	tell_father(current->father);
	schedule();
	return (-1);	/* just to suppress warnings */
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值