root/kernel/exit.c

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

DEFINITIONS

This source file includes following definitions.
  1. release
  2. send_sig
  3. kill_session
  4. sys_kill
  5. tell_father
  6. do_exit
  7. sys_exit
  8. sys_waitpid

   1 /*
   2  *  linux/kernel/exit.c
   3  *
   4  *  (C) 1991  Linus Torvalds
   5  */
   6 
   7 #include <errno.h>
   8 #include <signal.h>
   9 #include <sys/wait.h>
  10 
  11 #include <linux/sched.h>
  12 #include <linux/kernel.h>
  13 #include <linux/tty.h>
  14 #include <asm/segment.h>
  15 
  16 int sys_pause(void);
  17 int sys_close(int fd);
  18 
  19 void release(struct task_struct * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  20 {
  21         int i;
  22 
  23         if (!p)
  24                 return;
  25         for (i=1 ; i<NR_TASKS ; i++)
  26                 if (task[i]==p) {
  27                         task[i]=NULL;
  28                         free_page((long)p);
  29                         schedule();
  30                         return;
  31                 }
  32         panic("trying to release non-existent task");
  33 }
  34 
  35 static inline int send_sig(long sig,struct task_struct * p,int priv)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37         if (!p || sig<1 || sig>32)
  38                 return -EINVAL;
  39         if (priv || (current->euid==p->euid) || suser())
  40                 p->signal |= (1<<(sig-1));
  41         else
  42                 return -EPERM;
  43         return 0;
  44 }
  45 
  46 static void kill_session(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48         struct task_struct **p = NR_TASKS + task;
  49         
  50         while (--p > &FIRST_TASK) {
  51                 if (*p && (*p)->session == current->session)
  52                         (*p)->signal |= 1<<(SIGHUP-1);
  53         }
  54 }
  55 
  56 /*
  57  * XXX need to check permissions needed to send signals to process
  58  * groups, etc. etc.  kill() permissions semantics are tricky!
  59  */
  60 int sys_kill(int pid,int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         struct task_struct **p = NR_TASKS + task;
  63         int err, retval = 0;
  64 
  65         if (!pid) while (--p > &FIRST_TASK) {
  66                 if (*p && (*p)->pgrp == current->pid) 
  67                         if (err=send_sig(sig,*p,1))
  68                                 retval = err;
  69         } else if (pid>0) while (--p > &FIRST_TASK) {
  70                 if (*p && (*p)->pid == pid) 
  71                         if (err=send_sig(sig,*p,0))
  72                                 retval = err;
  73         } else if (pid == -1) while (--p > &FIRST_TASK)
  74                 if (err = send_sig(sig,*p,0))
  75                         retval = err;
  76         else while (--p > &FIRST_TASK)
  77                 if (*p && (*p)->pgrp == -pid)
  78                         if (err = send_sig(sig,*p,0))
  79                                 retval = err;
  80         return retval;
  81 }
  82 
  83 static void tell_father(int pid)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85         int i;
  86 
  87         if (pid)
  88                 for (i=0;i<NR_TASKS;i++) {
  89                         if (!task[i])
  90                                 continue;
  91                         if (task[i]->pid != pid)
  92                                 continue;
  93                         task[i]->signal |= (1<<(SIGCHLD-1));
  94                         return;
  95                 }
  96 /* if we don't find any fathers, we just release ourselves */
  97 /* This is not really OK. Must change it to make father 1 */
  98         printk("BAD BAD - no father found\n\r");
  99         release(current);
 100 }
 101 
 102 int do_exit(long code)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         int i;
 105 
 106         free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
 107         free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
 108         for (i=0 ; i<NR_TASKS ; i++)
 109                 if (task[i] && task[i]->father == current->pid) {
 110                         task[i]->father = 1;
 111                         if (task[i]->state == TASK_ZOMBIE)
 112                                 /* assumption task[1] is always init */
 113                                 (void) send_sig(SIGCHLD, task[1], 1);
 114                 }
 115         for (i=0 ; i<NR_OPEN ; i++)
 116                 if (current->filp[i])
 117                         sys_close(i);
 118         iput(current->pwd);
 119         current->pwd=NULL;
 120         iput(current->root);
 121         current->root=NULL;
 122         iput(current->executable);
 123         current->executable=NULL;
 124         if (current->leader && current->tty >= 0)
 125                 tty_table[current->tty].pgrp = 0;
 126         if (last_task_used_math == current)
 127                 last_task_used_math = NULL;
 128         if (current->leader)
 129                 kill_session();
 130         current->state = TASK_ZOMBIE;
 131         current->exit_code = code;
 132         tell_father(current->father);
 133         schedule();
 134         return (-1);    /* just to suppress warnings */
 135 }
 136 
 137 int sys_exit(int error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139         return do_exit((error_code&0xff)<<8);
 140 }
 141 
 142 int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         int flag, code;
 145         struct task_struct ** p;
 146 
 147         verify_area(stat_addr,4);
 148 repeat:
 149         flag=0;
 150         for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
 151                 if (!*p || *p == current)
 152                         continue;
 153                 if ((*p)->father != current->pid)
 154                         continue;
 155                 if (pid>0) {
 156                         if ((*p)->pid != pid)
 157                                 continue;
 158                 } else if (!pid) {
 159                         if ((*p)->pgrp != current->pgrp)
 160                                 continue;
 161                 } else if (pid != -1) {
 162                         if ((*p)->pgrp != -pid)
 163                                 continue;
 164                 }
 165                 switch ((*p)->state) {
 166                         case TASK_STOPPED:
 167                                 if (!(options & WUNTRACED))
 168                                         continue;
 169                                 put_fs_long(0x7f,stat_addr);
 170                                 return (*p)->pid;
 171                         case TASK_ZOMBIE:
 172                                 current->cutime += (*p)->utime;
 173                                 current->cstime += (*p)->stime;
 174                                 flag = (*p)->pid;
 175                                 code = (*p)->exit_code;
 176                                 release(*p);
 177                                 put_fs_long(code,stat_addr);
 178                                 return flag;
 179                         default:
 180                                 flag=1;
 181                                 continue;
 182                 }
 183         }
 184         if (flag) {
 185                 if (options & WNOHANG)
 186                         return 0;
 187                 current->state=TASK_INTERRUPTIBLE;
 188                 schedule();
 189                 if (!(current->signal &= ~(1<<(SIGCHLD-1))))
 190                         goto repeat;
 191                 else
 192                         return -EINTR;
 193         }
 194         return -ECHILD;
 195 }
 196 
 197 

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