如果看了学完前面Linux内核中进程的创建,那么至少对Linux内核中进程产生的机制有了一定的了解。下面就记录一些进程的产生的学习笔记。参考书籍和使用平台还是不变。
1.第一个进程:第一个进程事实上就是Linux kernel本身,第一个进程是唯一一个静态创建的进程,它是在Linux kernel编写和编译的时候创建。具体看看这个进程(注意:在内核中,这个进程叫做init task/thread(pid 0),但是他不是系统起来之后你ps列出来的那个进程init(pid 1))
- /* arch/i386/kernel/init_task.c*/
- static struct fs_struct init_fs =INIT_FS;
- static struct files_struct init_files = INIT_FILES;
- ………………
可以看出来,这个进程的所有结构都是静态创建的,他们位于代码段,init_thread_union位于数据段。
2.fork,clone,kernel_thread:系统之中的其他进程都是由其父进程派生出来的,Linux提供了两个系统调用fork和clone来实现。理论上他们都是fork,由于Linux之后引入了线程的概念,即一种轻量级的进程的概念,是由clone实现的。而他们在底层的调用都是do_fork实现的。关于fork在应用层上的实现,以前学习过了,不用这里浪费水电阐述。下面做Linux内核中系统调用的分析。
fork分析:内核的具体代码冗长不说,以后的更新也是会有变化的,直接分析原理。fork()的原理如下(附上一些内核源码):
(1)为新进程分配一些基本的数据结构,如task_struct等。
- static struct task_struct *dup_task_struct(structt task_struct *orig)
- {
- struct task_struct *tsk;
- struct thread_info *ti;
- prepare_to_copy (orig);
- tsk=alloc_tast_struct();
- if(!tsk)
- return NULL;
- ti = alloc_thread_info ( tsk );
- if(!ti){
- free_task_struct(tsk);
- return NULL;
- }
- *tsk = *orig;
- *tsk->thread_info=ti;
- setup_thread_info=ti;
- atomic_set(&tsk->usage,2);
- atomic_set (&tsk->fs_excl,0);
- return tsk;
- }
(2)共享或者拷贝父进程的资源
(3)为子进程创建虚拟地址空间:一下代码看出,dup_mm主要实现了复制内存的工作
- static int copy_mm(unsigned long clone_flags,struct task_struct *tsk)
- {
- ……
- retval = -ENOMEM;
- mm=dup_mm(tsk);
- if(!mm){
- goto fail_nomem;
- }
- good_mm:
- tsk->mm=mm;
- tsk->active_mm=mm;
- return 0;
- fail_nomem:
- return retval;
- }
(4)为子进程设置好相关虚拟地址空间:这一部分太抽象,我觉得现在不需要理解太多…………
(5)fork()的返回:fork()调用之后有2个返回值,父进程返回子进程的pid很好理解,下面着重理解子进程的返回。在do_fork()中,copy_process()调用完成后,如果没有出错,父进程会去唤醒子进程:
- if(!(clone_flags&CLONE_STOPPED)))
- wake_up_new_task(p,clone_flags);
- else
- p->stats = TASK_STOPPED;