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