jake1036
My Links
C++博客
首页
新随笔
联系
聚合
管理
Blog Stats
Posts - 101
Stories - 0
Comments - 23
Trackbacks - 0
常用链接
我的随笔
我的评论
我参与的随笔
留言簿
(1)
给我留言
查看公开留言
查看私人留言
随笔分类
c++学习总结(7)
(rss)
larbin源码分析(4)
(rss)
算法相关(65)
(rss)
随笔档案
2011年9月 (4)
2011年8月 (1)
2011年7月 (5)
2011年6月 (24)
2011年5月 (34)
2011年4月 (10)
2011年3月 (4)
2010年12月 (1)
2010年11月 (7)
2010年10月 (5)
2010年9月 (5)
2010年8月 (1)
搜索
最新评论
1. re: 01背包问题总结(一)http://www.cppblog.com/Modules/CaptchaImage/JpegImage.aspx
评论内容较长,点击标题查看
--http://www.cppblog.com/Modules/CaptchaImage/JpegIm
2. re: 编程之美-2.5寻求最大的K个数[未登录]
你确定以上代码可以运行?
呵呵
--xixi
3. re: larbin源码分析(七) larbin中的2种容器与4个url队列
评论内容较长,点击标题查看
--Humton
4. re: larbin源码分析(七) larbin中的2种容器与4个url队列
评论内容较长,点击标题查看
--Humton
5. re: 动态规划法-------最大连续子序列和
@123
谁说的,明明b[7] == 25好吧
--456
阅读排行榜
1. 01背包问题总结(一)(24983)
2. 动态规划法-------最大连续子序列和(9604)
3. c++类模板学习(8025)
4. 完全背包问题 <二>(4499)
5. 编程之美1.8-----电梯调度算法(4179)
评论排行榜
1. 2011-4-16 淘宝实习生面试总结(6)
2. 动态规划法-------最大连续子序列和(3)
3. 动态规划法-----最长增序子序列(非连续)(3)
4. 面试100 34找出数组中唯一出现一次的两个数字(2)
5. larbin源码分析(七) larbin中的2种容器与4个url队列(2)
linux0.11---fork.c函数分析
1 功能描述
fork()系统调用用于创建子进程,Linux中所有的进程都是进程0的子进程。
copy_process()函数用于创建并复制进程代码段和数据段以及环境,在进程复制的过程中,工作主要牵涉到进程数据结构中信息的设置。
系统首先为新建进程在主内存区申请一页内存来存放任务数据结构信息,并复制当前进程任务数据结构中的所有内容作为新进程任务数据结构的模板。
随后对已经复制的任务数据结构内容进行修改。把当前进程设置为新进程的父进程,清除信号位图并复位新进程的各个统计值。接着根据当前进程环境设置新进程任务状态段TSS中各个寄存器的值,新建进程内核态堆栈指针tss.esp0被设置成为任务数据结构所在内存页面的顶端,而tss.ss0被设置为内核数据段选择符。
每当任务进入内核态运行的时候,其内核态堆栈指针初始位置不变,均为任务数据所在页面的顶端。
2源代码分析
#include
<
errno.h
>
#include
<
linux
/
sched.h
>
#include
<
linux
/
kernel.h
>
#include
<
asm
/
segment.h
>
#include
<
asm
/
system.h
>
extern
void
write_verify(unsigned
long
address) ;
long
last_pid
=
0
;
//
最新进程号,其值会由get_empty_process生成
void
verify_area(
void
*
addr ,
int
size)
{
unsigned
long
start ;
start
=
(unsigned
long
) addr ;
size
+=
start
&
0xfff
;
start
&=
0xfffff000
;
start
+=
get_base(current
->
ldt[
2
]) ;
while
(size
>
0
)
{
size
-=
4096
;
write_verify(start) ;
start
+=
4096
;
}
}
//
该函数为新的进程在线性地址空间中设置新的代码段和数据段基地址和限长
int
copy_mem(
int
nr ,
struct
task_struct
*
p)
{
unsigned
long
old_data_base , new_data_base , data_limit ;
unsigned
long
old_code_base , new_code_base , code_limit ;
code_limit
=
get_limit(
0x0f
) ;
data_limit
=
get_limit(
0x17
) ;
old_code_base
=
get_base(current
->
ldt[
1
]) ;
old_data_base
=
get_base(current
->
ldt[
2
]) ;
if
(old_code_base
!=
old_data_base)
panic(
"
We donot support seperate ID
"
) ;
if
(data_limit
<
code_limit)
panic(
"
Bad data_limit
"
) ;
new_data_base
=
new_code_base
=
nr
*
0x4000000
;
//
nr * 64MB
p
->
start_code
=
new_code_base ;
set_base(p
->
ldt[
1
] , new_code_base) ;
set_base(p
->
ldt[
2
] , new_data_base) ;
if
(copy_page_tables(old_data_base , new_data_base , data_limit))
{
free_page_tables(new_data_base , data_limit) ;
return
-
ENOMEM ;
}
return
0
;
}
//
下面是主要的fork程序,负责复制系统进程信息
//
并且设置必要的寄存器,还整个地复制数据段
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 ;
//
并不是指针的赋值 ,而是直接申请了一个空间
//
下面开始修改任务数据结构的值
p
->
state
=
TASK_UNINTERRUPTIBLE ;
p
->
pid
=
last_pid ;
p
->
father
=
current
->
pid ;
p
->
counter
=
p
->
priority ;
//
设置时间片
p
->
signal
=
0
;
//
信号位图置0
p
->
alarm
=
0
;
//
报警定时器值
p
->
leader
=
0
;
//
进程的领导权
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
;
//
这是当fork()调用返回时 新进程会返回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 ;
}
//
如果父进程中有些文件是打开的,则将对应文件的打开次数加1 ,因为子进程会共享父进程打开的这些文件
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
++
;
//
最后在GDT表中设置新任务TSS段和LDT段描述符
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 ;
return
last_pid ;
}
//
为新进程取得不重复的进程号last_pid ,函数返回在任务数组中的任务号
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 ;
}
posted on 2010-11-08 19:48
kahn
阅读(1000)
评论(0)
编辑
收藏
引用
只有注册用户
登录
后才能发表评论。
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
网站导航:
博客园
IT新闻
BlogJava
知识库
博问
管理
Powered by:
C++博客
Copyright © kahn