File:  [Early Linux] / linux / kernel / exit.c
Revision 1.1.1.9 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:09:43 2018 UTC (2 years, 3 months ago) by root
Branches: linus, MAIN
CVS tags: linux096b, HEAD
linux 0.96b

    1: /*
    2:  *  linux/kernel/exit.c
    3:  *
    4:  *  (C) 1991  Linus Torvalds
    5:  */
    6: 
    7: #define DEBUG_PROC_TREE
    8: 
    9: #include <errno.h>
   10: #include <signal.h>
   11: #include <sys/wait.h>
   12: 
   13: #include <linux/sched.h>
   14: #include <linux/kernel.h>
   15: #include <linux/tty.h>
   16: #include <asm/segment.h>
   17: 
   18: int sys_close(int fd);
   19: 
   20: int send_sig(long sig,struct task_struct * p,int priv)
   21: {
   22: 	if (!p || (sig < 0) || (sig > 32))
   23: 		return -EINVAL;
   24: 	if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
   25: 	    (current->euid != p->euid) && (current->uid != p->uid) && !suser())
   26: 		return -EPERM;
   27: 	if (!sig)
   28: 		return 0;
   29: 	if ((sig == SIGKILL) || (sig == SIGCONT)) {
   30: 		if (p->state == TASK_STOPPED)
   31: 			p->state = TASK_RUNNING;
   32: 		p->exit_code = 0;
   33: 		p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
   34: 				(1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
   35: 	} 
   36: 	/* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */
   37: 	if ((sig >= SIGSTOP) && (sig <= SIGTTOU)) 
   38: 		p->signal &= ~(1<<(SIGCONT-1));
   39: 	/* Actually deliver the signal */
   40: 	p->signal |= (1<<(sig-1));
   41: 	if (p->flags & PF_PTRACED) {
   42: 		/* save the signal number for wait. */
   43: 		p->exit_code = sig;
   44: 
   45: 		/* we have to make sure the parent process is awake. */
   46: 		if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE)
   47: 			p->p_pptr->state = TASK_RUNNING;
   48: 
   49: 		/* we have to make sure that the process stops. */
   50: 		if (p->state == TASK_INTERRUPTIBLE || p->state == TASK_RUNNING)
   51: 			p->state = TASK_STOPPED;
   52: 	}
   53: 	return 0;
   54: }
   55: 
   56: void release(struct task_struct * p)
   57: {
   58: 	int i;
   59: 
   60: 	if (!p)
   61: 		return;
   62: 	if (p == current) {
   63: 		printk("task releasing itself\n\r");
   64: 		return;
   65: 	}
   66: 	for (i=1 ; i<NR_TASKS ; i++)
   67: 		if (task[i] == p) {
   68: 			task[i] = NULL;
   69: 			REMOVE_LINKS(p);
   70: 			free_page((long) p);
   71: 			return;
   72: 		}
   73: 	panic("trying to release non-existent task");
   74: }
   75: 
   76: #ifdef DEBUG_PROC_TREE
   77: /*
   78:  * Check to see if a task_struct pointer is present in the task[] array
   79:  * Return 0 if found, and 1 if not found.
   80:  */
   81: int bad_task_ptr(struct task_struct *p)
   82: {
   83: 	int 	i;
   84: 
   85: 	if (!p)
   86: 		return 0;
   87: 	for (i=0 ; i<NR_TASKS ; i++)
   88: 		if (task[i] == p)
   89: 			return 0;
   90: 	return 1;
   91: }
   92: 	
   93: /*
   94:  * This routine scans the pid tree and make sure the rep invarient still
   95:  * holds.  Used for debugging only, since it's very slow....
   96:  *
   97:  * It looks a lot scarier than it really is.... we're doing ænothing more
   98:  * than verifying the doubly-linked list foundæin p_ysptr and p_osptr, 
   99:  * and checking it corresponds with the process tree defined by p_cptr and 
  100:  * p_pptr;
  101:  */
  102: void audit_ptree()
  103: {
  104: 	int	i;
  105: 
  106: 	for (i=1 ; i<NR_TASKS ; i++) {
  107: 		if (!task[i])
  108: 			continue;
  109: 		if (bad_task_ptr(task[i]->p_pptr))
  110: 			printk("Warning, pid %d's parent link is bad\n",
  111: 				task[i]->pid);
  112: 		if (bad_task_ptr(task[i]->p_cptr))
  113: 			printk("Warning, pid %d's child link is bad\n",
  114: 				task[i]->pid);
  115: 		if (bad_task_ptr(task[i]->p_ysptr))
  116: 			printk("Warning, pid %d's ys link is bad\n",
  117: 				task[i]->pid);
  118: 		if (bad_task_ptr(task[i]->p_osptr))
  119: 			printk("Warning, pid %d's os link is bad\n",
  120: 				task[i]->pid);
  121: 		if (task[i]->p_pptr == task[i])
  122: 			printk("Warning, pid %d parent link points to self\n");
  123: 		if (task[i]->p_cptr == task[i])
  124: 			printk("Warning, pid %d child link points to self\n");
  125: 		if (task[i]->p_ysptr == task[i])
  126: 			printk("Warning, pid %d ys link points to self\n");
  127: 		if (task[i]->p_osptr == task[i])
  128: 			printk("Warning, pid %d os link points to self\n");
  129: 		if (task[i]->p_osptr) {
  130: 			if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
  131: 				printk(
  132: 			"Warning, pid %d older sibling %d parent is %d\n",
  133: 				task[i]->pid, task[i]->p_osptr->pid,
  134: 				task[i]->p_osptr->p_pptr->pid);
  135: 			if (task[i]->p_osptr->p_ysptr != task[i])
  136: 				printk(
  137: 		"Warning, pid %d older sibling %d has mismatched ys link\n",
  138: 				task[i]->pid, task[i]->p_osptr->pid);
  139: 		}
  140: 		if (task[i]->p_ysptr) {
  141: 			if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
  142: 				printk(
  143: 			"Warning, pid %d younger sibling %d parent is %d\n",
  144: 				task[i]->pid, task[i]->p_osptr->pid,
  145: 				task[i]->p_osptr->p_pptr->pid);
  146: 			if (task[i]->p_ysptr->p_osptr != task[i])
  147: 				printk(
  148: 		"Warning, pid %d younger sibling %d has mismatched os link\n",
  149: 				task[i]->pid, task[i]->p_ysptr->pid);
  150: 		}
  151: 		if (task[i]->p_cptr) {
  152: 			if (task[i]->p_cptr->p_pptr != task[i])
  153: 				printk(
  154: 			"Warning, pid %d youngest child %d has mismatched parent link\n",
  155: 				task[i]->pid, task[i]->p_cptr->pid);
  156: 			if (task[i]->p_cptr->p_ysptr)
  157: 				printk(
  158: 			"Warning, pid %d youngest child %d has non-NULL ys link\n",
  159: 				task[i]->pid, task[i]->p_cptr->pid);
  160: 		}
  161: 	}
  162: }
  163: #endif /* DEBUG_PROC_TREE */
  164: 
  165: /*
  166:  * This checks not only the pgrp, but falls back on the pid if no
  167:  * satisfactory prgp is found. I dunno - gdb doesn't work correctly
  168:  * without this...
  169:  */
  170: int session_of_pgrp(int pgrp)
  171: {
  172: 	struct task_struct **p;
  173: 	int fallback;
  174: 
  175: 	fallback = -1;
  176:  	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  177:  		if (!*p || (*p)->session <= 0)
  178:  			continue;
  179: 		if ((*p)->pgrp == pgrp)
  180: 			return (*p)->session;
  181: 		if ((*p)->pid == pgrp)
  182: 			fallback = (*p)->session;
  183: 	}
  184: 	return fallback;
  185: }
  186: 
  187: int kill_pg(int pgrp, int sig, int priv)
  188: {
  189: 	struct task_struct **p;
  190: 	int err,retval = -ESRCH;
  191: 	int found = 0;
  192: 
  193: 	if (sig<0 || sig>32 || pgrp<=0)
  194: 		return -EINVAL;
  195:  	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
  196: 		if (*p && (*p)->pgrp == pgrp) {
  197: 			if (sig && (err = send_sig(sig,*p,priv)))
  198: 				retval = err;
  199: 			else
  200: 				found++;
  201: 		}
  202: 	return(found ? 0 : retval);
  203: }
  204: 
  205: int kill_proc(int pid, int sig, int priv)
  206: {
  207:  	struct task_struct **p;
  208: 
  209: 	if (sig<0 || sig>32)
  210: 		return -EINVAL;
  211: 	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
  212: 		if (*p && (*p)->pid == pid)
  213: 			return(sig ? send_sig(sig,*p,priv) : 0);
  214: 	return(-ESRCH);
  215: }
  216: 
  217: /*
  218:  * POSIX specifies that kill(-1,sig) is unspecified, but what we have
  219:  * is probably wrong.  Should make it like BSD or SYSV.
  220:  */
  221: int sys_kill(int pid,int sig)
  222: {
  223: 	struct task_struct **p = NR_TASKS + task;
  224: 	int err, retval = 0, count = 0;
  225: 
  226: 	if (!pid)
  227: 		return(kill_pg(current->pgrp,sig,0));
  228: 	if (pid == -1) {
  229: 		while (--p > &FIRST_TASK)
  230: 			if (*p && (*p)->pid > 1 && *p != current) {
  231: 				++count;
  232: 				if ((err = send_sig(sig,*p,0)) != -EPERM)
  233: 					retval = err;
  234: 			}
  235: 		return(count ? retval : -ESRCH);
  236: 	}
  237: 	if (pid < 0) 
  238: 		return(kill_pg(-pid,sig,0));
  239: 	/* Normal kill */
  240: 	return(kill_proc(pid,sig,0));
  241: }
  242: 
  243: /*
  244:  * Determine if a process group is "orphaned", according to the POSIX
  245:  * definition in 2.2.2.52.  Orphaned process groups are not to be affected
  246:  * by terminal-generated stop signals.  Newly orphaned process groups are 
  247:  * to receive a SIGHUP and a SIGCONT.
  248:  * 
  249:  * "I ask you, have you ever known what it is to be an orphan?"
  250:  */
  251: int is_orphaned_pgrp(int pgrp)
  252: {
  253: 	struct task_struct **p;
  254: 
  255: 	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  256: 		if (!(*p) ||
  257: 		    ((*p)->pgrp != pgrp) || 
  258: 		    ((*p)->state == TASK_ZOMBIE) ||
  259: 		    ((*p)->p_pptr->pid == 1))
  260: 			continue;
  261: 		if (((*p)->p_pptr->pgrp != pgrp) &&
  262: 		    ((*p)->p_pptr->session == (*p)->session))
  263: 			return 0;
  264: 	}
  265: 	return(1);	/* (sighing) "Often!" */
  266: }
  267: 
  268: static int has_stopped_jobs(int pgrp)
  269: {
  270: 	struct task_struct ** p;
  271: 
  272: 	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
  273: 		if (!*p || (*p)->pgrp != pgrp)
  274: 			continue;
  275: 		if ((*p)->state == TASK_STOPPED)
  276: 			return(1);
  277: 	}
  278: 	return(0);
  279: }
  280: 
  281: static void forget_original_parent(struct task_struct * father)
  282: {
  283: 	struct task_struct ** p;
  284: 
  285: 	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
  286: 		if (*p && (*p)->p_opptr == father)
  287: 			(*p)->p_opptr = task[1];
  288: }
  289: 
  290: volatile void do_exit(long code)
  291: {
  292: 	struct task_struct *p;
  293: 	int i;
  294: 
  295: 	free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
  296: 	free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
  297: 	for (i=0 ; i<NR_OPEN ; i++)
  298: 		if (current->filp[i])
  299: 			sys_close(i);
  300: 	forget_original_parent(current);
  301: 	iput(current->pwd);
  302: 	current->pwd = NULL;
  303: 	iput(current->root);
  304: 	current->root = NULL;
  305: 	iput(current->executable);
  306: 	current->executable = NULL;
  307: 	for (i=0; i < current->numlibraries; i++) {
  308: 		iput(current->libraries[i].library);
  309: 		current->libraries[i].library = NULL;
  310: 	}	
  311: 	current->state = TASK_ZOMBIE;
  312: 	current->exit_code = code;
  313: 	current->rss = 0;
  314: 	/* 
  315: 	 * Check to see if any process groups have become orphaned
  316: 	 * as a result of our exiting, and if they have any stopped
  317: 	 * jobs, send them a SIGUP and then a SIGCONT.  (POSIX 3.2.2.2)
  318: 	 *
  319: 	 * Case i: Our father is in a different pgrp than we are
  320: 	 * and we were the only connection outside, so our pgrp
  321: 	 * is about to become orphaned.
  322:  	 */
  323: 	if ((current->p_pptr->pgrp != current->pgrp) &&
  324: 	    (current->p_pptr->session == current->session) &&
  325: 	    is_orphaned_pgrp(current->pgrp) &&
  326: 	    has_stopped_jobs(current->pgrp)) {
  327: 		kill_pg(current->pgrp,SIGHUP,1);
  328: 		kill_pg(current->pgrp,SIGCONT,1);
  329: 	}
  330: 	/* Let father know we died */
  331: 	send_sig (SIGCHLD, current->p_pptr, 1);
  332: 	
  333: 	/*
  334: 	 * This loop does two things:
  335: 	 * 
  336:   	 * A.  Make init inherit all the child processes
  337: 	 * B.  Check to see if any process groups have become orphaned
  338: 	 *	as a result of our exiting, and if they have any stopped
  339: 	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
  340: 	 */
  341: 	while (p = current->p_cptr) {
  342: 		current->p_cptr = p->p_osptr;
  343: 		p->p_ysptr = NULL;
  344: 		p->flags &= ~PF_PTRACED;
  345: 		p->p_pptr = task[1];
  346: 		p->p_osptr = p->p_pptr->p_cptr;
  347: 		p->p_osptr->p_ysptr = p;
  348: 		p->p_pptr->p_cptr = p;
  349: 		if (p->state == TASK_ZOMBIE)
  350: 			p->p_pptr->signal |= (1<<(SIGCHLD-1));
  351: 		/*
  352: 		 * process group orphan check
  353: 		 * Case ii: Our child is in a different pgrp 
  354: 		 * than we are, and it was the only connection
  355: 		 * outside, so the child pgrp is now orphaned.
  356: 		 */
  357: 		if ((p->pgrp != current->pgrp) &&
  358: 		    (p->session == current->session) &&
  359: 		    is_orphaned_pgrp(p->pgrp) &&
  360: 		    has_stopped_jobs(p->pgrp)) {
  361: 			kill_pg(p->pgrp,SIGHUP,1);
  362: 			kill_pg(p->pgrp,SIGCONT,1);
  363: 		}
  364: 	}
  365: 	if (current->leader) {
  366: 		struct task_struct **p;
  367: 		struct tty_struct *tty;
  368: 
  369: 		if (current->tty >= 0) {
  370: 			tty = TTY_TABLE(current->tty);
  371: 			if (tty->pgrp > 0)
  372: 				kill_pg(tty->pgrp, SIGHUP, 1);
  373: 			tty->pgrp = -1;
  374: 			tty->session = 0;
  375: 		}
  376: 	 	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
  377: 			if (*p && (*p)->session == current->session)
  378: 				(*p)->tty = -1;
  379: 	}
  380: 	if (last_task_used_math == current)
  381: 		last_task_used_math = NULL;
  382: #ifdef DEBUG_PROC_TREE
  383: 	audit_ptree();
  384: #endif
  385: 	schedule();
  386: }
  387: 
  388: int sys_exit(int error_code)
  389: {
  390: 	do_exit((error_code&0xff)<<8);
  391: }
  392: 
  393: int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
  394: {
  395: 	int flag;
  396: 	struct task_struct *p;
  397: 	unsigned long oldblocked;
  398: 
  399: 	if (stat_addr)
  400: 		verify_area(stat_addr,4);
  401: repeat:
  402: 	flag=0;
  403:  	for (p = current->p_cptr ; p ; p = p->p_osptr) {
  404: 		if (pid>0) {
  405: 			if (p->pid != pid)
  406: 				continue;
  407: 		} else if (!pid) {
  408: 			if (p->pgrp != current->pgrp)
  409: 				continue;
  410: 		} else if (pid != -1) {
  411: 			if (p->pgrp != -pid)
  412: 				continue;
  413: 		}
  414: 		switch (p->state) {
  415: 			case TASK_STOPPED:
  416: 				if (!p->exit_code)
  417: 					continue;
  418: 				if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
  419: 					continue;
  420: 				if (stat_addr)
  421: 					put_fs_long((p->exit_code << 8) | 0x7f,
  422: 						stat_addr);
  423: 				p->exit_code = 0;
  424: 				return p->pid;
  425: 			case TASK_ZOMBIE:
  426: 				current->cutime += p->utime + p->cutime;
  427: 				current->cstime += p->stime + p->cstime;
  428: 				current->cmin_flt += p->min_flt + p->cmin_flt;
  429: 				current->cmaj_flt += p->maj_flt + p->cmaj_flt;
  430: 				flag = p->pid;
  431: 				if (stat_addr)
  432: 					put_fs_long(p->exit_code, stat_addr);
  433: 				if (p->p_opptr != p->p_pptr) {
  434: 					REMOVE_LINKS(p);
  435: 					p->p_pptr = p->p_opptr;
  436: 					SET_LINKS(p);
  437: 					send_sig(SIGCHLD,p->p_pptr,1);
  438: 				} else
  439: 					release(p);
  440: #ifdef DEBUG_PROC_TREE
  441: 				audit_ptree();
  442: #endif
  443: 				return flag;
  444: 			default:
  445: 				flag=1;
  446: 				continue;
  447: 		}
  448: 	}
  449: 	if (flag) {
  450: 		if (options & WNOHANG)
  451: 			return 0;
  452: 		current->state=TASK_INTERRUPTIBLE;
  453: 		oldblocked = current->blocked;
  454: 		current->blocked &= ~(1<<(SIGCHLD-1));
  455: 		schedule();
  456: 		current->blocked = oldblocked;
  457: 		if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1))))
  458: 			return -ERESTARTSYS;
  459: 		else
  460: 			goto repeat;
  461: 	}
  462: 	return -ECHILD;
  463: }

unix.superglobalmegacorp.com