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

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

unix.superglobalmegacorp.com