您的位置:首页 > 理论基础 > 计算机网络

Linux内核源代码分析——fork()原理&多进程网络模型

2014-04-04 09:19 477 查看


Linux内核源代码分析——fork()原理&多进程网络模型

分类: Linux Kernel2013-06-08
00:42 1959人阅读 评论(10) 收藏 举报

Linux
Kernel

今晚和一位500强的leader喝喝小酒吃吃烤鱼,生活乐无边。这位兄弟伙才毕业2年,已经做到管理层了,机遇和能力不可谓不好。喝酒之余,聊到Linux内核的两个问题——fork()、exec()的原理。

兄弟伙:fork()的原理是什么呢?

我:其实一句话就概括了——copy on write。

兄弟伙:copy on wirte我懂,书上介绍的一抓一大把,但是没几本书是能说明白的。我想从你这里得到通俗的解释。

我:我在《口述程序员如何意淫进程》的三篇文章里详细介绍过进程是什么样子的。你应该得到启发的。

兄弟伙:我明白进程是什么样子的了。但是fork()与exec()的原理还不甚明了。

我:从你的角度,你觉得进程需要具备哪些东西呢?

兄弟伙:至少具备四个东西。

1、task_struct结构体。这玩意儿好比是进程的身份证。(线程则没有)

2、进程还必须要有一段可执行代码。

3、进程必须具备它独立的内存空间(线程则没有)。

4、进程必须具备独立的内核堆栈。

我:是的。我顺便补充一下。之所以必须具备内核堆栈,是因为代码从内核态进入用户态时(从0级切换到3级),必须保护内核态“现场”,使其能够恢复。

兄弟伙:那fork()与这4点是什么关系呢?

我:理解这一点,必须分2种情况。

1、调用fork()之后立即调用exec()执行新的程序,生成一个全新的进程。

2、调用fork()之后不调用exec(),仅仅是为将当前进程生成多个,以提升软件并发能力——典型的是Web Server,如Apache,nginx等。

兄弟伙:对于第一点,有什么需要关注的吗?

我:我们先聊第二点吧。

兄弟伙:好。

我:调用fork()之后,操作系统会复制一个全新的task_struct结构体,这个结构体除了id号不一样外,其余的都完全一样——这意味着,两个进程的内存空间也是映射到相同的地址。

兄弟伙:这种情况应该是最简单,也最完美的情况。

我:是的。这种情况下,一般fork的进程数只要与CPU数量一致,整个server的性能就不会太差——至少不会因为context switch而变差。而且,具备一个优点——如果每个进程都使用了IO多路复用,比如最典型的epoll,每一个进程都会因为fork而具备独立的数据结构,这相对与多线程模型来说,实在太简单了。

兄弟伙:啊。你不是说“两个进程的内存空间也是映射到相同的地址”吗?这岂不是互相矛盾?

我:这个问题提得很好。这并不矛盾。在fork时,两个进程是共享想同的内存的。但是,当其中一个进程试图去修改其中一个数据结构时(写时复制),Linux内核就会产生“缺页中断”为该数据结构分配全新的空间。

兄弟伙:为什么Unix采用写时复制会大幅度提升内存管理性能呢?

我:如果不采用写时复制,那么调用fork时,就会为进程分配全新的、独立的内存空间地址,而事实上,其中很大一部分内容可能与父进程是相同的——也就是说,大部分内存其实被重复浪费了。而采用写时复制之后,只有当真的需要分配独立的内存空间的时候,才会发生缺页中断,分配全新的内存空间,这个copy on write是基于page的,而不是基于进程的。

兄弟伙:明白了。通过代码分析下fork()吧。

我:首先,你需要明白,fork()其实做了些什么。我选一些早期的Linux内核代码给你看看吧。fork()其实做了2步。1、找到空闲的进程号。2、从父进程拷贝进程信息。

1、

[html] view
plaincopy

int find_empty_process(void)

{

int i;

repeat:

if ((++last_pid)<0) last_pid=1;

for(i=0 ; i<NR_TASKS ; i++)

if (task[i] && task[i]->pid == last_pid) goto repeat;

for(i=1 ; i<NR_TASKS ; i++)

if (!task[i])

return i;

return -EAGAIN;

}

2、

[html] view
plaincopy

int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,

long ebx,long ecx,long edx,

long fs,long es,long ds,

long eip,long cs,long eflags,long esp,long ss)

{

struct task_struct *p;

int i;

struct file *f;

p = (struct task_struct *) get_free_page();

if (!p)

return -EAGAIN;

task[nr] = p;

*p = *current; /* NOTE! this doesn't copy the supervisor stack */

p->state = TASK_UNINTERRUPTIBLE;

p->pid = last_pid;

p->father = current->pid;

p->counter = p->priority;

p->signal = 0;

p->alarm = 0;

p->leader = 0; /* process leadership doesn't inherit */

p->utime = p->stime = 0;

p->cutime = p->cstime = 0;

p->start_time = jiffies;

p->tss.back_link = 0;

p->tss.esp0 = PAGE_SIZE + (long) p;

p->tss.ss0 = 0x10;

p->tss.eip = eip;

p->tss.eflags = eflags;

p->tss.eax = 0;

p->tss.ecx = ecx;

p->tss.edx = edx;

p->tss.ebx = ebx;

p->tss.esp = esp;

p->tss.ebp = ebp;

p->tss.esi = esi;

p->tss.edi = edi;

p->tss.es = es & 0xffff;

p->tss.cs = cs & 0xffff;

p->tss.ss = ss & 0xffff;

p->tss.ds = ds & 0xffff;

p->tss.fs = fs & 0xffff;

p->tss.gs = gs & 0xffff;

p->tss.ldt = _LDT(nr);

p->tss.trace_bitmap = 0x80000000;

if (last_task_used_math == current)

__asm__("clts ; fnsave %0"::"m" (p->tss.i387));

if (copy_mem(nr,p)) {

task[nr] = NULL;

free_page((long) p);

return -EAGAIN;

}

for (i=0; i<NR_OPEN;i++)

if (f=p->filp[i])

f->f_count++;

if (current->pwd)

current->pwd->i_count++;

if (current->root)

current->root->i_count++;

if (current->executable)

current->executable->i_count++;

set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));

set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));

p->state = TASK_RUNNING; /* do this last, just in case */

return last_pid;

}

find_empty_process()这个函数你一看就明白了,实在太简单。我们分析下copy_process这个函数吧。

在copy_process这个函数里,有一行比较牛逼的语句。这一句相对比较难一点,需要重点说明下。

p = (struct task_struct *) get_free_page();

这里的新task_struct为什么会指向一个free page呢?



明白了吧?

task_struct结构体是按page分配的,多余的部分作为该进程的内核堆栈,从底向task_struct延伸。

之后就是对task_struct的属性进行设置了,包括“智能”与CPU相关部分属性。

通过这部分源代码的分析,你应该明白了吧——最初的“口述程序员如何意淫进程”这样的吹牛B的话看似随意,其实是理解Linux内核的基础与根本,如果真把那些文章当成吹牛逼了,这里的源代码分析对你来说就是天书了——如何才能轻松看懂源代码分析?

答案是——多看几遍吹牛逼的对话,直到你明白这其中的深意。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐