root/kernel/exit.c

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

DEFINITIONS

This source file includes following definitions.
  1. send_sig
  2. release
  3. bad_task_ptr
  4. audit_ptree
  5. session_of_pgrp
  6. kill_pg
  7. kill_proc
  8. sys_kill
  9. is_orphaned_pgrp
  10. has_stopped_jobs
  11. forget_original_parent
  12. do_exit
  13. sys_exit
  14. sys_waitpid

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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()
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412         do_exit((error_code&0xff)<<8);
 413 }
 414 
 415 int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

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