URN Logo
UNIX Resources » Linux » China Linux Forum » Linux内核技术 » 293 » 新兵笔记--ULK(C3) Creating Processes
announcement 声明: 本页内容为中国Linux论坛的内容镜像,文章的版权以及其他所有的相关权利属于中国Linux论坛和相应文章的作者,如果转载,请注明文章来源及相关版权信息。
Resources
China Linux Forum(finished)
Linux Forum(finished)
FreeBSD China(finished)
linuxforum.net
  业界新闻与评论
  自由软件杂谈
  IT 人生
  Linux软件快递
  翻译作坊
  Linux图书与评论
  GNU Emacs/XEmacs
  Linux 中文环境和中文化
  Linux桌面与办公软件
  Linux 多媒体与娱乐版
  自由之窗Mozilla
  笔记本电脑上的Linux
  Gentoo
  Debian 一族
  网络管理技术
  Linux 安装与入门
  WEB服务器和FTP服务器
  域名服务器和邮件服务器
  Linux防火墙和代理服务器应用
  文件及打印服务器
  技术培训与认证
  TI专版
  Linux内核技术
  Linux 嵌入技术
  Linux设备驱动程序
  Linux 集群技术
  LINUX平台数据库
  系统和网络安全
  CPU 与 编译器
  系统计算研究所专栏
  Linux下的GUI软件开发
  C/C++编程版
  PHP 技 术
  Java&jsp技术
  Shell编程技术
  Perl 编 程
  Python 编 程
  XML/Web Service 技术
  永远的Unix
  FreeBSD世界
   
新兵笔记--ULK(C3) Creating Processes
新兵笔记--ULK(C3) Creating Processes - Big John [2001-05-29 17:36 | 5,290 byte(s)]
 
 
Re: 新兵笔记--ULK(C3) Creating Processes - jkl [2001-05-30 12:30 | 266 byte(s)]
 
Re: 新兵笔记--ULK(C3) Creating Processes - Big John [2001-05-31 15:34 | 586 byte(s)]
 
Re: 新兵笔记--ULK(C3) Creating Processes - lucian_yao [2001-05-29 21:39 | 184 byte(s)]
 
Subject: 新兵笔记--ULK(C3) Creating Processes
Author: Big John    Posted: 2001-05-29 17:36    Length: 5,290 byte(s)
[Original] [Print] [Top]
description:
创建一个进程我一直认为是很复杂的一件事情,它牵涉太多的东西,现在就提出来讲似乎早了点,我只感觉有点力不从心了。

不管怎样,还是开始吧,先让我们考虑了下fork一个进程需要进行的工作吧,最少它应该分配一个本章第一节中讲到的task_struct结构体;然后它还应该有一些父子关系,运行状态等东西是要满足的;最后,它和父进程有相同的内存结构,相同的代码,相同的文件,这些都是要解决的问题;还有一个小问题,父子进程同时从fork返回,但返回值不一样,相信每个用过fork的人都会知道了,如何实现的呢?

实际运行的问题远不止这些,还是来看代码吧,do_fork这个所有创建进程的入口,看它都解决了那些问题。

第一个问题是CLONE_PID,它好象会起多个process 0,这和多CPU有关,我就不关心它了。
然后是一个有关vfork的实现问题,vfork的含义为创建一个子进程,这个子进程和父进程共享地址空间,并且,父进程会阻塞在vfork的调用,直到子进程结束或执行一个新的程序父进程才能解除阻塞。Linux的实现如下:
1、struct semaphore sem = MUTEX_LOCKED; // 定义一个信号灯并初始化为已锁状态
2、current->vfork_sem = &sem; // 把信号灯赋到父进程的vfork_sem域中
3、if ((clone_flags & CLONE_VFORK) && (retval > 0)) // 如果是vfork调用,则父进程阻塞
down(&sem);
4、up(tsk->p_opptr->vfork_sem); // 解除父进程的vfork_sem信号灯
其中1-3是在do_fork中调用的,4是在mm_release中,想来进程结束或执行新的程序时会调用这个函数吧。

然后就是为子进程分配一个描述符并进行适当的初始化了。首先调用alloc_task_struct为子进程分配一个task_struct(这个函数在第一节中看到过),并进行一个“野蛮”的结构体值copy,把父进程的所有值copy到子进程的描述符中,由于是值copy,所以现在子进程的所有的指针都和父进程的指向相同的地方。然后调用find_empty_process在task数组中找一个空的位置并把它发进去。它还将调用get_pid得到一个进程号(这个看似简单的工作也是有说头的)。它的state会被初始化为TASK_RUNNING,并且它会由write_unlock_irq放到可运行队列中,它还将调用hash_pid函数把它挂进一个hash表pidhash中。它的起始时间将被置为jiffies,这是Linux的一个内部时间。当然,它还有一堆指针要置,一堆值要初始化,但这些应该是比较主要的了,也是我现在能理解的。

然后是一些资源环境的copy,文件描述符,进程路径,信号,虚存系统(也就是我说的线性地址空间),这些都有相应的clone_flag控制,你看每个函数的开头都会有的。具体情况就不讲了,否则这节就没完了。等我有时间或那位英雄有心情再把它补上吧。

然后是copy_thread函数,它是用来算是堆栈和tss段的,pt_regs是系统调时指向栈顶的一个结构,也就是说进程从do_fork调用返回用户态时,运行环境将从这里弹出。这里好象比较重要的是一个eax域吧,它被强行置0,好象就表示子进程退出时得到的返回值是0。然后是tss段的初始化,它的esp指向栈顶,它的eip指向ret_from_fork,这个东西在entry.s中,它是怎么用呢?我也没仔细看了。不过它的意思应该是当子进程得到CPU时,它马上就从do_fork返回到用户态。

还有一个counter域,这个值是用来计算进程的动态优先级的,
current->counter >>= 1;
p->counter = current->counter;
这样就是说父子进程平分这个counter值,它的潜意应该是说你不可能通过多创建进程来多获得CPU的时间,这样可以更公平对待所有进程。

还有就是一些比较杂的事了,比如 if (p->user) {
if (atomic_read(&p->user->count) >= p->rlim[RLIMIT_NPROC].rlim_cur)
goto bad_fork_free;
atomic_inc(&p->user->count);
是来判断当前用户创建的进程是否超出限制了,系统不会希望某个用户不停的创建进程的。这里要注意的是user是一个指针,如上所述,父子进程它们这个域指向的是同一个域。rlim是本章第一节的内容了。

if (p->exec_domain && p->exec_domain->module)
__MOD_INC_USE_COUNT(p->exec_domain->module);
if (p->binfmt && p->binfmt->module)
__MOD_INC_USE_COUNT(p->binfmt->module);
用来增加模块计数,可惜我还不知道它怎么用呢。

最后,来看看get_pid这个函数,它的作用是得到一个当前没有使用的pid。在Linux中,pid的值是从0到0x7fff之间。一般新进程使用的pid会是上一个最新进程的pid+1,但是这个pid可能已经超出Linux的允许范围,也许它另有一个进程在用。这样就需要另外选择了。Linux中是这样选择进程号的,它使用一个全局变量last_pid记录上次创建进程时用的进程号,还有一个静态变量next_safe用来记录从last_pid开始,下一个已被使用的最小的进程号。这样如果last_pid不超过next_safe,并且不超过表示范围(>0x7fff)的话,你都可以放心的分配进程了。如果last_pid超过范围,那么它会被置为300,原因是比这小的进程号可能被一些内核线程占用了。不过last_pid超过范围或超过next_pid的值时,last_pid和next_pid都会被重新计算,last_pid会不停的递增,然后遍觅进程链表,直到找到一个没有一个重复的进程号为止,同时next_safe也会和所有进程的pid比较,直到找到一个比last_pid大的最小的正在使用的进程号为止。

question:
要说问题似乎多了点,很多域都不知道是干什么用的,不过这些都待以后解决吧。
还有一个问题没想通:
p->state = TASK_UNINTERRUPTIBLE;
copy_flags(clone_flags, p);
p->pid = get_pid(clone_flags);
p->state = TASK_RUNNING;
这段中为什么先把state置为TASK_UNINTERRUPTIBLE,经过copy_flags和get_pid才把它置为TASK_RUNNING呢?有什么原因吗?还是只是随便写写?

闲言:
上周有点忙,所以一直也没帖,真是对不起党对不起人民。:)

[Original] [Print] [Top]
Subject: Re: 新兵笔记--ULK(C3) Creating Processes
Author: lucian_yao    Posted: 2001-05-29 21:39    Length: 184 byte(s)
[Original] [Print] [Top]
党和人民已经非常感激你了。:-)

我们的
内核文档与源码学习
[Original] [Print] [Top]
Subject: Re: 新兵笔记--ULK(C3) Creating Processes
Author: jkl    Posted: 2001-05-30 12:30    Length: 266 byte(s)
[Original] [Print] [Top]
CLONE_PID是内核初始化线程用来建立各个CPU的idle线程之用,2.2中do_fork()不将这些pid=0的子线程唤醒,而让它们保持在TASK_RUNNING状态。在2.4中有所变化,已经看不到"p->state = TASK_RUNNING"这一行了,所有的子线程都被唤醒。



[Original] [Print] [Top]
Subject: Re: 新兵笔记--ULK(C3) Creating Processes
Author: Big John    Posted: 2001-05-31 15:34    Length: 586 byte(s)
[Original] [Print] [Top]
我明白了,也就是说每个CPU会有一个pid为0的idle进程,并且所有的idle进程都形成一个自环
p->state = TASK_RUNNING;
p->next_run = p;
p->prev_run = p;
但它们不被wake_up_process唤醒。
retval = p->pid;
if (retval) {
。。。
wake_up_process(p);
}
对吧。

但是init好说,自已就是可运行队形的头,所以它不用wake_up的,但其它的idle进程呢?难道它们就一直这样自环着了?
本来不打算接触多CPU,但还是很好奇。

[Original] [Print] [Top]
Subject: Re: 新兵笔记--ULK(C3) Creating Processes
Author: coldsnowice    Posted: 2003-08-10 22:51    Length: 802 byte(s)
[Original] [Print] [Top]
p->state = TASK_UNINTERRUPTIBLE;
copy_flags(clone_flags, p);
p->pid = get_pid(clone_flags);
p->state = TASK_RUNNING;
这段中为什么先把state置为TASK_UNINTERRUPTIBLE,经过copy_flags和get_pid才把它置为TASK_RUNNING呢?有什么原因吗?还是只是随便写写?


之所以把 p->state 置为 TASK_UNITERRUPTIBLE是因为 get_pid() 是一个独占的操作,在这个过程中,有可能一时进不了临界区,所以只好先把 state 设为 这样了!仔细看一看 get_pid的代码就知道了



我有一个问题是关于0 号和 1号进程的。

0 号进程是在 start_kernel 时捏造出来的,在系统启动之后就成为了 idle( )了,而1 号进程是在 kernel_thread( ) 产生的,名字为int ,runqueue 是以 init 进程为队列头的,不知道我的理解对不对啊
[Original] [Print] [Top]
« Previous thread
核心中内存访问是否要进行页表转换?
Linux内核技术
293
Next thread »
关于内核升级的问题?
     

Copyright © 2007~2009 UNIX Resources Network, All Rights Reserved.      About URN | Privacy & Legal | Help | Contact us
webmaster: webmaster@unixresources.net
This page created on 2009-09-07 16:31:24, cost 0.0200080871582 ms.