netlib.narod.ru< Назад | Оглавление | Далее >

kernel/exit.c

22927 /*
22928  *  linux/kernel/exit.c
22929  *
22930  *  Copyright (C) 1991, 1992  Linus Torvalds
22931  */
22932 
22933 #include <linux/config.h>
22934 #include <linux/malloc.h>
22935 #include <linux/interrupt.h>
22936 #include <linux/smp_lock.h>
22937 #include <linux/module.h>
22938 #ifdef CONFIG_BSD_PROCESS_ACCT
22939 #include <linux/acct.h>
22940 #endif
22941 
22942 #include <asm/uaccess.h>
22943 #include <asm/pgtable.h>
22944 #include <asm/mmu_context.h>
22945 
22946 extern void sem_exit (void);
22947 extern struct task_struct *child_reaper;
22948 
22949 int getrusage(struct task_struct *, int, struct rusage*);
22950 
 Комментарий
22951 static void release(struct task_struct * p)
22952 {
22953   if (p != current) {
22954 #ifdef __SMP__
22955     /* Wait to make sure the process isn't active on any
22956      * other CPU */
22957     for (;;)  {
22958       int has_cpu;
22959       spin_lock(&scheduler_lock);
22960       has_cpu = p->has_cpu;
22961       spin_unlock(&scheduler_lock);
22962       if (!has_cpu)
22963         break;
22964       do {
22965         barrier();
22966       } while (p->has_cpu);
22967     }
22968 #endif
22969     free_uid(p);
22970     nr_tasks--;
22971     add_free_taskslot(p->tarray_ptr);
22972 
22973     write_lock_irq(&tasklist_lock);
22974     unhash_pid(p);
22975     REMOVE_LINKS(p);
22976     write_unlock_irq(&tasklist_lock);
22977 
22978     release_thread(p);
22979     current->cmin_flt += p->min_flt + p->cmin_flt;
22980     current->cmaj_flt += p->maj_flt + p->cmaj_flt;
22981     current->cnswap += p->nswap + p->cnswap;
22982     free_task_struct(p);
22983   } else {
22984     printk("task releasing itself\n");
22985   }
22986 }
22987 
22988 /* This checks not only the pgrp, but falls back on the
22989  * pid if no satisfactory pgrp is found. I dunno - gdb
22990  * doesn't work correctly without this...  */
22991 int session_of_pgrp(int pgrp)
22992 {
22993   struct task_struct *p;
22994   int fallback;
22995 
22996   fallback = -1;
22997   read_lock(&tasklist_lock);
22998   for_each_task(p) {
22999     if (p->session <= 0)
23000       continue;
23001     if (p->pgrp == pgrp) {
23002       fallback = p->session;
23003       break;
23004     }
23005     if (p->pid == pgrp)
23006       fallback = p->session;
23007   }
23008   read_unlock(&tasklist_lock);
23009   return fallback;
23010 }
23011 
23012 /* Determine if a process group is "orphaned", according
23013  * to the POSIX definition in 2.2.2.52.  Orphaned process
23014  * groups are not to be affected by terminal-generated
23015  * stop signals.  Newly orphaned process groups are to
23016  * receive a SIGHUP and a SIGCONT.
23017  *
23018  * "I ask you, have you ever known what it is to be an
23019  * orphan?"  */
23020 static int will_become_orphaned_pgrp(int pgrp,
23021   struct task_struct * ignored_task)
23022 {
23023   struct task_struct *p;
23024 
23025   read_lock(&tasklist_lock);
23026   for_each_task(p) {
23027     if ((p == ignored_task) || (p->pgrp != pgrp) ||
23028         (p->state == TASK_ZOMBIE) ||
23029         (p->p_pptr->pid == 1))
23030       continue;
23031     if ((p->p_pptr->pgrp != pgrp) &&
23032         (p->p_pptr->session == p->session)) {
23033       read_unlock(&tasklist_lock);
23034       return 0;
23035     }
23036   }
23037   read_unlock(&tasklist_lock);
23038   return 1;       /* (sighing) "Often!" */
23039 }
23040 
23041 int is_orphaned_pgrp(int pgrp)
23042 {
23043   return will_become_orphaned_pgrp(pgrp, 0);
23044 }
23045 
23046 static inline int has_stopped_jobs(int pgrp)
23047 {
23048   int retval = 0;
23049   struct task_struct * p;
23050 
23051   read_lock(&tasklist_lock);
23052   for_each_task(p) {
23053     if (p->pgrp != pgrp)
23054       continue;
23055     if (p->state != TASK_STOPPED)
23056       continue;
23057     retval = 1;
23058     break;
23059   }
23060   read_unlock(&tasklist_lock);
23061   return retval;
23062 }
23063 
23064 static inline void forget_original_parent(
23065   struct task_struct * father)
23066 {
23067   struct task_struct * p;
23068 
23069   read_lock(&tasklist_lock);
23070   for_each_task(p) {
23071     if (p->p_opptr == father) {
23072       p->exit_signal = SIGCHLD;
23073       p->p_opptr = child_reaper; /* init */
23074       if (p->pdeath_signal)
23075         send_sig(p->pdeath_signal, p, 0);
23076     }
23077   }
23078   read_unlock(&tasklist_lock);
23079 }
23080 
23081 static inline void close_files(
23082   struct files_struct * files)
23083 {
23084   int i, j;
23085 
23086   j = 0;
23087   for (;;) {
23088     unsigned long set = files->open_fds.fds_bits[j];
23089     i = j * __NFDBITS;
23090     j++;
23091     if (i >= files->max_fds)
23092       break;
23093     while (set) {
23094       if (set & 1) {
23095         struct file * file = files->fd[i];
23096         if (file) {
23097           files->fd[i] = NULL;
23098           filp_close(file, files);
23099         }
23100       }
23101       i++;
23102       set >>= 1;
23103     }
23104   }
23105 }
23106 
23107 extern kmem_cache_t *files_cachep;
23108 
23109 static inline void __exit_files(struct task_struct *tsk)
23110 {
23111   struct files_struct * files = tsk->files;
23112 
23113   if (files) {
23114     tsk->files = NULL;
 Комментарий
23115     if (atomic_dec_and_test(&files->count)) {
23116       close_files(files);
23117       /* Free the fd array as appropriate ... */
23118       if (NR_OPEN * sizeof(struct file *) == PAGE_SIZE)
23119         free_page((unsigned long) files->fd);
23120       else
23121         kfree(files->fd);
23122       kmem_cache_free(files_cachep, files);
23123     }
23124   }
23125 }
23126 
23127 void exit_files(struct task_struct *tsk)
23128 {
23129   __exit_files(tsk);
23130 }
23131 
23132 static inline void __exit_fs(struct task_struct *tsk)
23133 {
23134   struct fs_struct * fs = tsk->fs;
23135 
23136   if (fs) {
23137     tsk->fs = NULL;
23138     if (atomic_dec_and_test(&fs->count)) {
23139       dput(fs->root);
23140       dput(fs->pwd);
23141       kfree(fs);
23142     }
23143   }
23144 }
23145 
23146 void exit_fs(struct task_struct *tsk)
23147 {
23148   __exit_fs(tsk);
23149 }
23150 
23151 static inline void __exit_sighand(
23152   struct task_struct *tsk)
23153 {
23154   struct signal_struct * sig = tsk->sig;
23155 
23156   if (sig) {
23157     unsigned long flags;
23158 
23159     spin_lock_irqsave(&tsk->sigmask_lock, flags);
23160     tsk->sig = NULL;
23161     spin_unlock_irqrestore(&tsk->sigmask_lock, flags);
23162     if (atomic_dec_and_test(&sig->count))
23163       kfree(sig);
23164   }
23165 
23166   flush_signals(tsk);
23167 }
23168 
23169 void exit_sighand(struct task_struct *tsk)
23170 {
23171   __exit_sighand(tsk);
23172 }
23173 
23174 static inline void __exit_mm(struct task_struct * tsk)
23175 {
23176   struct mm_struct * mm = tsk->mm;
23177 
23178   /* Set us up to use the kernel mm state */
23179   if (mm != &init_mm) {
23180     flush_cache_mm(mm);
23181     flush_tlb_mm(mm);
23182     destroy_context(mm);
23183     tsk->mm = &init_mm;
23184     tsk->swappable = 0;
23185     SET_PAGE_DIR(tsk, swapper_pg_dir);
23186     mm_release();
23187     mmput(mm);
23188   }
23189 }
23190 
23191 void exit_mm(struct task_struct *tsk)
23192 {
23193   __exit_mm(tsk);
23194 }
23195 
23196 /* Send signals to all our closest relatives so that they
23197  * know to properly mourn us..  */
23198 static void exit_notify(void)
23199 {
23200   struct task_struct * p;
23201 
23202   forget_original_parent(current);
23203   /* Check to see if any process groups have become
23204    * orphaned as a result of our exiting, and if they
23205    * have any stopped jobs, send them a SIGHUP and then a
23206    * SIGCONT.  (POSIX 3.2.2.2)
23207    *
23208    * Case i: Our father is in a different pgrp than we
23209    * are and we were the only connection outside, so our
23210    * pgrp is about to become orphaned.  */
23211   if ((current->p_pptr->pgrp != current->pgrp) &&
23212       (current->p_pptr->session == current->session) &&
23213       will_become_orphaned_pgrp(current->pgrp, current)&&
23214       has_stopped_jobs(current->pgrp)) {
23215     kill_pg(current->pgrp,SIGHUP,1);
23216     kill_pg(current->pgrp,SIGCONT,1);
23217   }
23218 
23219   /* Let father know we died */
23220   notify_parent(current, current->exit_signal);
23221 
23222   /* This loop does two things:
23223    *
23224    * A.  Make init inherit all the child processes
23225    * B.  Check to see if any process groups have become
23226    * orphaned as a result of our exiting, and if they
23227    * have any stopped jobs, send them a SIGHUP and then a
23228    * SIGCONT.  (POSIX 3.2.2.2) */
23229 
23230   write_lock_irq(&tasklist_lock);
23231   while (current->p_cptr != NULL) {
23232     p = current->p_cptr;
23233     current->p_cptr = p->p_osptr;
23234     p->p_ysptr = NULL;
23235     p->flags &= ~(PF_PTRACED|PF_TRACESYS);
23236 
23237     p->p_pptr = p->p_opptr;
23238     p->p_osptr = p->p_pptr->p_cptr;
23239     if (p->p_osptr)
23240       p->p_osptr->p_ysptr = p;
23241     p->p_pptr->p_cptr = p;
23242     if (p->state == TASK_ZOMBIE)
23243       notify_parent(p, p->exit_signal);
23244     /* process group orphan check
23245      * Case ii: Our child is in a different pgrp than we
23246      * are, and it was the only connection outside, so
23247      * the child pgrp is now orphaned.  */
23248     if ((p->pgrp != current->pgrp) &&
23249         (p->session == current->session)) {
23250       int pgrp = p->pgrp;
23251 
23252       write_unlock_irq(&tasklist_lock);
23253       if (is_orphaned_pgrp(pgrp) &&
23254           has_stopped_jobs(pgrp)) {
23255         kill_pg(pgrp,SIGHUP,1);
23256         kill_pg(pgrp,SIGCONT,1);
23257       }
23258       write_lock_irq(&tasklist_lock);
23259     }
23260   }
23261   write_unlock_irq(&tasklist_lock);
23262 
23263   if (current->leader)
23264     disassociate_ctty(1);
23265 }
23266 
 Комментарий
23267 NORET_TYPE void do_exit(long code)
23268 {
23269   struct task_struct *tsk = current;
23270 
23271   if (in_interrupt())
23272     printk("Aiee, killing interrupt handler\n");
23273   if (!tsk->pid)
23274     panic("Attempted to kill the idle task!");
23275   tsk->flags |= PF_EXITING;
23276   start_bh_atomic();
23277   del_timer(&tsk->real_timer);
23278   end_bh_atomic();
23279 
23280   lock_kernel();
23281 fake_volatile:
23282 #ifdef CONFIG_BSD_PROCESS_ACCT
23283   acct_process(code);
23284 #endif
23285   sem_exit();
23286   __exit_mm(tsk);
23287 #if CONFIG_AP1000
23288   exit_msc(tsk);
23289 #endif
23290   __exit_files(tsk);
23291   __exit_fs(tsk);
23292   __exit_sighand(tsk);
23293   exit_thread();
23294   tsk->state = TASK_ZOMBIE;
23295   tsk->exit_code = code;
23296   exit_notify();
23297 #ifdef DEBUG_PROC_TREE
23298   audit_ptree();
23299 #endif
23300   if (tsk->exec_domain && tsk->exec_domain->module)
23301     __MOD_DEC_USE_COUNT(tsk->exec_domain->module);
23302   if (tsk->binfmt && tsk->binfmt->module)
23303     __MOD_DEC_USE_COUNT(tsk->binfmt->module);
23304   schedule();
23305 /* In order to get rid of the "volatile function does
23306  * return" message I did this little loop that confuses
23307  * gcc to think do_exit really is volatile. In fact it's
23308  * schedule() that is volatile in some circumstances:
23309  * when current->state = ZOMBIE, schedule() never
23310  * returns.
23311  *
23312  * In fact the natural way to do all this is to have the
23313  * label and the goto right after each other, but I put
23314  * the fake_volatile label at the start of the function
23315  * just in case something /really/ bad happens, and the
23316  * schedule returns. This way we can try again. I'm not
23317  * paranoid: it's just that everybody is out to get me.
23318  */
23319   goto fake_volatile;
23320 }
23321 
23322 asmlinkage int sys_exit(int error_code)
23323 {
23324   do_exit((error_code&0xff)<<8);
23325 }
23326 
 Комментарий
23327 asmlinkage int sys_wait4(pid_t pid,
23328   unsigned int * stat_addr, int options,
23329   struct rusage * ru)
23330 {
23331   int flag, retval;
23332   struct wait_queue wait = { current, NULL };
23333   struct task_struct *p;
23334 
23335   if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
23336     return -EINVAL;
23337 
23338   add_wait_queue(&current->wait_chldexit,&wait);
23339 repeat:
23340   flag = 0;
23341   read_lock(&tasklist_lock);
23342   for (p = current->p_cptr ; p ; p = p->p_osptr) {
23343     if (pid>0) {
23344       if (p->pid != pid)
23345         continue;
23346     } else if (!pid) {
23347       if (p->pgrp != current->pgrp)
23348         continue;
23349     } else if (pid != -1) {
23350       if (p->pgrp != -pid)
23351         continue;
23352     }
23353     /* wait for cloned processes iff the __WCLONE flag is
23354      * set */
23355     if ((p->exit_signal != SIGCHLD) ^
23356         ((options & __WCLONE) != 0))
23357       continue;
23358     flag = 1;
23359     switch (p->state) {
23360       case TASK_STOPPED:
23361         if (!p->exit_code)
23362           continue;
23363         if (!(options & WUNTRACED) &&
23364             !(p->flags & PF_PTRACED))
23365           continue;
23366         read_unlock(&tasklist_lock);
23367         retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
23368         if (!retval && stat_addr)
23369           retval = put_user((p->exit_code << 8) | 0x7f,
23370                             stat_addr);
23371         if (!retval) {
23372           p->exit_code = 0;
23373           retval = p->pid;
23374         }
23375         goto end_wait4;
23376       case TASK_ZOMBIE:
23377         current->times.tms_cutime += p->times.tms_utime +
23378                                      p->times.tms_cutime;
23379         current->times.tms_cstime += p->times.tms_stime +
23380                                      p->times.tms_cstime;
23381         read_unlock(&tasklist_lock);
23382         retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
23383         if (!retval && stat_addr)
23384           retval = put_user(p->exit_code, stat_addr);
23385         if (retval)
23386           goto end_wait4;
23387         retval = p->pid;
23388         if (p->p_opptr != p->p_pptr) {
23389           write_lock_irq(&tasklist_lock);
23390           REMOVE_LINKS(p);
23391           p->p_pptr = p->p_opptr;
23392           SET_LINKS(p);
23393           write_unlock_irq(&tasklist_lock);
23394           notify_parent(p, SIGCHLD);
23395         } else
23396           release(p);
23397 #ifdef DEBUG_PROC_TREE
23398         audit_ptree();
23399 #endif
 Комментарий
23400         goto end_wait4;
23401       default:
23402         continue;
23403     }
23404   }
23405   read_unlock(&tasklist_lock);
23406   if (flag) {
23407     retval = 0;
23408     if (options & WNOHANG)
23409       goto end_wait4;
23410     retval = -ERESTARTSYS;
23411     if (signal_pending(current))
23412       goto end_wait4;
23413     current->state=TASK_INTERRUPTIBLE;
23414     schedule();
23415     goto repeat;
23416   }
23417   retval = -ECHILD;
23418 end_wait4:
23419   remove_wait_queue(&current->wait_chldexit,&wait);
23420   return retval;
23421 }
23422 
23423 #ifndef __alpha__
23424 
23425 /* sys_waitpid() remains for compatibility. waitpid()
23426  * should be implemented by calling sys_wait4() from
23427  * libc.a.  */
23428 asmlinkage int sys_waitpid(pid_t pid,
23429   unsigned int * stat_addr, int options)
23430 {
23431   return sys_wait4(pid, stat_addr, options, NULL);
23432 }
23433 
23434 #endif

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz