File:  [Early Linux] / linux / kernel / exit.c
Revision 1.1.1.11 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:13:04 2018 UTC (23 months, 2 weeks ago) by root
Branches: linus, MAIN
CVS tags: linux097, HEAD
linux 0.97

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

unix.superglobalmegacorp.com