Diff for /linux/kernel/exit.c between versions 1.1.1.1 and 1.1.1.6

version 1.1.1.1, 2018/04/24 18:00:41 version 1.1.1.6, 2018/04/24 18:05:29
Line 1 Line 1
   /*
    *  linux/kernel/exit.c
    *
    *  (C) 1991  Linus Torvalds
    */
   
   #define DEBUG_PROC_TREE
   
 #include <errno.h>  #include <errno.h>
 #include <signal.h>  #include <signal.h>
 #include <sys/wait.h>  #include <sys/wait.h>
Line 7 Line 15
 #include <linux/tty.h>  #include <linux/tty.h>
 #include <asm/segment.h>  #include <asm/segment.h>
   
 int sys_pause(void);  
 int sys_close(int fd);  int sys_close(int fd);
   
   inline int send_sig(long sig,struct task_struct * p,int priv)
   {
           if (!p || (sig < 0) || (sig > 32))
                   return -EINVAL;
           if (!priv && (current->euid!=p->euid) && !suser())
                   return -EPERM;
           if (!sig)
                   return 0;
           if ((sig == SIGKILL) || (sig == SIGCONT)) {
                   if (p->state == TASK_STOPPED)
                           p->state = TASK_RUNNING;
                   p->exit_code = 0;
                   p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
                                   (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
           } 
           /* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */
           if ((sig >= SIGSTOP) && (sig <= SIGTTOU)) 
                   p->signal &= ~(1<<(SIGCONT-1));
           /* Actually deliver the signal */
           p->signal |= (1<<(sig-1));
           if (p->flags & PF_PTRACED) {
                   /* save the signal number for wait. */
                   p->exit_code = sig;
   
                   /* we have to make sure the parent is awake. */
                   if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE)
                           p->p_pptr->state = TASK_RUNNING;
   
                   /* we have to make sure that the process stops. */
                   if (p->state == TASK_INTERRUPTIBLE || p->state == TASK_RUNNING)
                           p->state = TASK_STOPPED;
   
                   if (p == current)
                           schedule();
           }
           return 0;
   }
   
 void release(struct task_struct * p)  void release(struct task_struct * p)
 {  {
         int i;          int i;
   
         if (!p)          if (!p)
                 return;                  return;
           if (p == current) {
                   printk("task releasing itself\n\r");
                   return;
           }
         for (i=1 ; i<NR_TASKS ; i++)          for (i=1 ; i<NR_TASKS ; i++)
                 if (task[i]==p) {                  if (task[i]==p) {
                         task[i]=NULL;                          task[i]=NULL;
                           /* Update links */
                           if (p->p_osptr)
                                   p->p_osptr->p_ysptr = p->p_ysptr;
                           if (p->p_ysptr)
                                   p->p_ysptr->p_osptr = p->p_osptr;
                           else
                                   p->p_pptr->p_cptr = p->p_osptr;
                         free_page((long)p);                          free_page((long)p);
                         schedule();                          schedule();
                         return;                          return;
Line 26  void release(struct task_struct * p) Line 82  void release(struct task_struct * p)
         panic("trying to release non-existent task");          panic("trying to release non-existent task");
 }  }
   
 static inline void send_sig(long sig,struct task_struct * p,int priv)  #ifdef DEBUG_PROC_TREE
   /*
    * Check to see if a task_struct pointer is present in the task[] array
    * Return 0 if found, and 1 if not found.
    */
   int bad_task_ptr(struct task_struct *p)
 {  {
         if (!p || sig<1 || sig>32)          int     i;
                 return;  
         if (priv ||          if (!p)
                 current->uid==p->uid ||                  return 0;
                 current->euid==p->uid ||          for (i=0 ; i<NR_TASKS ; i++)
                 current->uid==p->euid ||                  if (task[i] == p)
                 current->euid==p->euid)                          return 0;
                 p->signal |= (1<<(sig-1));          return 1;
 }  }
           
   /*
    * This routine scans the pid tree and make sure the rep invarient still
    * holds.  Used for debugging only, since it's very slow....
    *
    * It looks a lot scarier than it really is.... we're doing ænothing more
    * than verifying the doubly-linked list foundæin p_ysptr and p_osptr, 
    * and checking it corresponds with the process tree defined by p_cptr and 
    * p_pptr;
    */
   void audit_ptree()
   {
           int     i;
   
           for (i=1 ; i<NR_TASKS ; i++) {
                   if (!task[i])
                           continue;
                   if (bad_task_ptr(task[i]->p_pptr))
                           printk("Warning, pid %d's parent link is bad\n",
                                   task[i]->pid);
                   if (bad_task_ptr(task[i]->p_cptr))
                           printk("Warning, pid %d's child link is bad\n",
                                   task[i]->pid);
                   if (bad_task_ptr(task[i]->p_ysptr))
                           printk("Warning, pid %d's ys link is bad\n",
                                   task[i]->pid);
                   if (bad_task_ptr(task[i]->p_osptr))
                           printk("Warning, pid %d's os link is bad\n",
                                   task[i]->pid);
                   if (task[i]->p_pptr == task[i])
                           printk("Warning, pid %d parent link points to self\n");
                   if (task[i]->p_cptr == task[i])
                           printk("Warning, pid %d child link points to self\n");
                   if (task[i]->p_ysptr == task[i])
                           printk("Warning, pid %d ys link points to self\n");
                   if (task[i]->p_osptr == task[i])
                           printk("Warning, pid %d os link points to self\n");
                   if (task[i]->p_osptr) {
                           if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
                                   printk(
                           "Warning, pid %d older sibling %d parent is %d\n",
                                   task[i]->pid, task[i]->p_osptr->pid,
                                   task[i]->p_osptr->p_pptr->pid);
                           if (task[i]->p_osptr->p_ysptr != task[i])
                                   printk(
                   "Warning, pid %d older sibling %d has mismatched ys link\n",
                                   task[i]->pid, task[i]->p_osptr->pid);
                   }
                   if (task[i]->p_ysptr) {
                           if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
                                   printk(
                           "Warning, pid %d younger sibling %d parent is %d\n",
                                   task[i]->pid, task[i]->p_osptr->pid,
                                   task[i]->p_osptr->p_pptr->pid);
                           if (task[i]->p_ysptr->p_osptr != task[i])
                                   printk(
                   "Warning, pid %d younger sibling %d has mismatched os link\n",
                                   task[i]->pid, task[i]->p_ysptr->pid);
                   }
                   if (task[i]->p_cptr) {
                           if (task[i]->p_cptr->p_pptr != task[i])
                                   printk(
                           "Warning, pid %d youngest child %d has mismatched parent link\n",
                                   task[i]->pid, task[i]->p_cptr->pid);
                           if (task[i]->p_cptr->p_ysptr)
                                   printk(
                           "Warning, pid %d youngest child %d has non-NULL ys link\n",
                                   task[i]->pid, task[i]->p_cptr->pid);
                   }
           }
   }
   #endif /* DEBUG_PROC_TREE */
   
 void do_kill(long pid,long sig,int priv)  int session_of_pgrp(int pgrp)
 {  {
         struct task_struct **p = NR_TASKS + task;          struct task_struct **p;
   
           for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                   if ((*p)->pgrp == pgrp)
                           return((*p)->session);
           return -1;
   }
   
   int kill_pg(int pgrp, int sig, int priv)
   {
           struct task_struct **p;
           int err,retval = -ESRCH;
           int found = 0;
   
           if (sig<0 || sig>32 || pgrp<=0)
                   return -EINVAL;
           for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                   if ((*p)->pgrp == pgrp) {
                           if (sig && (err = send_sig(sig,*p,priv)))
                                   retval = err;
                           else
                                   found++;
                   }
           return(found ? 0 : retval);
   }
   
   int kill_proc(int pid, int sig, int priv)
   {
           struct task_struct **p;
   
         if (!pid) while (--p > &FIRST_TASK) {          if (sig<0 || sig>32)
                 if (*p && (*p)->pgrp == current->pid)                  return -EINVAL;
                         send_sig(sig,*p,priv);          for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
         } else if (pid>0) while (--p > &FIRST_TASK) {                  if ((*p)->pid == pid)
                 if (*p && (*p)->pid == pid)                          return(sig ? send_sig(sig,*p,priv) : 0);
                         send_sig(sig,*p,priv);          return(-ESRCH);
         } else if (pid == -1) while (--p > &FIRST_TASK)  
                 send_sig(sig,*p,priv);  
         else while (--p > &FIRST_TASK)  
                 if (*p && (*p)->pgrp == -pid)  
                         send_sig(sig,*p,priv);  
 }  }
   
   /*
    * POSIX specifies that kill(-1,sig) is unspecified, but what we have
    * is probably wrong.  Should make it like BSD or SYSV.
    */
 int sys_kill(int pid,int sig)  int sys_kill(int pid,int sig)
 {  {
         do_kill(pid,sig,!(current->uid || current->euid));          struct task_struct **p = NR_TASKS + task;
         return 0;          int err, retval = 0;
   
           if (!pid)
                   return(kill_pg(current->pid,sig,0));
           if (pid == -1) {
                   while (--p > &FIRST_TASK)
                           if (err = send_sig(sig,*p,0))
                                   retval = err;
                   return(retval);
           }
           if (pid < 0) 
                   return(kill_pg(-pid,sig,0));
           /* Normal kill */
           return(kill_proc(pid,sig,0));
   }
   
   /*
    * Determine if a process group is "orphaned", according to the POSIX
    * definition in 2.2.2.52.  Orphaned process groups are not to be affected
    * by terminal-generated stop signals.  Newly orphaned process groups are 
    * to receive a SIGHUP and a SIGCONT.
    * 
    * "I ask you, have you ever known what it is to be an orphan?"
    */
   int is_orphaned_pgrp(int pgrp)
   {
           struct task_struct **p;
   
           for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
                   if (!(*p) ||
                       ((*p)->pgrp != pgrp) || 
                       ((*p)->state == TASK_ZOMBIE) ||
                       ((*p)->p_pptr->pid == 1))
                           continue;
                   if (((*p)->p_pptr->pgrp != pgrp) &&
                       ((*p)->p_pptr->session == (*p)->session))
                           return 0;
           }
           return(1);      /* (sighing) "Often!" */
   }
   
   static int has_stopped_jobs(int pgrp)
   {
           struct task_struct ** p;
   
           for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
                   if ((*p)->pgrp != pgrp)
                           continue;
                   if ((*p)->state == TASK_STOPPED)
                           return(1);
           }
           return(0);
 }  }
   
 int do_exit(long code)  volatile void do_exit(long code)
 {  {
           struct task_struct *p;
         int i;          int i;
   
         free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));          free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
         free_page_tables(get_base(current->ldt[2]),get_limit(0x17));          free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
         for (i=0 ; i<NR_TASKS ; i++)  
                 if (task[i] && task[i]->father == current->pid)  
                         task[i]->father = 0;  
         for (i=0 ; i<NR_OPEN ; i++)          for (i=0 ; i<NR_OPEN ; i++)
                 if (current->filp[i])                  if (current->filp[i])
                         sys_close(i);                          sys_close(i);
         iput(current->pwd);          iput(current->pwd);
         current->pwd=NULL;          current->pwd = NULL;
         iput(current->root);          iput(current->root);
         current->root=NULL;          current->root = NULL;
         if (current->leader && current->tty >= 0)          iput(current->executable);
                 tty_table[current->tty].pgrp = 0;          current->executable = NULL;
           iput(current->library);
           current->library = NULL;
           current->state = TASK_ZOMBIE;
           current->exit_code = code;
           /* 
            * Check to see if any process groups have become orphaned
            * as a result of our exiting, and if they have any stopped
            * jobs, send them a SIGUP and then a SIGCONT.  (POSIX 3.2.2.2)
            *
            * Case i: Our father is in a different pgrp than we are
            * and we were the only connection outside, so our pgrp
            * is about to become orphaned.
            */
           if ((current->p_pptr->pgrp != current->pgrp) &&
               (current->p_pptr->session == current->session) &&
               is_orphaned_pgrp(current->pgrp) &&
               has_stopped_jobs(current->pgrp)) {
                   kill_pg(current->pgrp,SIGHUP,1);
                   kill_pg(current->pgrp,SIGCONT,1);
           }
           /* Let father know we died */
           send_sig (SIGCHLD, current->p_pptr, 1);
           
           /*
            * This loop does two things:
            * 
            * A.  Make init inherit all the child processes
            * B.  Check to see if any process groups have become orphaned
            *      as a result of our exiting, and if they have any stopped
            *      jons, send them a SIGUP and then a SIGCONT.  (POSIX 3.2.2.2)
            */
           if (p = current->p_cptr) {
                   while (1) {
                           p->flags &= ~PF_PTRACED;
                           p->p_pptr = task[1];
                           if (p->state == TASK_ZOMBIE)
                                   task[1]->signal |= (1<<(SIGCHLD-1));
                           /*
                            * process group orphan check
                            * Case ii: Our child is in a different pgrp 
                            * than we are, and it was the only connection
                            * outside, so the child pgrp is now orphaned.
                            */
                           if ((p->pgrp != current->pgrp) &&
                               (p->session == current->session) &&
                               is_orphaned_pgrp(p->pgrp) &&
                               has_stopped_jobs(p->pgrp)) {
                                   kill_pg(p->pgrp,SIGHUP,1);
                                   kill_pg(p->pgrp,SIGCONT,1);
                           }
                           if (p->p_osptr) {
                                   p = p->p_osptr;
                                   continue;
                           }
                           /*
                            * This is it; link everything into init's children 
                            * and leave 
                            */
                           p->p_osptr = task[1]->p_cptr;
                           task[1]->p_cptr->p_ysptr = p;
                           task[1]->p_cptr = current->p_cptr;
                           current->p_cptr = 0;
                           break;
                   }
           }
           if (current->leader) {
                   struct task_struct **p;
                   struct tty_struct *tty;
   
                   if (current->tty >= 0) {
                           tty = TTY_TABLE(current->tty);
                           if (tty->pgrp > 0)
                                   kill_pg(tty->pgrp, SIGHUP, 1);
                           tty->pgrp = -1;
                           tty->session = 0;
                   }
                   for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                           if ((*p)->session == current->session)
                                   (*p)->tty = -1;
           }
         if (last_task_used_math == current)          if (last_task_used_math == current)
                 last_task_used_math = NULL;                  last_task_used_math = NULL;
         if (current->father) {  #ifdef DEBUG_PROC_TREE
                 current->state = TASK_ZOMBIE;          audit_ptree();
                 do_kill(current->father,SIGCHLD,1);  #endif
                 current->exit_code = code;  
         } else  
                 release(current);  
         schedule();          schedule();
         return (-1);    /* just to suppress warnings */  
 }  }
   
 int sys_exit(int error_code)  int sys_exit(int error_code)
 {  {
         return do_exit((error_code&0xff)<<8);          do_exit((error_code&0xff)<<8);
 }  }
   
 int sys_waitpid(pid_t pid,int * stat_addr, int options)  int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
 {  {
         int flag=0;          int flag;
         struct task_struct ** p;          struct task_struct *p;
           unsigned long oldblocked;
   
         verify_area(stat_addr,4);          if (stat_addr)
                   verify_area(stat_addr,4);
 repeat:  repeat:
         for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)          flag=0;
                 if (*p && *p != current &&          for (p = current->p_cptr ; p ; p = p->p_osptr) {
                    (pid==-1 || (*p)->pid==pid ||                  if (pid>0) {
                    (pid==0 && (*p)->pgrp==current->pgrp) ||                          if (p->pid != pid)
                    (pid<0 && (*p)->pgrp==-pid)))                                  continue;
                         if ((*p)->father == current->pid) {                  } else if (!pid) {
                           if (p->pgrp != current->pgrp)
                                   continue;
                   } else if (pid != -1) {
                           if (p->pgrp != -pid)
                                   continue;
                   }
                   switch (p->state) {
                           case TASK_STOPPED:
                                   if (!(options & WUNTRACED) || 
                                       !p->exit_code)
                                           continue;
                                   if (stat_addr)
                                           put_fs_long((p->exit_code << 8) | 0x7f,
                                                   stat_addr);
                                   p->exit_code = 0;
                                   return p->pid;
                           case TASK_ZOMBIE:
                                   current->cutime += p->utime;
                                   current->cstime += p->stime;
                                   flag = p->pid;
                                   if (stat_addr)
                                           put_fs_long(p->exit_code, stat_addr);
                                   release(p);
   #ifdef DEBUG_PROC_TREE
                                   audit_ptree();
   #endif
                                   return flag;
                           default:
                                 flag=1;                                  flag=1;
                                 if ((*p)->state==TASK_ZOMBIE) {                                  continue;
                                         put_fs_long((*p)->exit_code,                  }
                                                 (unsigned long *) stat_addr);          }
                                         current->cutime += (*p)->utime;  
                                         current->cstime += (*p)->stime;  
                                         flag = (*p)->pid;  
                                         release(*p);  
                                         return flag;  
                                 }  
                         }  
         if (flag) {          if (flag) {
                 if (options & WNOHANG)                  if (options & WNOHANG)
                         return 0;                          return 0;
                 sys_pause();                  current->state=TASK_INTERRUPTIBLE;
                 if (!(current->signal &= ~(1<<(SIGCHLD-1))))                  oldblocked = current->blocked;
                         goto repeat;                  current->blocked &= ~(1<<(SIGCHLD-1));
                   schedule();
                   current->blocked = oldblocked;
                   if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1))))
                           return -ERESTARTSYS;
                 else                  else
                         return -EINTR;                          goto repeat;
         }          }
         return -ECHILD;          return -ECHILD;
 }  }

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.6


unix.superglobalmegacorp.com