以下内容已屏蔽图片优化访问速度 |
---|
图说Linux进程 图说Linux进程之二 五、计算机体系结构相关数据 在task_struct里面有一个thread_info [IMG] [IMG] 为什么需要单独的这个数据结构呢?因为不同的体系结构可能会有不同的实现。 [IMG] 从代码可以看出不同的体系结构有不同的实现。 [IMG] 在thread_info里面有一个指针指向task_struct。 这个指针有什么用的,当一个用户态的进程进入到内核的时候,如何找到对应的task_struct呢? 一般是从当前CPU的一个寄存器里面,通过函数current_thread_info得到在内核态里面的thread_info的地址,然后就可以通过指针找到task_struct了。 六、进程树 [IMG] task_struct中有一系列指针是用来维护进程树的。 [IMG] parent指向的是一个进程的原来的父进程,real_parent指向的是进程的当前的父进程,这两个值大多数情况下是一致的。 但是有一种情况下不一致,就是在一个进程被Debug的时候,这个时候GDB就变成了当前的父进程。 [IMG] 父进程有一个children指针指向子进程的列表,里面有两个指针,一个指头,一个指尾。 同一个层次的进程通过sibing链表串起来。 七、进程的资源管理 一个进程是一系列资源的集合,主要有哪些资源呢? [IMG] 一个是files,指向这个进程打开的所有的文件,具体可参考Linux的虚拟文件系统VFS。 一个是fs,指向文件系统相关的信息,例如进程的当前目录等,也可参考上面的那篇文章。 一个是sighand,指向用于处理信号的signal handler 一个是mm,指向这个进程的内存。 八、fork创建子进程 [IMG] 通过调用系统调用fork可以创建另一个进程。 会在内核里面调用_do_fork [IMG] 里面会调用 p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace, tls, NUMA_NO_NODE); [IMG] 里面有 p = dup_task_struct(current, node); retval = copy_creds(p, clone_flags); cgroup_fork(p); retval = copy_files(clone_flags, p); retval = copy_fs(clone_flags, p); retval = copy_sighand(clone_flags, p); retval = copy_signal(clone_flags, p); retval = copy_mm(clone_flags, p); retval = copy_namespaces(clone_flags, p); retval = copy_io(clone_flags, p); retval = copy_thread_tls(clone_flags, stack_start, stack_size, p, tls); pid = alloc_pid(p->nsproxy->pid_ns_for_children); 子进程有独立的task_struct结构,有自己的PID,在fork的当下,代码段是和父进程是一样的,一般会被exec系列函数重新加载新的代码段,数据段和栈是新创建的,采取的copy on write的模式。 上面提到的四个数据结构,都是完全拷贝一份的。 九、pthread_create创建新线程 新的线程和原来的线程是共享进程空间的,因而调用__clone函数。 在内核中调用sys_clone函数,但是会设定以下的flag CLONE_VM,则子线程和父线程共享虚拟内存 CLONE_FILES,共享files CLONE_FS,共享fs CLONE_SIGHAND,共享sighand。 [IMG] |