root/kernel/exit.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. generate
  2. send_sig
  3. notify_parent
  4. release
  5. bad_task_ptr
  6. audit_ptree
  7. session_of_pgrp
  8. kill_pg
  9. kill_sl
  10. kill_proc
  11. sys_kill
  12. is_orphaned_pgrp
  13. has_stopped_jobs
  14. forget_original_parent
  15. __exit_files
  16. exit_files
  17. __exit_fs
  18. exit_fs
  19. __exit_sighand
  20. exit_sighand
  21. exit_mm
  22. exit_notify
  23. do_exit
  24. sys_exit
  25. sys_wait4
  26. sys_waitpid

   1 /*
   2  *  linux/kernel/exit.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #undef 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/resource.h>
  15 #include <linux/mm.h>
  16 #include <linux/tty.h>
  17 #include <linux/malloc.h>
  18 
  19 #include <asm/segment.h>
  20 #include <asm/pgtable.h>
  21 
  22 extern void sem_exit (void);
  23 extern void acct_process (long exitcode);
  24 extern void kerneld_exit(void);
  25 
  26 int getrusage(struct task_struct *, int, struct rusage *);
  27 
  28 static inline void generate(unsigned long sig, struct task_struct * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  29 {
  30         unsigned long mask = 1 << (sig-1);
  31         struct sigaction * sa = sig + p->sig->action - 1;
  32 
  33         /*
  34          * Optimize away the signal, if it's a signal that can
  35          * be handled immediately (ie non-blocked and untraced)
  36          * and that is ignored (either explicitly or by default)
  37          */
  38         if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) {
  39                 /* don't bother with ignored signals (but SIGCHLD is special) */
  40                 if (sa->sa_handler == SIG_IGN && sig != SIGCHLD)
  41                         return;
  42                 /* some signals are ignored by default.. (but SIGCONT already did its deed) */
  43                 if ((sa->sa_handler == SIG_DFL) &&
  44                     (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG))
  45                         return;
  46         }
  47         p->signal |= mask;
  48         if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked))
  49                 wake_up_process(p);
  50 }
  51 
  52 int send_sig(unsigned long sig,struct task_struct * p,int priv)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54         if (!p || sig > 32)
  55                 return -EINVAL;
  56         if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
  57             (current->euid ^ p->euid) && (current->euid ^ p->uid) &&
  58             (current->uid ^ p->euid) && (current->uid ^ p->uid) &&
  59             !suser())
  60                 return -EPERM;
  61         if (!sig)
  62                 return 0;
  63         /*
  64          * Forget it if the process is already zombie'd.
  65          */
  66         if (!p->sig)
  67                 return 0;
  68         if ((sig == SIGKILL) || (sig == SIGCONT)) {
  69                 if (p->state == TASK_STOPPED)
  70                         wake_up_process(p);
  71                 p->exit_code = 0;
  72                 p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
  73                                 (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
  74         }
  75         if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
  76                 p->signal &= ~(1<<(SIGCONT-1));
  77         /* Actually generate the signal */
  78         generate(sig,p);
  79         return 0;
  80 }
  81 
  82 void notify_parent(struct task_struct * tsk)
     /* [previous][next][first][last][top][bottom][index][help] */
  83 {
  84         if (tsk->p_pptr == task[smp_num_cpus])          /* Init */
  85                 tsk->exit_signal = SIGCHLD;
  86         send_sig(tsk->exit_signal, tsk->p_pptr, 1);
  87         wake_up_interruptible(&tsk->p_pptr->wait_chldexit);
  88 }
  89 
  90 void release(struct task_struct * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         int i;
  93 
  94         if (!p)
  95                 return;
  96         if (p == current) {
  97                 printk("task releasing itself\n");
  98                 return;
  99         }
 100         for (i=1 ; i<NR_TASKS ; i++)
 101                 if (task[i] == p) {
 102                         nr_tasks--;
 103                         task[i] = NULL;
 104                         REMOVE_LINKS(p);
 105                         release_thread(p);
 106                         if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page)
 107                                 printk(KERN_ALERT "release: %s kernel stack corruption. Aiee\n", p->comm);
 108                         free_kernel_stack(p->kernel_stack_page);
 109                         current->cmin_flt += p->min_flt + p->cmin_flt;
 110                         current->cmaj_flt += p->maj_flt + p->cmaj_flt;
 111                         current->cnswap += p->nswap + p->cnswap;
 112                         kfree(p);
 113                         return;
 114                 }
 115         panic("trying to release non-existent task");
 116 }
 117 
 118 #ifdef DEBUG_PROC_TREE
 119 /*
 120  * Check to see if a task_struct pointer is present in the task[] array
 121  * Return 0 if found, and 1 if not found.
 122  */
 123 int bad_task_ptr(struct task_struct *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125         int     i;
 126 
 127         if (!p)
 128                 return 0;
 129         for (i=0 ; i<NR_TASKS ; i++)
 130                 if (task[i] == p)
 131                         return 0;
 132         return 1;
 133 }
 134         
 135 /*
 136  * This routine scans the pid tree and makes sure the rep invariant still
 137  * holds.  Used for debugging only, since it's very slow....
 138  *
 139  * It looks a lot scarier than it really is.... we're doing nothing more
 140  * than verifying the doubly-linked list found in p_ysptr and p_osptr, 
 141  * and checking it corresponds with the process tree defined by p_cptr and 
 142  * p_pptr;
 143  */
 144 void audit_ptree(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146         int     i;
 147 
 148         for (i=1 ; i<NR_TASKS ; i++) {
 149                 if (!task[i])
 150                         continue;
 151                 if (bad_task_ptr(task[i]->p_pptr))
 152                         printk("Warning, pid %d's parent link is bad\n",
 153                                 task[i]->pid);
 154                 if (bad_task_ptr(task[i]->p_cptr))
 155                         printk("Warning, pid %d's child link is bad\n",
 156                                 task[i]->pid);
 157                 if (bad_task_ptr(task[i]->p_ysptr))
 158                         printk("Warning, pid %d's ys link is bad\n",
 159                                 task[i]->pid);
 160                 if (bad_task_ptr(task[i]->p_osptr))
 161                         printk("Warning, pid %d's os link is bad\n",
 162                                 task[i]->pid);
 163                 if (task[i]->p_pptr == task[i])
 164                         printk("Warning, pid %d parent link points to self\n",
 165                                 task[i]->pid);
 166                 if (task[i]->p_cptr == task[i])
 167                         printk("Warning, pid %d child link points to self\n",
 168                                 task[i]->pid);
 169                 if (task[i]->p_ysptr == task[i])
 170                         printk("Warning, pid %d ys link points to self\n",
 171                                 task[i]->pid);
 172                 if (task[i]->p_osptr == task[i])
 173                         printk("Warning, pid %d os link points to self\n",
 174                                 task[i]->pid);
 175                 if (task[i]->p_osptr) {
 176                         if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
 177                                 printk(
 178                         "Warning, pid %d older sibling %d parent is %d\n",
 179                                 task[i]->pid, task[i]->p_osptr->pid,
 180                                 task[i]->p_osptr->p_pptr->pid);
 181                         if (task[i]->p_osptr->p_ysptr != task[i])
 182                                 printk(
 183                 "Warning, pid %d older sibling %d has mismatched ys link\n",
 184                                 task[i]->pid, task[i]->p_osptr->pid);
 185                 }
 186                 if (task[i]->p_ysptr) {
 187                         if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
 188                                 printk(
 189                         "Warning, pid %d younger sibling %d parent is %d\n",
 190                                 task[i]->pid, task[i]->p_osptr->pid,
 191                                 task[i]->p_osptr->p_pptr->pid);
 192                         if (task[i]->p_ysptr->p_osptr != task[i])
 193                                 printk(
 194                 "Warning, pid %d younger sibling %d has mismatched os link\n",
 195                                 task[i]->pid, task[i]->p_ysptr->pid);
 196                 }
 197                 if (task[i]->p_cptr) {
 198                         if (task[i]->p_cptr->p_pptr != task[i])
 199                                 printk(
 200                         "Warning, pid %d youngest child %d has mismatched parent link\n",
 201                                 task[i]->pid, task[i]->p_cptr->pid);
 202                         if (task[i]->p_cptr->p_ysptr)
 203                                 printk(
 204                         "Warning, pid %d youngest child %d has non-NULL ys link\n",
 205                                 task[i]->pid, task[i]->p_cptr->pid);
 206                 }
 207         }
 208 }
 209 #endif /* DEBUG_PROC_TREE */
 210 
 211 /*
 212  * This checks not only the pgrp, but falls back on the pid if no
 213  * satisfactory pgrp is found. I dunno - gdb doesn't work correctly
 214  * without this...
 215  */
 216 int session_of_pgrp(int pgrp)
     /* [previous][next][first][last][top][bottom][index][help] */
 217 {
 218         struct task_struct *p;
 219         int fallback;
 220 
 221         fallback = -1;
 222         for_each_task(p) {
 223                 if (p->session <= 0)
 224                         continue;
 225                 if (p->pgrp == pgrp)
 226                         return p->session;
 227                 if (p->pid == pgrp)
 228                         fallback = p->session;
 229         }
 230         return fallback;
 231 }
 232 
 233 /*
 234  * kill_pg() sends a signal to a process group: this is what the tty
 235  * control characters do (^C, ^Z etc)
 236  */
 237 int kill_pg(int pgrp, int sig, int priv)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239         struct task_struct *p;
 240         int err,retval = -ESRCH;
 241         int found = 0;
 242 
 243         if (sig<0 || sig>32 || pgrp<=0)
 244                 return -EINVAL;
 245         for_each_task(p) {
 246                 if (p->pgrp == pgrp) {
 247                         if ((err = send_sig(sig,p,priv)) != 0)
 248                                 retval = err;
 249                         else
 250                                 found++;
 251                 }
 252         }
 253         return(found ? 0 : retval);
 254 }
 255 
 256 /*
 257  * kill_sl() sends a signal to the session leader: this is used
 258  * to send SIGHUP to the controlling process of a terminal when
 259  * the connection is lost.
 260  */
 261 int kill_sl(int sess, int sig, int priv)
     /* [previous][next][first][last][top][bottom][index][help] */
 262 {
 263         struct task_struct *p;
 264         int err,retval = -ESRCH;
 265         int found = 0;
 266 
 267         if (sig<0 || sig>32 || sess<=0)
 268                 return -EINVAL;
 269         for_each_task(p) {
 270                 if (p->session == sess && p->leader) {
 271                         if ((err = send_sig(sig,p,priv)) != 0)
 272                                 retval = err;
 273                         else
 274                                 found++;
 275                 }
 276         }
 277         return(found ? 0 : retval);
 278 }
 279 
 280 int kill_proc(int pid, int sig, int priv)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282         struct task_struct *p;
 283 
 284         if (sig<0 || sig>32)
 285                 return -EINVAL;
 286         for_each_task(p) {
 287                 if (p && p->pid == pid)
 288                         return send_sig(sig,p,priv);
 289         }
 290         return(-ESRCH);
 291 }
 292 
 293 /*
 294  * POSIX specifies that kill(-1,sig) is unspecified, but what we have
 295  * is probably wrong.  Should make it like BSD or SYSV.
 296  */
 297 asmlinkage int sys_kill(int pid,int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 298 {
 299         int err, retval = 0, count = 0;
 300 
 301         if (!pid)
 302                 return(kill_pg(current->pgrp,sig,0));
 303         if (pid == -1) {
 304                 struct task_struct * p;
 305                 for_each_task(p) {
 306                         if (p->pid > 1 && p != current) {
 307                                 ++count;
 308                                 if ((err = send_sig(sig,p,0)) != -EPERM)
 309                                         retval = err;
 310                         }
 311                 }
 312                 return(count ? retval : -ESRCH);
 313         }
 314         if (pid < 0) 
 315                 return(kill_pg(-pid,sig,0));
 316         /* Normal kill */
 317         return(kill_proc(pid,sig,0));
 318 }
 319 
 320 /*
 321  * Determine if a process group is "orphaned", according to the POSIX
 322  * definition in 2.2.2.52.  Orphaned process groups are not to be affected
 323  * by terminal-generated stop signals.  Newly orphaned process groups are 
 324  * to receive a SIGHUP and a SIGCONT.
 325  * 
 326  * "I ask you, have you ever known what it is to be an orphan?"
 327  */
 328 int is_orphaned_pgrp(int pgrp)
     /* [previous][next][first][last][top][bottom][index][help] */
 329 {
 330         struct task_struct *p;
 331 
 332         for_each_task(p) {
 333                 if ((p->pgrp != pgrp) || 
 334                     (p->state == TASK_ZOMBIE) ||
 335                     (p->p_pptr->pid == 1))
 336                         continue;
 337                 if ((p->p_pptr->pgrp != pgrp) &&
 338                     (p->p_pptr->session == p->session))
 339                         return 0;
 340         }
 341         return(1);      /* (sighing) "Often!" */
 342 }
 343 
 344 static inline int has_stopped_jobs(int pgrp)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346         struct task_struct * p;
 347 
 348         for_each_task(p) {
 349                 if (p->pgrp != pgrp)
 350                         continue;
 351                 if (p->state == TASK_STOPPED)
 352                         return(1);
 353         }
 354         return(0);
 355 }
 356 
 357 static inline void forget_original_parent(struct task_struct * father)
     /* [previous][next][first][last][top][bottom][index][help] */
 358 {
 359         struct task_struct * p;
 360 
 361         for_each_task(p) {
 362                 if (p->p_opptr == father)
 363                         if (task[smp_num_cpus]) /* init */
 364                                 p->p_opptr = task[smp_num_cpus];
 365                         else
 366                                 p->p_opptr = task[0];
 367         }
 368 }
 369 
 370 static inline void __exit_files(struct task_struct *tsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 371 {
 372         struct files_struct * files = tsk->files;
 373 
 374         if (files) {
 375                 tsk->files = NULL;
 376                 if (!--files->count) {
 377                         int i;
 378                         for (i=0 ; i<NR_OPEN ; i++) {
 379                                 struct file * filp = files->fd[i];
 380                                 if (!filp)
 381                                         continue;
 382                                 files->fd[i] = NULL;
 383                                 close_fp(filp);
 384                         }
 385                         kfree(files);
 386                 }
 387         }
 388 }
 389 
 390 void exit_files(struct task_struct *tsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 391 {
 392   __exit_files(tsk);
 393 }
 394 
 395 static inline void __exit_fs(struct task_struct *tsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 396 {
 397         struct fs_struct * fs = tsk->fs;
 398 
 399         if (fs) {
 400                 tsk->fs = NULL;
 401                 if (!--fs->count) {
 402                         iput(fs->root);
 403                         iput(fs->pwd);
 404                         kfree(fs);
 405                 }
 406         }
 407 }
 408 
 409 void exit_fs(struct task_struct *tsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 410 {
 411   __exit_fs(tsk);
 412 }
 413 
 414 static inline void __exit_sighand(struct task_struct *tsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 415 {
 416         struct signal_struct * sig = tsk->sig;
 417 
 418         if (sig) {
 419                 tsk->sig = NULL;
 420                 if (!--sig->count) {
 421                         kfree(sig);
 422                 }
 423         }
 424 }
 425 
 426 void exit_sighand(struct task_struct *tsk)
     /* [previous][next][first][last][top][bottom][index][help] */
 427 {
 428         __exit_sighand(tsk);
 429 }
 430 
 431 static inline void exit_mm(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 432 {
 433         struct mm_struct * mm = current->mm;
 434 
 435         /* Set us up to use the kernel mm state */
 436         if (mm != &init_mm) {
 437                 flush_cache_mm(mm);
 438                 flush_tlb_mm(mm);
 439                 current->mm = &init_mm;
 440                 current->swappable = 0;
 441                 SET_PAGE_DIR(current, swapper_pg_dir);
 442 
 443                 /* free the old state - not used any more */
 444                 if (!--mm->count) {
 445                         exit_mmap(mm);
 446                         free_page_tables(mm);
 447                         kfree(mm);
 448                 }
 449         }
 450 }
 451 
 452 /* 
 453  * Send signals to all our closest relatives so that they know
 454  * to properly mourn us..
 455  */
 456 static void exit_notify(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 457 {
 458         struct task_struct * p;
 459 
 460         forget_original_parent(current);
 461         /* 
 462          * Check to see if any process groups have become orphaned
 463          * as a result of our exiting, and if they have any stopped
 464          * jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
 465          *
 466          * Case i: Our father is in a different pgrp than we are
 467          * and we were the only connection outside, so our pgrp
 468          * is about to become orphaned.
 469          */
 470         if ((current->p_pptr->pgrp != current->pgrp) &&
 471             (current->p_pptr->session == current->session) &&
 472             is_orphaned_pgrp(current->pgrp) &&
 473             has_stopped_jobs(current->pgrp)) {
 474                 kill_pg(current->pgrp,SIGHUP,1);
 475                 kill_pg(current->pgrp,SIGCONT,1);
 476         }
 477         /* Let father know we died */
 478         notify_parent(current);
 479         
 480         /*
 481          * This loop does two things:
 482          * 
 483          * A.  Make init inherit all the child processes
 484          * B.  Check to see if any process groups have become orphaned
 485          *      as a result of our exiting, and if they have any stopped
 486          *      jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
 487          */
 488         while ((p = current->p_cptr) != NULL) {
 489                 current->p_cptr = p->p_osptr;
 490                 p->p_ysptr = NULL;
 491                 p->flags &= ~(PF_PTRACED|PF_TRACESYS);
 492                 if (task[smp_num_cpus] && task[smp_num_cpus] != current) /* init */
 493                         p->p_pptr = task[smp_num_cpus];
 494                 else
 495                         p->p_pptr = task[0];
 496                 p->p_osptr = p->p_pptr->p_cptr;
 497                 p->p_osptr->p_ysptr = p;
 498                 p->p_pptr->p_cptr = p;
 499                 if (p->state == TASK_ZOMBIE)
 500                         notify_parent(p);
 501                 /*
 502                  * process group orphan check
 503                  * Case ii: Our child is in a different pgrp 
 504                  * than we are, and it was the only connection
 505                  * outside, so the child pgrp is now orphaned.
 506                  */
 507                 if ((p->pgrp != current->pgrp) &&
 508                     (p->session == current->session) &&
 509                     is_orphaned_pgrp(p->pgrp) &&
 510                     has_stopped_jobs(p->pgrp)) {
 511                         kill_pg(p->pgrp,SIGHUP,1);
 512                         kill_pg(p->pgrp,SIGCONT,1);
 513                 }
 514         }
 515         if (current->leader)
 516                 disassociate_ctty(1);
 517 }
 518 
 519 NORET_TYPE void do_exit(long code)
     /* [previous][next][first][last][top][bottom][index][help] */
 520 {
 521         if (intr_count) {
 522                 printk("Aiee, killing interrupt handler\n");
 523                 intr_count = 0;
 524         }
 525 fake_volatile:
 526         acct_process(code);
 527         current->flags |= PF_EXITING;
 528         del_timer(&current->real_timer);
 529         sem_exit();
 530         kerneld_exit();
 531         exit_mm();
 532         __exit_files(current);
 533         __exit_fs(current);
 534         __exit_sighand(current);
 535         exit_thread();
 536         current->state = TASK_ZOMBIE;
 537         current->exit_code = code;
 538         exit_notify();
 539 #ifdef DEBUG_PROC_TREE
 540         audit_ptree();
 541 #endif
 542         if (current->exec_domain && current->exec_domain->use_count)
 543                 (*current->exec_domain->use_count)--;
 544         if (current->binfmt && current->binfmt->use_count)
 545                 (*current->binfmt->use_count)--;
 546         schedule();
 547 /*
 548  * In order to get rid of the "volatile function does return" message
 549  * I did this little loop that confuses gcc to think do_exit really
 550  * is volatile. In fact it's schedule() that is volatile in some
 551  * circumstances: when current->state = ZOMBIE, schedule() never
 552  * returns.
 553  *
 554  * In fact the natural way to do all this is to have the label and the
 555  * goto right after each other, but I put the fake_volatile label at
 556  * the start of the function just in case something /really/ bad
 557  * happens, and the schedule returns. This way we can try again. I'm
 558  * not paranoid: it's just that everybody is out to get me.
 559  */
 560         goto fake_volatile;
 561 }
 562 
 563 asmlinkage int sys_exit(int error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 564 {
 565         do_exit((error_code&0xff)<<8);
 566 }
 567 
 568 asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
     /* [previous][next][first][last][top][bottom][index][help] */
 569 {
 570         int flag, retval;
 571         struct wait_queue wait = { current, NULL };
 572         struct task_struct *p;
 573 
 574         if (stat_addr) {
 575                 flag = verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr));
 576                 if (flag)
 577                         return flag;
 578         }
 579         if (ru) {
 580                 flag = verify_area(VERIFY_WRITE, ru, sizeof(*ru));
 581                 if (flag)
 582                         return flag;
 583         }
 584         add_wait_queue(&current->wait_chldexit,&wait);
 585 repeat:
 586         flag=0;
 587         for (p = current->p_cptr ; p ; p = p->p_osptr) {
 588                 if (pid>0) {
 589                         if (p->pid != pid)
 590                                 continue;
 591                 } else if (!pid) {
 592                         if (p->pgrp != current->pgrp)
 593                                 continue;
 594                 } else if (pid != -1) {
 595                         if (p->pgrp != -pid)
 596                                 continue;
 597                 }
 598                 /* wait for cloned processes iff the __WCLONE flag is set */
 599                 if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
 600                         continue;
 601                 flag = 1;
 602                 switch (p->state) {
 603                         case TASK_STOPPED:
 604                                 if (!p->exit_code)
 605                                         continue;
 606                                 if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
 607                                         continue;
 608                                 if (ru != NULL)
 609                                         getrusage(p, RUSAGE_BOTH, ru);
 610                                 if (stat_addr)
 611                                         put_user((p->exit_code << 8) | 0x7f,
 612                                                 stat_addr);
 613                                 p->exit_code = 0;
 614                                 retval = p->pid;
 615                                 goto end_wait4;
 616                         case TASK_ZOMBIE:
 617                                 current->cutime += p->utime + p->cutime;
 618                                 current->cstime += p->stime + p->cstime;
 619                                 if (ru != NULL)
 620                                         getrusage(p, RUSAGE_BOTH, ru);
 621                                 if (stat_addr)
 622                                         put_user(p->exit_code, stat_addr);
 623                                 retval = p->pid;
 624                                 if (p->p_opptr != p->p_pptr) {
 625                                         REMOVE_LINKS(p);
 626                                         p->p_pptr = p->p_opptr;
 627                                         SET_LINKS(p);
 628                                         notify_parent(p);
 629                                 } else
 630                                         release(p);
 631 #ifdef DEBUG_PROC_TREE
 632                                 audit_ptree();
 633 #endif
 634                                 goto end_wait4;
 635                         default:
 636                                 continue;
 637                 }
 638         }
 639         if (flag) {
 640                 retval = 0;
 641                 if (options & WNOHANG)
 642                         goto end_wait4;
 643                 current->state=TASK_INTERRUPTIBLE;
 644                 schedule();
 645                 current->signal &= ~(1<<(SIGCHLD-1));
 646                 retval = -ERESTARTSYS;
 647                 if (current->signal & ~current->blocked)
 648                         goto end_wait4;
 649                 goto repeat;
 650         }
 651         retval = -ECHILD;
 652 end_wait4:
 653         remove_wait_queue(&current->wait_chldexit,&wait);
 654         return retval;
 655 }
 656 
 657 #ifndef __alpha__
 658 
 659 /*
 660  * sys_waitpid() remains for compatibility. waitpid() should be
 661  * implemented by calling sys_wait4() from libc.a.
 662  */
 663 asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options)
     /* [previous][next][first][last][top][bottom][index][help] */
 664 {
 665         return sys_wait4(pid, stat_addr, options, NULL);
 666 }
 667 
 668 #endif

/* [previous][next][first][last][top][bottom][index][help] */