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. do_exit
  12. sys_exit
  13. sys_waitpid

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

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