图说Linux进程之三

2020-06-01 00:00:00 线程 调用 进程 指针 指向


图说Linux进程


图说Linux进程之二


五、计算机体系结构相关数据


在task_struct里面有一个thread_info




为什么需要单独的这个数据结构呢?因为不同的体系结构可能会有不同的实现。



从代码可以看出不同的体系结构有不同的实现。



在thread_info里面有一个指针指向task_struct。


这个指针有什么用的,当一个用户态的进程进入到内核的时候,如何找到对应的task_struct呢?


一般是从当前CPU的一个寄存器里面,通过函数current_thread_info得到在内核态里面的thread_info的地址,然后就可以通过指针找到task_struct了。


六、进程树



task_struct中有一系列指针是用来维护进程树的。



parent指向的是一个进程的原来的父进程,real_parent指向的是进程的当前的父进程,这两个值大多数情况下是一致的。


但是有一种情况下不一致,就是在一个进程被Debug的时候,这个时候GDB就变成了当前的父进程。


父进程有一个children指针指向子进程的列表,里面有两个指针,一个指头,一个指尾。


同一个层次的进程通过sibing链表串起来。


七、进程的资源管理


一个进程是一系列资源的集合,主要有哪些资源呢?


一个是files,指向这个进程打开的所有的文件,具体可参考Linux的虚拟文件系统VFS。

一个是fs,指向文件系统相关的信息,例如进程的当前目录等,也可参考上面的那篇文章。

一个是sighand,指向用于处理信号的signal handler

一个是mm,指向这个进程的内存。


八、fork创建子进程



通过调用系统调用fork可以创建另一个进程。


会在内核里面调用_do_fork


里面会调用

p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace, tls, NUMA_NO_NODE);



里面有

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。



相关文章