Linux进程管理之进程的终止

   内核源码:linux-2.6.38.8.tar.bz2

    目标平台:ARM体系结构

 

    进程终止时,一般是调用exit库函数(无论是程序员显式调用还是编译器自动地把exit库函数插入到main函数的最后一条语句之后)来释放进程所拥有的资源。 

[cpp]  view plain copy
  1. $ man 3 exit  
  2.        void exit(int status);  
  3. $ man 2 exit_group  
  4.        void exit_group(int status);  
  5.   
  6. $ man 3 pthread_exit  
  7.        void pthread_exit(void *retval);  
  8. $ man 2 _exit  
  9.        void _exit(int status);  

    库函数exit使用系统调用exit_group来终止整个线程组,库函数pthread_exit使用系统调用_exit来终止某一个线程。

    这两个系统调用在Linux内核中的入口点函数分别为sys_exit和sys_exit_group。 

[cpp]  view plain copy
  1. /* linux-2.6.38.8/kernel/exit.c */  
  2. SYSCALL_DEFINE1(exit, int, error_code)  
  3. {  
  4.     do_exit((error_code&0xff)<<8);  
  5. }  
  6.   
  7. SYSCALL_DEFINE1(exit_group, int, error_code)  
  8. {  
  9.     do_group_exit((error_code & 0xff) << 8);  
  10.     /* NOTREACHED */  
  11.     return 0;  
  12. }  

    do_group_exit函数会杀死属于当前进程所在线程组的所有进程。它接受进程终止代号作为参数,进程终止代号可能是系统调用exit_group(正常结束)指定的一个值,也可能是内核提供的一个错误码(异常结束)。 

[cpp]  view plain copy
  1. NORET_TYPE void  
  2. do_group_exit(int exit_code)  
  3. {  
  4.     struct signal_struct *sig = current->signal;  
  5.   
  6.     BUG_ON(exit_code & 0x80); /* core dumps don't get here */  
  7.   
  8.     if (signal_group_exit(sig)) //检查current->sig->flags的SIGNAL_GROUP_EXIT标志是否置位,或者current->sig->group_exit_task是否不为NULL。  
  9.         exit_code = sig->group_exit_code; //group_exit_code存放的是线程组终止代码  
  10.     else if (!thread_group_empty(current)) { //检查线程组链表是否不为空。  
  11.         struct sighand_struct *const sighand = current->sighand;  
  12.         spin_lock_irq(&sighand->siglock);  
  13.         if (signal_group_exit(sig))  
  14.             /* Another thread got here before we took the lock.  */  
  15.             exit_code = sig->group_exit_code;  
  16.         else {  
  17.             sig->group_exit_code = exit_code;  
  18.             sig->flags = SIGNAL_GROUP_EXIT;  
  19.             zap_other_threads(current); //遍历整个线程组链表,并杀死其中的每个线程。  
  20.         }  
  21.         spin_unlock_irq(&sighand->siglock);  
  22.     }  
  23.   
  24.     do_exit(exit_code);  
  25.     /* NOTREACHED */  
  26. }  

    进程终止所要完成的任务都是由do_exit函数来处理。 

[cpp]  view plain copy
  1. /* linux-2.6.38.8/kernel/exit.c */  
  2. NORET_TYPE void do_exit(long code)  

    1、触发task_exit_nb通知链实例的处理函数 

[cpp]  view plain copy
  1.     profile_task_exit(tsk);  
  2.   
  3. /* linux-2.6.38.8/drivers/oprofile/buffer_sync.c */  
  4. static struct notifier_block task_exit_nb = {  
  5.     .notifier_call  = task_exit_notify,  
  6. };  

    2、检查current->fs_excl是否为0,不为0时也不会终止后续代码的执行 

[cpp]  view plain copy
  1.     WARN_ON(atomic_read(&tsk->fs_excl));  
  2.   
  3. /* linux-2.6.38.8/include/asm-generic/bug.h */  
  4. #ifndef WARN_ON  
  5. #define WARN_ON(condition) ({                       \  
  6.     int __ret_warn_on = !!(condition);              \  
  7.     if (unlikely(__ret_warn_on))                    \  
  8.         __WARN(); /* 输出警告信息的位置(哪个文件的哪行)*/   \  
  9.     unlikely(__ret_warn_on);                    \  
  10. })  
  11. #endif  

    3、oops消息 

[cpp]  view plain copy
  1. if (unlikely(in_interrupt()))  
  2.     panic("Aiee, killing interrupt handler!");  
  3. if (unlikely(!tsk->pid))  
  4.     panic("Attempted to kill the idle task!");  

     中断上下文不能执行do_exit函数,也不能终止PID为0的进程。

    4、设定进程可以使用的虚拟地址的上限(用户空间) 

[cpp]  view plain copy
  1.     set_fs(USER_DS);  
  2.   
  3. /* linux-2.6.38.8/arch/arm/include/asm/uaccess.h */  
  4. #define USER_DS     TASK_SIZE  
  5. #define TASK_SIZE       (UL(CONFIG_PAGE_OFFSET) - UL(0x01000000))  
  6.   
  7. static inline void set_fs(mm_segment_t fs)  
  8. {  
  9.     current_thread_info()->addr_limit = fs;  
  10.     modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);  
  11. }  

    5、current->flags的PF_EXITING标志表示进程正在被删除。 

[cpp]  view plain copy
  1. if (unlikely(tsk->flags & PF_EXITING)) {//检查PF_EXITING标志是否未被设置,如果设置了则执行大括号里的代码  
  2.     printk(KERN_ALERT  
  3.         "Fixing recursive fault but reboot is needed!\n");  
  4.   
  5.     tsk->flags |= PF_EXITPIDONE;  
  6.     set_current_state(TASK_UNINTERRUPTIBLE); //设置进程状态为不可中断的等待状态  
  7.     schedule(); //调度其它进程  
  8. }  

    6、设置current->irqaction->flags的IRQTF_DIED标志,表示清除当前进程的中断服务例程 

[cpp]  view plain copy
  1.     exit_irq_thread();  
  2.   
  3. /* linux-2.6.38.8/kernel/irq/mamage.c */  
  4. void exit_irq_thread(void)  
  5. {  
  6.     struct task_struct *tsk = current;  
  7.   
  8.     if (!tsk->irqaction)  
  9.         return;  
  10.   
  11.     printk(KERN_ERR  
  12.            "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",  
  13.            tsk->comm ? tsk->comm : "", tsk->pid, tsk->irqaction->irq);  
  14.   
  15.     /* 
  16.      * Set the THREAD DIED flag to prevent further wakeups of the 
  17.      * soon to be gone threaded handler. 
  18.      */  
  19.     set_bit(IRQTF_DIED, &tsk->irqaction->flags);  
  20. }  

    7、设置PF_EXITING标志 

[cpp]  view plain copy
  1.     exit_signals(tsk);  /* sets PF_EXITING */  
  2.   
  3. /* linux-2.6.38.8/kernel/signal.c */  
  4. void exit_signals(struct task_struct *tsk)  
  5. {  
  6.     int group_stop = 0;  
  7.     struct task_struct *t;  
  8.   
  9.     if (thread_group_empty(tsk) || signal_group_exit(tsk->signal)) { //检查线程组链表是否为空,或者是否要终止整个线程组  
  10.         tsk->flags |= PF_EXITING;  
  11.         return;  
  12.     }  
  13.   
  14.     spin_lock_irq(&tsk->sighand->siglock);  
  15.     /* 
  16.      * From now this task is not visible for group-wide signals, 
  17.      * see wants_signal(), do_signal_stop(). 
  18.      */  
  19.     tsk->flags |= PF_EXITING;  
  20.     if (!signal_pending(tsk)) //signal_pending函数用于检查当前进程是否有非阻塞的挂起信号,如果有则返回1,否则返回0  
  21.         goto out;  
  22.   
  23.     /* It could be that __group_complete_signal() choose us to 
  24.      * notify about group-wide signal. Another thread should be 
  25.      * woken now to take the signal since we will not. 
  26.      */  
  27.     for (t = tsk; (t = next_thread(t)) != tsk; ) //检查线程组中的其他进程  
  28.         if (!signal_pending(t) && !(t->flags & PF_EXITING)) //如果没有设置TIF_SIGPENDING标志,而且也没有设置PF_EXITING标志  
  29.             recalc_sigpending_and_wake(t); //则设置TIF_SIGPENDING标志,表示有挂起信号  
  30.   
  31.     if (unlikely(tsk->signal->group_stop_count) &&  
  32.             !--tsk->signal->group_stop_count) { //表示只终止线程组中的某个线程  
  33.         tsk->signal->flags = SIGNAL_STOP_STOPPED;  
  34.         group_stop = tracehook_notify_jctl(CLD_STOPPED, CLD_STOPPED);  
  35.     }  
  36. out:  
  37.     spin_unlock_irq(&tsk->sighand->siglock);  
  38.   
  39.     if (unlikely(group_stop)) {  
  40.         read_lock(&tasklist_lock);  
  41.         do_notify_parent_cldstop(tsk, group_stop);  
  42.         read_unlock(&tasklist_lock);  
  43.     }  
  44. }  

    8)、内存屏障,用于确保在它之后的操作开始执行之前,它之前的操作已经完成 

[cpp]  view plain copy
  1.     smp_mb();  
  2.     raw_spin_unlock_wait(&tsk->pi_lock); //一直等待,直到获得current->pi_lock自旋锁  
  3. /* linux-2.6.38.8/arch/arm/include/asm/system.h */  
  4. #define smp_mb()    barrier()  //!CONFIG_SMP  
  5. /* linux-2.6.38.8/include/linux/compiler-gcc.h */  
  6. #define barrier() __asm__ __volatile__("": : :"memory")  

    9)、获取current->mm->rss_stat.count[member]计数 

[cpp]  view plain copy
  1.     acct_update_integrals(tsk);  
  2.   
  3. void acct_update_integrals(struct task_struct *tsk)  
  4. {  
  5.     if (likely(tsk->mm)) {  
  6.         cputime_t time, dtime;  
  7.         struct timeval value;  
  8.         unsigned long flags;  
  9.         u64 delta;  
  10.   
  11.         local_irq_save(flags);  
  12.         time = tsk->stime + tsk->utime;  
  13.         dtime = cputime_sub(time, tsk->acct_timexpd);  
  14.         jiffies_to_timeval(cputime_to_jiffies(dtime), &value);  
  15.         delta = value.tv_sec;  
  16.         delta = delta * USEC_PER_SEC + value.tv_usec;  
  17.   
  18.         if (delta == 0)  
  19.             goto out;  
  20.         tsk->acct_timexpd = time;  
  21.         tsk->acct_rss_mem1 += delta * get_mm_rss(tsk->mm); //统计分配给进程的页框数(MM_FILEPAGES和MM_ANONPAGES两种类型的页框)  
  22.         tsk->acct_vm_mem1 += delta * tsk->mm->total_vm; //total_vm用来表示进程地址空间的大小(页数)  
  23.     out:  
  24.         local_irq_restore(flags);  
  25.     }  
  26. }  
  27.   
  28. /* linux-2.6.38.8/include/linux/mm.h */  
  29. static inline unsigned long get_mm_rss(struct mm_struct *mm)  
  30. {  
  31.     return get_mm_counter(mm, MM_FILEPAGES) +  
  32.         get_mm_counter(mm, MM_ANONPAGES);  
  33. }  
  34. static inline unsigned long get_mm_counter(struct mm_struct *mm, int member) //!USE_SPLIT_PTLOCKS  
  35. {  
  36.     return mm->rss_stat.count[member];  
  37. }  

    然后,把它们清零。 

[cpp]  view plain copy
  1.     /* sync mm's RSS info before statistics gathering */  
  2.     if (tsk->mm)  
  3.         sync_mm_rss(tsk, tsk->mm);  
  4.   
  5. /* linux-2.6.38.8/mm/memory.c */  
  6. void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)  
  7. {  
  8.     __sync_task_rss_stat(task, mm);  
  9. }  
  10. static void __sync_task_rss_stat(struct task_struct *task, struct mm_struct *mm)  
  11. {  
  12.     int i;  
  13.   
  14.     for (i = 0; i < NR_MM_COUNTERS; i++) {  //共有三类,MM_FILEPAGES、MM_ANONPAGES和MM_SWAPENTS  
  15.         if (task->rss_stat.count[i]) {  
  16.             add_mm_counter(mm, i, task->rss_stat.count[i]);  
  17.             task->rss_stat.count[i] = 0;  
  18.         }  
  19.     }  
  20.     task->rss_stat.events = 0;  
  21. }  

    10)、清除定时器 

[cpp]  view plain copy
  1. group_dead = atomic_dec_and_test(&tsk->signal->live); //live用来表示线程组中活动进程的数量  
  2. if (group_dead) { //当没有活动的进程时  
  3.     hrtimer_cancel(&tsk->signal->real_timer); //取消高精度定时器  
  4.     exit_itimers(tsk->signal); //删除POSIX.1b类型的定时器  
  5.     if (tsk->mm)  
  6.         setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm); //获取进程所拥有的最大页框数  
  7. }  

    11)、收集进程会计信息 

[cpp]  view plain copy
  1. acct_collect(code, group_dead);  

    12)、审计 

[cpp]  view plain copy
  1. if (group_dead)  
  2.     tty_audit_exit(); //记录审计事件  
  3. if (unlikely(tsk->audit_context))  
  4.     audit_free(tsk); //释放struct audit_context结构体  

    13)、输出taskstats信息 

[cpp]  view plain copy
  1. tsk->exit_code = code; //设置终止代码  
  2. taskstats_exit(tsk, group_dead);  

    14)、释放线性区描述符和页表 

[cpp]  view plain copy
  1.     exit_mm(tsk);  
  2.   
  3. /* linux-2.6.38.8/kernel/exit.c */  
  4. static void exit_mm(struct task_struct * tsk)  
  5. {  
  6.     struct mm_struct *mm = tsk->mm;  
  7.     struct core_state *core_state;  
  8.   
  9.     mm_release(tsk, mm);   //其中会唤醒tsk->vfork_done,让父进程开始执行,用于vfork时  
  10.     if (!mm)  
  11.         return;  
  12.     /* 
  13.      * Serialize with any possible pending coredump. 
  14.      * We must hold mmap_sem around checking core_state 
  15.      * and clearing tsk->mm.  The core-inducing thread 
  16.      * will increment ->nr_threads for each thread in the 
  17.      * group with ->mm != NULL. 
  18.      */  
  19.     down_read(&mm->mmap_sem);  
  20.     core_state = mm->core_state;  
  21.     if (core_state) {  //内存转储  
  22.         struct core_thread self;  
  23.         up_read(&mm->mmap_sem);  
  24.   
  25.         self.task = tsk;  
  26.         self.next = xchg(&core_state->dumper.next, &self);  
  27.         /* 
  28.          * Implies mb(), the result of xchg() must be visible 
  29.          * to core_state->dumper. 
  30.          */  
  31.         if (atomic_dec_and_test(&core_state->nr_threads))  
  32.             complete(&core_state->startup);  
  33.   
  34.         for (;;) {  
  35.             set_task_state(tsk, TASK_UNINTERRUPTIBLE);  
  36.             if (!self.task) /* see coredump_finish() */  
  37.                 break;  
  38.             schedule();  
  39.         }  
  40.         __set_task_state(tsk, TASK_RUNNING);  
  41.         down_read(&mm->mmap_sem);  
  42.     }  
  43.     atomic_inc(&mm->mm_count); //递增mm->mm_count计数,确保内存描述符暂时不会被删除,当要把正在被终止的进程从本地CPU撤销时,才由finish_task_switch函数来释放内存描述。  
  44.     BUG_ON(mm != tsk->active_mm);  
  45.     /* more a memory barrier than a real lock */  
  46.     task_lock(tsk);  
  47.     tsk->mm = NULL; //设置进程描述符的mm字段为NULL。   
  48.     up_read(&mm->mmap_sem);  
  49.     enter_lazy_tlb(mm, current); //使处理器处于懒惰TLB模式,ARM体系结构不支持。  
  50.     /* We don't want this task to be frozen prematurely */  
  51.     clear_freeze_flag(tsk);  //设置TIF_FREEZE标志。  
  52.     if (tsk->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)  
  53.         atomic_dec(&mm->oom_disable_count);  
  54.     task_unlock(tsk);  
  55.     mm_update_next_owner(mm);  
  56.     mmput(mm);  //当mm->mm_users为0(即没有任何进程使用它)时,释放线性区描述符和页表,但这时还不会释放内存描述符  
  57. }  

    15)、输出进程会计信息 

[cpp]  view plain copy
  1. if (group_dead)  
  2.     acct_process();  
  3. trace_sched_process_exit(tsk); //用于跟踪,定义在linux-2.6.38.8/include/trace/events/sched.h文件中  

    16)、遍历current->sysvsem.undo_list链表,并清除进程所涉及的每个IPC信号量的操作痕迹 

[cpp]  view plain copy
  1. exit_sem(tsk);  

    17)、释放文件对象相关资源 

[cpp]  view plain copy
  1.     exit_files(tsk);  
  2.   
  3. /* linux-2.6.38.8/kernel/exit.c */  
  4. void exit_files(struct task_struct *tsk)  
  5. {  
  6.     struct files_struct * files = tsk->files;  
  7.   
  8.     if (files) {  
  9.         task_lock(tsk);  
  10.         tsk->files = NULL; //把进程描述符的files字段设为NULL。  
  11.         task_unlock(tsk);  
  12.         put_files_struct(files);  
  13.     }  
  14. }  
  15.   
  16. void put_files_struct(struct files_struct *files)  
  17. {  
  18.     struct fdtable *fdt;  
  19.   
  20.     if (atomic_dec_and_test(&files->count)) { //当共享该表的进程数目为0时  
  21.         close_files(files); //执行进程终止时应该执行的文件操作相关函数,如release  
  22.         /* 
  23.          * Free the fd and fdset arrays if we expanded them. 
  24.          * If the fdtable was embedded, pass files for freeing 
  25.          * at the end of the RCU grace period. Otherwise, 
  26.          * you can free files immediately. 
  27.          */  
  28.         rcu_read_lock();  
  29.         fdt = files_fdtable(files);  
  30.         if (fdt != &files->fdtab)  
  31.             kmem_cache_free(files_cachep, files); //释放struct files_struct结构体所用内存  
  32.         free_fdtable(fdt);  
  33.         rcu_read_unlock();  
  34.     }  
  35. }  

    18)、释放struct fs_struct结构体 

[cpp]  view plain copy
  1.     exit_fs(tsk);  
  2.   
  3. /* linux-2.6.38.8/fs/fs_struct.c */  
  4. void exit_fs(struct task_struct *tsk)  
  5. {  
  6.     struct fs_struct *fs = tsk->fs;  
  7.   
  8.     if (fs) {  
  9.         int kill;  
  10.         task_lock(tsk);  
  11.         spin_lock(&fs->lock);  
  12.         write_seqcount_begin(&fs->seq);  
  13.         tsk->fs = NULL; //设置进程描述符的fs字段为NULL  
  14.         kill = !--fs->users;  //fs->users表示共享这个表的进程个数  
  15.         write_seqcount_end(&fs->seq);  
  16.         spin_unlock(&fs->lock);  
  17.         task_unlock(tsk);  
  18.         if (kill) //当为0时  
  19.             free_fs_struct(fs); //释放结构体所用内存  
  20.     }  
  21. }  

    19)、检查有多少未使用的进程内核栈 

[cpp]  view plain copy
  1.     check_stack_usage();  
  2. /* linux-2.6.38.8/kernel/exit.c */  
  3. #ifdef CONFIG_DEBUG_STACK_USAGE  
  4. static void check_stack_usage(void)  
  5. {  
  6.     static DEFINE_SPINLOCK(low_water_lock);  
  7.     static int lowest_to_date = THREAD_SIZE;  
  8.     unsigned long free;  
  9.   
  10.     free = stack_not_used(current);  
  11.   
  12.     if (free >= lowest_to_date)  
  13.         return;  
  14.   
  15.     spin_lock(&low_water_lock);  
  16.     if (free < lowest_to_date) {  
  17.         printk(KERN_WARNING "%s used greatest stack depth: %lu bytes "  
  18.                 "left\n",  
  19.                 current->comm, free);  
  20.         lowest_to_date = free;  
  21.     }  
  22.     spin_unlock(&low_water_lock);  
  23. }  
  24. #else  
  25. static inline void check_stack_usage(void) {}  
  26. #endif  

    20)、触发thread_notify_head链表中所有通知链实例的处理函数,用于处理struct thread_info结构体 

[cpp]  view plain copy
  1.     exit_thread();  
  2.   
  3. /* linux-2.6.38.8/arch/arm/kernel/process.c */  
  4. void exit_thread(void)  
  5. {  
  6.     thread_notify(THREAD_NOTIFY_EXIT, current_thread_info());  
  7. }  

    21)、Performance Event功能相关资源的释放 

[cpp]  view plain copy
  1.     perf_event_exit_task(tsk);  
  2.   
  3. /* linux-2.6.38.8/kernel/perf_event.c */  
  4. void perf_event_exit_task(struct task_struct *child)  
  5. {  
  6.     struct perf_event *event, *tmp;  
  7.     int ctxn;  
  8.   
  9.     mutex_lock(&child->perf_event_mutex);  
  10.     list_for_each_entry_safe(event, tmp, &child->perf_event_list,  
  11.                  owner_entry) {  
  12.         list_del_init(&event->owner_entry);  
  13.   
  14.         /* 
  15.          * Ensure the list deletion is visible before we clear 
  16.          * the owner, closes a race against perf_release() where 
  17.          * we need to serialize on the owner->perf_event_mutex. 
  18.          */  
  19.         smp_wmb();  
  20.         event->owner = NULL;  
  21.     }  
  22.     mutex_unlock(&child->perf_event_mutex);  
  23.   
  24.     for_each_task_context_nr(ctxn)  
  25.         perf_event_exit_task_context(child, ctxn);  
  26. }  

    22)、释放Control Groups相关的资源 

[cpp]  view plain copy
  1.     cgroup_exit(tsk, 1);  
  2.   
  3. /* linux-2.6.38.8/kernel/cgroup.c */  
  4. void cgroup_exit(struct task_struct *tsk, int run_callbacks)  
  5. {  
  6.     int i;  
  7.     struct css_set *cg;  
  8.   
  9.     if (run_callbacks && need_forkexit_callback) {  
  10.         /* 
  11.          * modular subsystems can't use callbacks, so no need to lock 
  12.          * the subsys array 
  13.          */  
  14.         for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {  
  15.             struct cgroup_subsys *ss = subsys[i];  
  16.             if (ss->exit)  
  17.                 ss->exit(ss, tsk);  
  18.         }  
  19.     }  
  20.   
  21.     /* 
  22.      * Unlink from the css_set task list if necessary. 
  23.      * Optimistically check cg_list before taking 
  24.      * css_set_lock 
  25.      */  
  26.     if (!list_empty(&tsk->cg_list)) {  
  27.         write_lock(&css_set_lock);  
  28.         if (!list_empty(&tsk->cg_list))  
  29.             list_del_init(&tsk->cg_list);  
  30.         write_unlock(&css_set_lock);  
  31.     }  
  32.   
  33.     /* Reassign the task to the init_css_set. */  
  34.     task_lock(tsk);  
  35.     cg = tsk->cgroups;  
  36.     tsk->cgroups = &init_css_set;  
  37.     task_unlock(tsk);  
  38.     if (cg)  
  39.         put_css_set_taskexit(cg);  
  40. }  

    23)、脱离控制终端 

[cpp]  view plain copy
  1. if (group_dead)  
  2.     disassociate_ctty(1);  

    24)、执行域 

[cpp]  view plain copy
  1. module_put(task_thread_info(tsk)->exec_domain->module);  

    25)、进程事件连接器(通过它来报告进程fork、exec、exit以及进程用户ID与组ID的变化) 

[cpp]  view plain copy
  1.     proc_exit_connector(tsk);  
  2.   
  3. /* linux-2.6.38.8/drivers/connector/cn_proc.c */  
  4. void proc_exit_connector(struct task_struct *task)  
  5. {  
  6.     struct cn_msg *msg;  
  7.     struct proc_event *ev;  
  8.     __u8 buffer[CN_PROC_MSG_SIZE];  
  9.     struct timespec ts;  
  10.   
  11.     if (atomic_read(&proc_event_num_listeners) < 1)  
  12.         return;  
  13.   
  14.     msg = (struct cn_msg*)buffer;  
  15.     ev = (struct proc_event*)msg->data;  
  16.     get_seq(&msg->seq, &ev->cpu);  
  17.     ktime_get_ts(&ts); /* get high res monotonic timestamp */  
  18.     put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);  
  19.     ev->what = PROC_EVENT_EXIT;  
  20.     ev->event_data.exit.process_pid = task->pid;  
  21.     ev->event_data.exit.process_tgid = task->tgid;  
  22.     ev->event_data.exit.exit_code = task->exit_code;  
  23.     ev->event_data.exit.exit_signal = task->exit_signal;  
  24.   
  25.     memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));  
  26.     msg->ack = 0; /* not used */  
  27.     msg->len = sizeof(*ev);  
  28.     cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);  
  29. }  

    参考文档:linux-2.6.38.8/Documentation/connector/connector.txt

    http://www.ibm.com/developerworks/cn/linux/l-connector/

    26)、注销断点 

[cpp]  view plain copy
  1.     ptrace_put_breakpoints(tsk);  
  2.   
  3. /* linux-2.6.38.8/kernel/ptrace.c */  
  4. void ptrace_put_breakpoints(struct task_struct *tsk)  
  5. {  
  6.     if (atomic_dec_and_test(&tsk->ptrace_bp_refcnt))  
  7.         flush_ptrace_hw_breakpoint(tsk);  
  8. }  
  9. /* linux-2.6.38.8/arch/arm/kernel/ptrace.c */  
  10. void flush_ptrace_hw_breakpoint(struct task_struct *tsk)  
  11. {  
  12.     int i;  
  13.     struct thread_struct *t = &tsk->thread;  
  14.   
  15.     for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) {  
  16.         if (t->debug.hbp[i]) {  
  17.             unregister_hw_breakpoint(t->debug.hbp[i]);  
  18.             t->debug.hbp[i] = NULL;  
  19.         }  
  20.     }  
  21. }  

    27)、更新所有子进程的父进程 

[cpp]  view plain copy
  1.     exit_notify(tsk, group_dead);  
  2.   
  3. /* linux-2.6.38.8/kernel/exit.c */  
  4. static void exit_notify(struct task_struct *tsk, int group_dead)  
  5. {  
  6.     int signal;  
  7.     void *cookie;  
  8.   
  9.     /* 
  10.      * This does two things: 
  11.      * 
  12.      * A.  Make init inherit all the child processes 
  13.      * B.  Check to see if any process groups have become orphaned 
  14.      *  as a result of our exiting, and if they have any stopped 
  15.      *  jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2) 
  16.      */  
  17.     forget_original_parent(tsk); //将子进程的父进程重新设置为线程组中的其他线程或init进程  
  18.     exit_task_namespaces(tsk); //当使用计数(current->nsproxy->count)为0时,释放命名空间(current->nsproxy)  
  19.   
  20.     write_lock_irq(&tasklist_lock);  
  21.     if (group_dead)  
  22.         kill_orphaned_pgrp(tsk->group_leader, NULL);  
  23.   
  24.     /* Let father know we died 
  25.      * 
  26.      * Thread signals are configurable, but you aren't going to use 
  27.      * that to send signals to arbitary processes. 
  28.      * That stops right now. 
  29.      * 
  30.      * If the parent exec id doesn't match the exec id we saved 
  31.      * when we started then we know the parent has changed security 
  32.      * domain. 
  33.      * 
  34.      * If our self_exec id doesn't match our parent_exec_id then 
  35.      * we have changed execution domain as these two values started 
  36.      * the same after a fork. 
  37.      */  
  38.     if (tsk->exit_signal != SIGCHLD && !task_detached(tsk) &&  //task_detached函数用于判断tsk->exit_signal是否等于-1  
  39.         (tsk->parent_exec_id != tsk->real_parent->self_exec_id ||  
  40.          tsk->self_exec_id != tsk->parent_exec_id))  
  41.         tsk->exit_signal = SIGCHLD;  //设置SIGCHLD信号  
  42.   
  43.     signal = tracehook_notify_death(tsk, &cookie, group_dead); //判断当前进程是否被跟踪  
  44.     if (signal >= 0)  
  45.         signal = do_notify_parent(tsk, signal); //告知父进程当前进程死亡  
  46.   
  47.     tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE; //当tsk->exit_signal不等于-1,或进程正在被跟踪,则设置tsk->exit_state为EXIT_ZOMBIE  
  48.   
  49.     /* mt-exec, de_thread() is waiting for group leader */  
  50.     if (unlikely(tsk->signal->notify_count < 0))  
  51.         wake_up_process(tsk->signal->group_exit_task);  
  52.     write_unlock_irq(&tasklist_lock);  
  53.   
  54.     tracehook_report_death(tsk, signal, cookie, group_dead);  
  55.   
  56.     /* If the process is dead, release it - nobody will wait for it */  
  57.     if (signal == DEATH_REAP) //如果tsk->exit_state为EXIT_DEAD状态  
  58.         release_task(tsk); //则调用release_task函数回收进程的其他数据结构所占用的内存  
  59. }  

    28)、用于NUMA,当引用计数为0时,释放struct mempolicy结构体所占用的内存 

[cpp]  view plain copy
  1. #ifdef CONFIG_NUMA  
  2.     task_lock(tsk);  
  3.     mpol_put(tsk->mempolicy);  
  4.     tsk->mempolicy = NULL;  
  5.     task_unlock(tsk);  
  6. #endif  

    29)、释放struct futex_pi_state结构体所占用的内存 

[cpp]  view plain copy
  1. #ifdef CONFIG_FUTEX  
  2.     if (unlikely(current->pi_state_cache))  
  3.         kfree(current->pi_state_cache);  
  4. #endif  

    30)、释放struct io_context结构体所占用的内存 

[cpp]  view plain copy
  1.     if (tsk->io_context)  
  2.         exit_io_context(tsk);  
  3.   
  4. /* linux-2.6.38.8/block/blk-ioc.c */  
  5. void exit_io_context(struct task_struct *task)  
  6. {  
  7.     struct io_context *ioc;  
  8.   
  9.     task_lock(task);  
  10.     ioc = task->io_context;  
  11.     task->io_context = NULL;  
  12.     task_unlock(task);  
  13.   
  14.     if (atomic_dec_and_test(&ioc->nr_tasks))  
  15.         cfq_exit(ioc);  
  16.   
  17.     put_io_context(ioc);  
  18. }  

    31)、释放与进程描述符splice_pipe字段相关的资源 

[cpp]  view plain copy
  1.     if (tsk->splice_pipe)  
  2.         __free_pipe_info(tsk->splice_pipe);  
  3.   
  4. /* linux-2.6.38.8/fs/pipe.c */  
  5. void __free_pipe_info(struct pipe_inode_info *pipe)  
  6. {  
  7.     int i;  
  8.   
  9.     for (i = 0; i < pipe->buffers; i++) {  
  10.         struct pipe_buffer *buf = pipe->bufs + i;  
  11.         if (buf->ops)  
  12.             buf->ops->release(pipe, buf);  
  13.     }  
  14.     if (pipe->tmp_page)  
  15.         __free_page(pipe->tmp_page);  
  16.     kfree(pipe->bufs);  
  17.     kfree(pipe);  
  18. }  

    32)、调度其它进程 

[cpp]  view plain copy
  1. tsk->state = TASK_DEAD; //调度程序忽略处于TASK_DEAD状态的进程  
  2. schedule();  

    在调用do_exit函数之后,尽管进程已经不能再被调度,但系统还是保留了它的进程描述符,这样做是为了让系统有办法在进程终止后仍能获得它的信息。在父进程获得已终止子进程的信息后,子进程的task_struct结构体才被释放(包括此进程的内核栈)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值