免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1453 | 回复: 0

Processes(二十) [复制链接]

论坛徽章:
0
发表于 2008-05-05 18:20 |显示全部楼层

Destroying Processes
Most processes "die" in the sense that they terminate the execution of the code they were supposed to run. When this occurs, the kernel must be notified so that it can release the resources owned by the process; this includes memory, open files, and any other odds and ends that we will encounter in this book, such as semaphores.
大多数进程死掉,标志是结束了它们应该运行的代码的执行。当它发生时,内核必须被告知,使得它可以释放这个进程拥有的资源;包括内存,打开的文件和其他杂七杂八的东西,比如信号量。
The usual way for a process to terminate is to invoke the exit( ) library function, which releases the resources allocated by the C library, executes each function registered by the programmer, and ends up invoking a system call that evicts the process from the system. The exit( ) library function may be inserted by the programmer explicitly. Additionally, the C compiler always inserts an exit( ) function call right after the last statement of the main( ) function.
进程结束的通常方法就是调用exit()库函数,它释放了由C库分配的资源,执行程序员注册的每个函数,最后通过一个将进程从系统中逐出的系统调用结束。库函数exit()可以被程序员显式地插入。另外,C编译器总是在main()函数的最后一个语句后插入一个exit()函数。
Alternatively, the kernel may force a whole thread group to die. This typically occurs when a process in the group has received a signal that it cannot handle or ignore (see Chapter 11) or when an unrecoverable CPU exception has been raised in Kernel Mode while the kernel was running on behalf of the process (see Chapter 4).
另外,内核可能强迫整个线程组结束。这通常发生在组内的进程收到一个它无法处理或忽略的信号,或者当内核在执行这个进程时内核栈内产生一个无法恢复的CPU异常。
Process Termination
In Linux 2.6 there are two system calls that terminate a User Mode application:
Linux2.6中有2个系统调用可以结束用户空间程序:
·         The exit_group( ) system call, which terminates a full thread group, that is, a whole multithreaded application. The main kernel function that implements this system call is called do_group_exit( ). This is the system call that should be invoked by the exit() C library function.
系统调用exit_group(),结束整个线程组,即整个多线程程序。实现这个系统调用的主要内核函数为do_group_exit()。这个系统调用应该由C库函数exit()调用。
·         The _exit( ) system call, which terminates a single process, regardless of any other process in the thread group of the victim. The main kernel function that implements this system call is called do_exit( ). This is the system call invoked, for instance, by the pthread_exit( ) function of the LinuxThreads library.
系统调用_exit(),结束单独一个进程,而不考虑该线程组内其他进程。实现这个系统调用的主要内核函数是do_exit()。这个系统调用由,比如说LinuxThreads库的pthread_exit()函数调用。
The do_group_exit( ) function
The do_group_exit( ) function kills all processes belonging to the thread group of current. It receives as a parameter the process termination code, which is either a value specified in the exit_group( ) system call (normal termination) or an error code supplied by the kernel (abnormal termination). The function executes the following operations:
函数do_group_exit()杀死属于curent的线程组的所有进程。它接收进程结束码为参数,进程结束码既可以是由exit_group()系统调用指明的值(正常结束),也可以是内核支持的错误码(不正常结束)。这个函数执行下列操作:
1.    Checks whether the SIGNAL_GROUP_EXIT flag of the exiting process is not zero, which means that the kernel already started an exit procedure for this thread group. In this case, it considers as exit code the value stored in current->signal->group_exit_code, and jumps to step 4.
检查退出进程的SIGNAL_GROUP_EXIT标志是否不为0,意味着内核已经开始了这个线程组的结束工作。在这个情况下,它认为存储在current->signal->group_exit_code的值为退出码,跳到第4步。
2.    Otherwise, it sets the SIGNAL_GROUP_EXIT flag of the process and stores the termination code in the current->signal->group_exit_code field.
否则,设置进程的SIGNAL_GROUP_EXIT标志,并将结束码存储在current->signal->group_exit_code成员。
3.    Invokes the zap_other_threads( ) function to kill the other processes in the thread group of current, if any. In order to do this, the function scans the per-PID list in the PIDTYPE_TGID hash table corresponding to current->tgid; for each process in the list different from current, it sends a SIGKILL signal to it (see Chapter 11). As a result, all such processes will eventually execute the do_exit( ) function, and thus they will be killed.
调用zap_other_threads()函数,杀死current的线程组的其他进程,如果有的话。为了完成这个,函数在PIDTYPE_TGID hash表中遍历对应current->tgid的每PID链表;对这个链表的每个不同于current的进程,它发送一个SIGKILL信号给它。结果,所有这些的进程最后都执行do_exit()函数,因此它们都被杀死。
4.    Invokes the do_exit( ) function passing to it the process termination code. As we'll see below, do_exit( ) kills the process and never returns.
调用do_exit()函数并将进程结束码传递给它。do_exit()杀死进程,而且不返回。
The do_exit( ) function
All process terminations are handled by the do_exit( ) function, which removes most references to the terminating process from kernel data structures. The do_exit( ) function receives as a parameter the process termination code and essentially executes the following actions:
所有进程的结束都是由函数do_exit()处理的,它从内核数据结构中移除大多数指向这个将结束进程的引用。函数do_exit()接收进程结束码为参数,并执行下列操作:
1.    Sets the PF_EXITING flag in the flag field of the process descriptor to indicate that the process is being eliminated.
设置进程描述符的flag成员中的PF_EXITING标志,表示这个进程正在被结束。
2.    Removes, if necessary, the process descriptor from a dynamic timer queue via the del_timer_sync( ) function (see Chapter 6).
如有必要,通过函数del_timer_sync()将进程描述符从动态定时器队列中移除。
3.    Detaches from the process descriptor the data structures related to paging, semaphores, filesystem, open file descriptors, namespaces, and I/O Permission Bitmap, respectively, with the exit_mm( ), exit_sem( ), _ _exit_files( ), _ _exit_fs(), exit_namespace( ), and exit_thread( ) functions. These functions also remove each of these data structures if no other processes are sharing them.
从进程描述符中分离与分页管理、信号量、文件系统、打开的文件描述符、命名空间和I/O权限映射有关的数据结构,分别使用函数exit_mm(),exit_sem(), _ _exit_files(), _ _exit_fs(),exit_namespace()和exit_thread()。如果没有其他进程共享这些数据结构,这些函数也将它们移除。
4.    If the kernel functions implementing the execution domain and the executable format (see Chapter 20) of the process being killed are included in kernel modules, the function decreases their usage counters.
如果实现被杀死进程的执行域和可执行格式的内核函数包含在内核模块中,这个函数减少它们的使用计数。
5.    Sets the exit_code field of the process descriptor to the process termination code. This value is either the _exit( ) or exit_group( ) system call parameter (normal termination), or an error code supplied by the kernel (abnormal termination).
设置进程描述符的exit_code成员为进程结束码。这个值是_exit()或exit_group()系统调用参数(正常结束),或者内核提供的错误码(不正常结束)。
6.    Invokes the exit_notify( ) function to perform the following operations:
调用函数exit_notify(),实现下列操作:
a.    Updates the parenthood relationships of both the parent process and the child processes. All child processes created by the terminating process become children of another process in the same thread group, if any is running, or otherwise of the init process.
更新父进程和子进程的父子关系。正被终止的进程创建的所有子进程变为同一个线程组内另一进程的子进程,如果任何一个在运行,否则选择init进程。
b.    Checks whether the exit_signal process descriptor field of the process being terminated is different from -1, and whether the process is the last member of its thread group (notice that these conditions always hold for any normal process; see step 16 in the description of copy_process( ) in the earlier section "The clone( ), fork( ), and vfork( ) System Calls"). In this case, the function sends a signal (usually SIGCHLD) to the parent of the process being terminated to notify the parent about a child's death.
检查正被终止的进程的描述符成员exit_signal是否不为-1,并且这个进程是否是线程组的最后一个成员。在这种情况下,函数发送一个信号(通常时SIGCHLD)给这个正被终止的进程的父进程,将子进程的结束告知父进程。
c.    Otherwise, if the exit_signal field is equal to -1 or the thread group includes other processes, the function sends a SIGCHLD signal to the parent only if the process is being traced (in this case the parent is the debugger, which is thus informed of the death of the lightweight process).
否则,如果exit_signal成员等于-1,或者线程组包含其他进程,这个函数仅在进程被跟踪(这种情况是,父进程就是跟踪程序,因此直到轻进程的结束)时,发送SIGCHLD信号给它的父进程。
d.    If the exit_signal process descriptor field is equal to -1 and the process is not being traced, it sets the exit_state field of the process descriptor to EXIT_DEAD, and invokes release_task( ) to reclaim the memory of the remaining process data structures and to decrease the usage counter of the process descriptor (see the following section). The usage counter becomes equal to 1 (see step 3f in the copy_process( ) function), so that the process descriptor itself is not released right away.
如果进程描述符的exit_signal成员等于-1,并且进程没有被跟踪,设置进程描述符的exit_state成员为EXIT_DEAD,调用release_task()来回收剩下的进程数据结构的内存,减小进程描述符的使用计数。使用计数值变为1,使得这个进程描述符不会立刻被释放。
e.    Otherwise, if the exit_signal process descriptor field is not equal to -1 or the process is being traced, it sets the exit_state field to EXIT_ZOMBIE. We'll see what happens to zombie processes in the following section.
否则,如果进程描述符的exit_signal成员不等于-1,或者进程被跟踪,设置exit_state成员为EXIT_ZOMBIE。
f.    Sets the PF_DEAD flag in the flags field of the process descriptor (see the section "The schedule( ) Function" in Chapter 7).
设置进程描述符的flags成员中PF_DEAD标志。
7.    Invokes the schedule( ) function (see Chapter 7) to select a new process to run. Because a process in an EXIT_ZOMBIE state is ignored by the scheduler, the process stops executing right after the switch_to macro in schedule( ) is invoked. As we'll see in Chapter 7, the scheduler will check the PF_DEAD flag and will decrease the usage counter in the descriptor of the zombie process being replaced to denote the fact that the process is no longer alive.
调用schedule()函数选择一个新的进程运行。因为处在EXIT_ZOMBIE状态的进程被调度器忽略,这个进程在schedule()中宏switch_to被调用后停止执行。调度器将检查PF_DEAD标志,并减少即将被替换的僵死进程的描述符中的使用计数,表明这个进程不再活动了。
Process Removal
The Unix operating system allows a process to query the kernel to obtain the PID of its parent process or the execution state of any of its children. A process may, for instance, create a child process to perform a specific task and then invoke some wait( )-like library function to check whether the child has terminated. If the child has terminated, its termination code will tell the parent process if the task has been carried out successfully.
Unix操作系统允许进程向内核查询它父进程的PID或它的任一子进程的执行状态。比如,进程可以创建一个子进程来实现某个特定的任务,并调用wait-类似的库函数来检查子进程是否结束。如果子进程已经结束了,它的结束码将会告知父进程这个任务是否被成功地执行。
To comply with these design choices, Unix kernels are not allowed to discard data included in a process descriptor field right after the process terminates. They are allowed to do so only after the parent process has issued a wait( )-like system call that refers to the terminated process. This is why the EXIT_ZOMBIE state has been introduced: although the process is technically dead, its descriptor must be saved until the parent process is notified.
为了适应这个设计要求,Unix内核不允许在进程结束后丢弃进程描述符的数据。仅在父进程提出了一个涉及被结束进程的wait-类似的系统调用后,才做这件事。这就是为什么引入EXIT_ZOMBIE状态的原因:尽管这个进程技术上死了,它的描述符必须保存到父进程被通知时。
What happens if parent processes terminate before their children? In such a case, the system could be flooded with zombie processes whose process descriptors would stay forever in RAM. As mentioned earlier, this problem is solved by forcing all orphan processes to become children of the init process. In this way, the init process will destroy the zombies while checking for the termination of one of its legitimate children through a wait( )-like system call.
如果父进程在它的子进程前结束会发生什么了?在这种情况下,系统可能会被众多僵死进程淹没,这些进程的进程描述符将会永远保存在RAM中。通过将所有的孤儿进程变为init进程的子进程,解决这个问题。这样,init进程通过wait-类似的系统调用,检查它的合法子进程的结束将其彻底销毁。
The release_task( ) function detaches the last data structures from the descriptor of a zombie process; it is applied on a zombie process in two possible ways: by the do_exit( ) function if the parent is not interested in receiving signals from the child, or by the wait4( ) or waitpid( ) system calls after a signal has been sent to the parent. In the latter case, the function also will reclaim the memory used by the process descriptor, while in the former case the memory reclaiming will be done by the scheduler (see Chapter 7). This function executes the following steps:
函数release_task()从一个僵死进程中分离最后一个数据结构;有两种可能的方式应用在一个僵死进程上:如果父进程对从子进程接收信号不感兴趣,使用do_exit(),或者信号已经发生给父进程后,使用wait4()或wait-类似的系统调用。在后一种情况,函数也会回收进程描述符占用的内存,而前一种,内存回收由调度器进行。
1.    Decreases the number of processes belonging to the user owner of the terminated process. This value is stored in the user_struct structure mentioned earlier in the chapter (see step 4 of copy_process( )).
减少被结束进程的使用者的进程数目。这个值存放在user_struct结构中。
2.    If the process is being traced, the function removes it from the debugger's ptrace_children list and assigns the process back to its original parent.
如果进程被跟踪,函数将其从调试器的ptrace_children链表中移除并这个进程分配给它的初始父进程。
3.    Invokes _ _exit_signal() to cancel any pending signal and to release the signal_struct descriptor of the process. If the descriptor is no longer used by other lightweight processes, the function also removes this data structure. Moreover, the function invokes exit_itimers( ) to detach any POSIX interval timer from the process.
调用_ _exit_signal()取消任何未处理的信号并释放进程的signal_struct描述符。如果这个描述符不再被其他轻进程使用的话,函数也移除这个数据结构。此外,这个函数调用exit_itimers()将任何POSIX定时器从进程中分离。
4.    Invokes _ _exit_sighand() to get rid of the signal handlers.
调用_ _exit_sighand()丢弃信号处理函数。
5.    Invokes _ _unhash_process( ), which in turn:
调用_ _unhash_process():
a.    Decreases by 1 the nr_threads variable.
将nr_threads变量值减1。
b.    Invokes detach_pid( ) twice to remove the process descriptor from the pidhash hash tables of type PIDTYPE_PID and PIDTYPE_TGID.
调用两次detach_pid(),将进程描述符从类型为PIDTYPE_PID和PIDTYPE_TGID的pidhash hash表中移除。
c.    If the process is a thread group leader, invokes again detach_pid( ) twice to remove the process descriptor from the PIDTYPE_PGID and PIDTYPE_SID hash tables.
如果这个进程是线程组组长,再调用两次detach_pid()将进程描述符从类型为PIDTYPE_PGID和PIDTYPE_SID的hash表中移除。
d.    Uses the REMOVE_LINKS macro to unlink the process descriptor from the process list.
使用宏REMOVE_LINKS将进程描述符从进程链表中去掉。
6.    If the process is not a thread group leader, the leader is a zombie, and the process is the last member of the thread group, the function sends a signal to the parent of the leader to notify it of the death of the process.
如果进程不是进程组组长,而组长是僵死进程,这个进程是线程组的最后一个成员,函数发送一个信号给组长的父进程,通知它这个进程的结束。
7.    Invokes the sched_exit( ) function to adjust the timeslice of the parent process (this step logically complements step 17 in the description of copy_process( ))
调用函数sched_exit()调整父进程的时隙。
8.    Invokes put_task_struct() to decrease the process descriptor's usage counter; if the counter becomes zero, the function drops any remaining reference to the process:
调用put_task_struct(),减少进程描述符的使用计数;如果这个计数值为0,函数丢弃任何指向这个进程的引用。
a.    Decreases the usage counter (_ _count field) of the user_struct data structure of the user that owns the process (see step 5 of copy_process( )), and releases that data structure if the usage counter becomes zero.
减少拥有这个进程的用户的user_struct数据结构的使用计数器(_ _count成员),如果计数值为0,则释放那个数据结构。
b.    Releases the process descriptor and the memory area used to contain the thread_info descriptor and the Kernel Mode stack.
释放进程描述符和包含thread_info描述符和内核栈的内存区域。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/65228/showart_674005.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP