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

version 1.1.1.3, 2018/04/24 18:02:23 version 1.1.1.6, 2018/04/24 18:05:29
Line 4 Line 4
  *  (C) 1991  Linus Torvalds   *  (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 13 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 32  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 int 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)
   {
           int     i;
   
           if (!p)
                   return 0;
           for (i=0 ; i<NR_TASKS ; i++)
                   if (task[i] == p)
                           return 0;
           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 */
   
   int session_of_pgrp(int pgrp)
 {  {
         if (!p || sig<1 || sig>32)          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;                  return -EINVAL;
         if (priv || (current->euid==p->euid) || suser())          for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                 p->signal |= (1<<(sig-1));                  if ((*p)->pgrp == pgrp) {
         else                          if (sig && (err = send_sig(sig,*p,priv)))
                 return -EPERM;                                  retval = err;
         return 0;                          else
                                   found++;
                   }
           return(found ? 0 : retval);
 }  }
   
 static void kill_session(void)  int kill_proc(int pid, int sig, int priv)
 {  {
         struct task_struct **p = NR_TASKS + task;          struct task_struct **p;
           
         while (--p > &FIRST_TASK) {          if (sig<0 || sig>32)
                 if (*p && (*p)->session == current->session)                  return -EINVAL;
                         (*p)->signal |= 1<<(SIGHUP-1);          for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
         }                  if ((*p)->pid == pid)
                           return(sig ? send_sig(sig,*p,priv) : 0);
           return(-ESRCH);
 }  }
   
 /*  /*
  * XXX need to check permissions needed to send signals to process   * POSIX specifies that kill(-1,sig) is unspecified, but what we have
  * groups, etc. etc.  kill() permissions semantics are tricky!   * is probably wrong.  Should make it like BSD or SYSV.
  */   */
 int sys_kill(int pid,int sig)  int sys_kill(int pid,int sig)
 {  {
         struct task_struct **p = NR_TASKS + task;          struct task_struct **p = NR_TASKS + task;
         int err, retval = 0;          int err, retval = 0;
   
         if (!pid) while (--p > &FIRST_TASK) {          if (!pid)
                 if (*p && (*p)->pgrp == current->pid)                   return(kill_pg(current->pid,sig,0));
                         if (err=send_sig(sig,*p,1))          if (pid == -1) {
                                 retval = err;                  while (--p > &FIRST_TASK)
         } else if (pid>0) while (--p > &FIRST_TASK) {  
                 if (*p && (*p)->pid == pid)   
                         if (err=send_sig(sig,*p,0))  
                                 retval = err;  
         } else if (pid == -1) while (--p > &FIRST_TASK)  
                 if (err = send_sig(sig,*p,0))  
                         retval = err;  
         else while (--p > &FIRST_TASK)  
                 if (*p && (*p)->pgrp == -pid)  
                         if (err = send_sig(sig,*p,0))                          if (err = send_sig(sig,*p,0))
                                 retval = err;                                  retval = err;
         return retval;                  return(retval);
           }
           if (pid < 0) 
                   return(kill_pg(-pid,sig,0));
           /* Normal kill */
           return(kill_proc(pid,sig,0));
 }  }
   
 static void tell_father(int pid)  /*
    * 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)
 {  {
         int i;          struct task_struct **p;
   
         if (pid)          for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
                 for (i=0;i<NR_TASKS;i++) {                  if (!(*p) ||
                         if (!task[i])                      ((*p)->pgrp != pgrp) || 
                                 continue;                      ((*p)->state == TASK_ZOMBIE) ||
                         if (task[i]->pid != pid)                      ((*p)->p_pptr->pid == 1))
                                 continue;                          continue;
                         task[i]->signal |= (1<<(SIGCHLD-1));                  if (((*p)->p_pptr->pgrp != pgrp) &&
                         return;                      ((*p)->p_pptr->session == (*p)->session))
                 }                          return 0;
 /* if we don't find any fathers, we just release ourselves */          }
 /* This is not really OK. Must change it to make father 1 */          return(1);      /* (sighing) "Often!" */
         printk("BAD BAD - no father found\n\r");  }
         release(current);  
   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 = 1;  
                         if (task[i]->state == TASK_ZOMBIE)  
                                 /* assumption task[1] is always init */  
                                 (void) send_sig(SIGCHLD, task[1], 1);  
                 }  
         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;
         iput(current->executable);          iput(current->executable);
         current->executable=NULL;          current->executable = NULL;
         if (current->leader && current->tty >= 0)          iput(current->library);
                 tty_table[current->tty].pgrp = 0;          current->library = NULL;
         if (last_task_used_math == current)  
                 last_task_used_math = NULL;  
         if (current->leader)  
                 kill_session();  
         current->state = TASK_ZOMBIE;          current->state = TASK_ZOMBIE;
         current->exit_code = code;          current->exit_code = code;
         tell_father(current->father);          /* 
            * 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)
                   last_task_used_math = NULL;
   #ifdef DEBUG_PROC_TREE
           audit_ptree();
   #endif
         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,unsigned long * stat_addr, int options)  int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
 {  {
         int flag, code;          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:
         flag=0;          flag=0;
         for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {          for (p = current->p_cptr ; p ; p = p->p_osptr) {
                 if (!*p || *p == current)  
                         continue;  
                 if ((*p)->father != current->pid)  
                         continue;  
                 if (pid>0) {                  if (pid>0) {
                         if ((*p)->pid != pid)                          if (p->pid != pid)
                                 continue;                                  continue;
                 } else if (!pid) {                  } else if (!pid) {
                         if ((*p)->pgrp != current->pgrp)                          if (p->pgrp != current->pgrp)
                                 continue;                                  continue;
                 } else if (pid != -1) {                  } else if (pid != -1) {
                         if ((*p)->pgrp != -pid)                          if (p->pgrp != -pid)
                                 continue;                                  continue;
                 }                  }
                 switch ((*p)->state) {                  switch (p->state) {
                         case TASK_STOPPED:                          case TASK_STOPPED:
                                 if (!(options & WUNTRACED))                                  if (!(options & WUNTRACED) || 
                                       !p->exit_code)
                                         continue;                                          continue;
                                 put_fs_long(0x7f,stat_addr);                                  if (stat_addr)
                                 return (*p)->pid;                                          put_fs_long((p->exit_code << 8) | 0x7f,
                                                   stat_addr);
                                   p->exit_code = 0;
                                   return p->pid;
                         case TASK_ZOMBIE:                          case TASK_ZOMBIE:
                                 current->cutime += (*p)->utime;                                  current->cutime += p->utime;
                                 current->cstime += (*p)->stime;                                  current->cstime += p->stime;
                                 flag = (*p)->pid;                                  flag = p->pid;
                                 code = (*p)->exit_code;                                  if (stat_addr)
                                 release(*p);                                          put_fs_long(p->exit_code, stat_addr);
                                 put_fs_long(code,stat_addr);                                  release(p);
   #ifdef DEBUG_PROC_TREE
                                   audit_ptree();
   #endif
                                 return flag;                                  return flag;
                         default:                          default:
                                 flag=1;                                  flag=1;
Line 185  repeat: Line 432  repeat:
                 if (options & WNOHANG)                  if (options & WNOHANG)
                         return 0;                          return 0;
                 current->state=TASK_INTERRUPTIBLE;                  current->state=TASK_INTERRUPTIBLE;
                   oldblocked = current->blocked;
                   current->blocked &= ~(1<<(SIGCHLD-1));
                 schedule();                  schedule();
                 if (!(current->signal &= ~(1<<(SIGCHLD-1))))                  current->blocked = oldblocked;
                         goto repeat;                  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.3  
changed lines
  Added in v.1.1.1.6


unix.superglobalmegacorp.com