Example #1
0
File: exit.c Project: gozfree/src
int do_exit(long code)
{
	int i;

	free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
	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;
			if (task[i]->state == TASK_ZOMBIE)
				/* assumption task[1] is always init */
				(void) send_sig(SIGCHLD, task[1], 1);
		}
	for (i=0 ; i<NR_OPEN ; i++)
		if (current->filp[i])
			sys_close(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 */
}
Example #2
0
int do_exit(long code)
{
	int i;

	free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
	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 = 0;
	for (i=0 ; i<NR_OPEN ; i++)
		if (current->filp[i])
			sys_close(i);
	iput(current->pwd);
	current->pwd=NULL;
	iput(current->root);
	current->root=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->father) {
		current->state = TASK_ZOMBIE;
		do_kill(current->father,SIGCHLD,1);
		current->exit_code = code;
	} else
		release(current);
	schedule();
	return (-1);	/* just to suppress warnings */
}
Example #3
0
int do_exit(long code)
{
	int i;
	// TODO 待看页表
	free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
	free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
	/*
	 * 找出所有子进程,将它们的父亲设为 init 进程,将状态标记为僵尸
	 * 然后给 init 进程发送一个 SIGCHLD 信号,提醒 init 进程回收子进程
	 */
	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 */
				// 最后一个参数 1 代表 privilege,此处为强制发送
				(void) send_sig(SIGCHLD, task[1], 1);
		}
	// TODO 关闭文件?
	/*
	 * NR_OPEN 是一个进程可以打开的最大文件数
	 * 而 NR_FILE 是系统在某时刻的限制文件总数
	 */
	for (i=0 ; i<NR_OPEN ; i++)
		if (current->filp[i])
			sys_close(i);
	// 进程的当前工作目录 inode
	iput(current->pwd);
	current->pwd=NULL;
	// 进程的根目录 inode
	iput(current->root);
	current->root=NULL;
	// 进程本身可执行文件的 inode
	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;
	/*
	 * 如果是 session leader 会话领头进程,则向该会话所有进程发送 SIGHUP 信号
	 * PID, PPID, PGID, SID
	 * http://unix.stackexchange.com/questions/18166/what-are-session-leaders-in-ps
	 * 在同一次 ssh 会话中,用户对应的 shell 最先被启动,成为 session leader,
	 * 所有在同一次会话中产生的进程 session id 都等于这个 session leader 的 pid
	 * 当 session leader 退出时,它会向所有同一 session 中的进程发送 SIGHUP,
	 * 这个信号是可以被捕获的,如果进程忽略这个 SIGHUP,它则可以以一个孤儿进程继续执行
	 * http://www.firefoxbug.com/index.php/archives/2782/
	 */
	if (current->leader)
		kill_session();
	// 将自己设为僵尸,设置退出状态码,同时告诉父进程回收子进程
	current->state = TASK_ZOMBIE;
	current->exit_code = code;
	tell_father(current->father);
	// 如果 tell_father 中找不到父进程,自己把自己释放掉了,那也不会有机会继续执行下面代码了
	schedule();
	return (-1);	/* just to suppress warnings */
}
Example #4
0
//// 程序退出处理程序。在系统调用的中断处理程序中被调用。
int
do_exit (long code)		// code 是错误码。
{
  int i;

// 释放当前进程代码段和数据段所占的内存页(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));
// 如果当前进程有子进程,就将子进程的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);
      }
// 关闭当前进程打开着的所有文件。
  for (i = 0; i < NR_OPEN; i++)
    if (current->filp[i])
      sys_close (i);
// 对当前进程工作目录pwd、根目录root 以及运行程序的i 节点进行同步操作,并分别置空。
  iput (current->pwd);
  current->pwd = NULL;
  iput (current->root);
  current->root = NULL;
  iput (current->executable);
  current->executable = NULL;
// 如果当前进程是领头(leader)进程并且其有控制的终端,则释放该终端。
  if (current->leader && current->tty >= 0)
    tty_table[current->tty].pgrp = 0;
// 如果当前进程上次使用过协处理器,则将last_task_used_math 置空。
  if (last_task_used_math == current)
    last_task_used_math = NULL;
// 如果当前进程是leader 进程,则终止所有相关进程。
  if (current->leader)
    kill_session ();
// 把当前进程置为僵死状态,并设置退出码。
  current->state = TASK_ZOMBIE;
  current->exit_code = code;
// 通知父进程,也即向父进程发送信号SIGCHLD -- 子进程将停止或终止。
  tell_father (current->father);
  schedule ();			// 重新调度进程的运行。
  return (-1);			/* just to suppress warnings */
}
Example #5
0
int sys_shmdt(void *shmaddr)
{
	unsigned long data_base, vir_addr;
	
	data_base = get_base(current->ldt[2]);	
	vir_addr = data_base + current->brk - PAGE_SIZE;	
	if(((unsigned long)shmaddr<=vir_addr) && ((unsigned long)shmaddr>data_base)){
		free_page_tables((unsigned long)shmaddr, PAGE_SIZE);	
		current->brk -= PAGE_SIZE;
		
		return 0;
	}
		
	return -EINVAL;	
}
Example #6
0
static inline void __exit_mm(struct task_struct * tsk)
{
	struct mm_struct * mm = tsk->mm;

	/* Set us up to use the kernel mm state */
	if (mm != &init_mm) {
		flush_cache_mm(mm);
		flush_tlb_mm(mm);
		tsk->mm = &init_mm;
		tsk->swappable = 0;
		SET_PAGE_DIR(tsk, swapper_pg_dir);

		/* free the old state - not used any more */
		if (!--mm->count) {
			exit_mmap(mm);
			free_page_tables(mm);
			kfree(mm);
		}
	}
}
Example #7
0
// 设置新任务的代码和数据段基址、限长并复制页表。
// nr 为新任务号;p 是新任务数据结构的指针。
int copy_mem (int nr, struct task_struct *p)
{
	unsigned long old_data_base, new_data_base, data_limit;
	unsigned long old_code_base, new_code_base, code_limit;

	code_limit = get_limit (0x0f);	// 取局部描述符表中代码段描述符项中段限长。
	data_limit = get_limit (0x17);	// 取局部描述符表中数据段描述符项中段限长。
	old_code_base = get_base (current->ldt[1]);	// 取原代码段基址。
	old_data_base = get_base (current->ldt[2]);	// 取原数据段基址。
	if (old_data_base != old_code_base)	// 0.11 版不支持代码和数据段分立的情况。
		panic ("We don't support separate I&D");
	if (data_limit < code_limit)	// 如果数据段长度 < 代码段长度也不对。
		panic ("Bad data_limit");
	new_data_base = new_code_base = nr * 0x4000000;	// 新基址=任务号*64Mb(任务大小)。
	p->start_code = new_code_base;
	set_base (p->ldt[1], new_code_base);	// 设置代码段描述符中基址域。
	set_base (p->ldt[2], new_data_base);	// 设置数据段描述符中基址域。
	if (copy_page_tables (old_data_base, new_data_base, data_limit))
    {				// 复制代码和数据段。
		free_page_tables (new_data_base, data_limit);	// 如果出错则释放申请的内存。
		return -ENOMEM;
    }
	return 0;
}
Example #8
0
volatile void do_exit(long code)
{
	struct task_struct *p;
	int i;

fake_volatile:
	free_page_tables(current);
	for (i=0 ; i<NR_OPEN ; i++)
		if (current->filp[i])
			sys_close(i);
	forget_original_parent(current);
	iput(current->pwd);
	current->pwd = NULL;
	iput(current->root);
	current->root = NULL;
	iput(current->executable);
	current->executable = NULL;
	for (i=0; i < current->numlibraries; i++) {
		iput(current->libraries[i].library);
		current->libraries[i].library = NULL;
	}	
	current->state = TASK_ZOMBIE;
	current->exit_code = code;
	current->rss = 0;
	/* 
	 * Check to see if any process groups have become orphaned
	 * as a result of our exiting, and if they have any stopped
	 * jobs, send them a SIGUP and then a SIGCONT.  (POSIX 3.2.2.2)
	 *
	 * Case i: Our father is in a different pgrp than we are
	 * and we were the only connection outside, so our pgrp
	 * is about to become orphaned.
 	 */
	if ((current->p_pptr->pgrp != current->pgrp) &&
	    (current->p_pptr->session == current->session) &&
	    is_orphaned_pgrp(current->pgrp) &&
	    has_stopped_jobs(current->pgrp)) {
		kill_pg(current->pgrp,SIGHUP,1);
		kill_pg(current->pgrp,SIGCONT,1);
	}
	/* Let father know we died */
	send_sig (SIGCHLD, current->p_pptr, 1);
	
	/*
	 * This loop does two things:
	 * 
  	 * A.  Make init inherit all the child processes
	 * B.  Check to see if any process groups have become orphaned
	 *	as a result of our exiting, and if they have any stopped
	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
	 */
	while ((p = current->p_cptr) != NULL) {
		current->p_cptr = p->p_osptr;
		p->p_ysptr = NULL;
		p->flags &= ~(PF_PTRACED|PF_TRACESYS);
		if (task[1])
			p->p_pptr = task[1];
		else
			p->p_pptr = task[0];
		p->p_osptr = p->p_pptr->p_cptr;
		p->p_osptr->p_ysptr = p;
		p->p_pptr->p_cptr = p;
		if (p->state == TASK_ZOMBIE)
			send_sig(SIGCHLD,p->p_pptr,1);
		/*
		 * process group orphan check
		 * Case ii: Our child is in a different pgrp 
		 * than we are, and it was the only connection
		 * outside, so the child pgrp is now orphaned.
		 */
		if ((p->pgrp != current->pgrp) &&
		    (p->session == current->session) &&
		    is_orphaned_pgrp(p->pgrp) &&
		    has_stopped_jobs(p->pgrp)) {
			kill_pg(p->pgrp,SIGHUP,1);
			kill_pg(p->pgrp,SIGCONT,1);
		}
	}
	if (current->leader) {
		struct task_struct **p;
		struct tty_struct *tty;

		if (current->tty >= 0) {
			tty = TTY_TABLE(current->tty);
			if (tty) {
				if (tty->pgrp > 0)
					kill_pg(tty->pgrp, SIGHUP, 1);
				tty->pgrp = -1;
				tty->session = 0;
			}
		}
	 	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
			if (*p && (*p)->session == current->session)
				(*p)->tty = -1;
	}
	if (last_task_used_math == current)
		last_task_used_math = NULL;
#ifdef DEBUG_PROC_TREE
	audit_ptree();
#endif
	schedule();
/*
 * In order to get rid of the "volatile function does return" message
 * I did this little loop that confuses gcc to think do_exit really
 * is volatile. In fact it's schedule() that is volatile in some
 * circumstances: when current->state = ZOMBIE, schedule() never
 * returns.
 *
 * In fact the natural way to do all this is to have the label and the
 * goto right after each other, but I put the fake_volatile label at
 * the start of the function just in case something /really/ bad
 * happens, and the schedule returns. This way we can try again. I'm
 * not paranoid: it's just that everybody is out to get me.
 */
	goto fake_volatile;
}
Example #9
0
NORET_TYPE void do_exit(long code)
{
	struct task_struct *p;
	int i;

fake_volatile:
	if (current->semun)
		sem_exit();
	if (current->shm)
		shm_exit();
	free_page_tables(current);
	for (i=0 ; i<NR_OPEN ; i++)
		if (current->filp[i])
			sys_close(i);
	forget_original_parent(current);
	iput(current->pwd);
	current->pwd = NULL;
	iput(current->root);
	current->root = NULL;
	iput(current->executable);
	current->executable = NULL;
	/* Release all of the old mmap stuff. */
	
	{
		struct vm_area_struct * mpnt, *mpnt1;
		mpnt = current->mmap;
		current->mmap = NULL;
		while (mpnt) {
			mpnt1 = mpnt->vm_next;
			if (mpnt->vm_ops && mpnt->vm_ops->close)
				mpnt->vm_ops->close(mpnt);
			kfree(mpnt);
			mpnt = mpnt1;
		}
	}

	if (current->ldt) {
		vfree(current->ldt);
		current->ldt = NULL;
		for (i=1 ; i<NR_TASKS ; i++) {
			if (task[i] == current) {
				set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, &default_ldt, 1);
				load_ldt(i);
			}
		}
	}

	current->state = TASK_ZOMBIE;
	current->exit_code = code;
	current->rss = 0;
	/* 
	 * Check to see if any process groups have become orphaned
	 * as a result of our exiting, and if they have any stopped
	 * jobs, send them a SIGUP and then a SIGCONT.  (POSIX 3.2.2.2)
	 *
	 * Case i: Our father is in a different pgrp than we are
	 * and we were the only connection outside, so our pgrp
	 * is about to become orphaned.
 	 */
	if ((current->p_pptr->pgrp != current->pgrp) &&
	    (current->p_pptr->session == current->session) &&
	    is_orphaned_pgrp(current->pgrp) &&
	    has_stopped_jobs(current->pgrp)) {
		kill_pg(current->pgrp,SIGHUP,1);
		kill_pg(current->pgrp,SIGCONT,1);
	}
	/* Let father know we died */

    /* 通知父进程 */
	notify_parent(current);
	
	/*
	 * This loop does two things:
	 * 
  	 * A.  Make init inherit all the child processes
	 * B.  Check to see if any process groups have become orphaned
	 *	as a result of our exiting, and if they have any stopped
	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
	 */
	while ((p = current->p_cptr) != NULL) {
		current->p_cptr = p->p_osptr;
		p->p_ysptr = NULL;
		p->flags &= ~(PF_PTRACED|PF_TRACESYS);
		if (task[1] && task[1] != current)
			p->p_pptr = task[1];
		else
			p->p_pptr = task[0];
		p->p_osptr = p->p_pptr->p_cptr;
		p->p_osptr->p_ysptr = p;
		p->p_pptr->p_cptr = p;
		if (p->state == TASK_ZOMBIE)
			notify_parent(p);
		/*
		 * process group orphan check
		 * Case ii: Our child is in a different pgrp 
		 * than we are, and it was the only connection
		 * outside, so the child pgrp is now orphaned.
		 */
		if ((p->pgrp != current->pgrp) &&
		    (p->session == current->session) &&
		    is_orphaned_pgrp(p->pgrp) &&
		    has_stopped_jobs(p->pgrp)) {
			kill_pg(p->pgrp,SIGHUP,1);
			kill_pg(p->pgrp,SIGCONT,1);
		}
	}
	if (current->leader)
		disassociate_ctty(1);
	if (last_task_used_math == current)
		last_task_used_math = NULL;
#ifdef DEBUG_PROC_TREE
	audit_ptree();
#endif
	schedule();
/*
 * In order to get rid of the "volatile function does return" message
 * I did this little loop that confuses gcc to think do_exit really
 * is volatile. In fact it's schedule() that is volatile in some
 * circumstances: when current->state = ZOMBIE, schedule() never
 * returns.
 *
 * In fact the natural way to do all this is to have the label and the
 * goto right after each other, but I put the fake_volatile label at
 * the start of the function just in case something /really/ bad
 * happens, and the schedule returns. This way we can try again. I'm
 * not paranoid: it's just that everybody is out to get me.
 */
	goto fake_volatile;
}