Ядро Linux в комментариях

       

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


Содержание раздела