朱宇轲 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

今天,我们将通过阅读linux的内核代码来对linux系统中进程的创建过程进行简单的分析。

大家都知道,linux通过进程控制块PCB来对进程进行控制和管理,它存放了进程的数据。在linux中,PCB的代码如下(当然是节选的==):

struct task_struct {
volatile long state;//进程状态
void *stack;//进程堆栈指针
atomic_t usage;
unsigned int flags;
unsigned int ptrace;
...
//一些记录优先级的变量
int prio, static_prio, normal_prio;
unsigned int rt_priority;
const struct sched_class *sched_class;
struct sched_entity se;
struct sched_rt_entity rt;
...
//进程链表
struct list_head tasks;
#ifdef CONFIG_SMP
struct plist_node pushable_tasks;
struct rb_node pushable_dl_tasks;
#endif
//pid号
pid_t pid;
pid_t tgid;
...
//父进程以及子进程
struct task_struct __rcu *real_parent;
struct task_struct __rcu *parent; struct list_head children;
struct list_head sibling;
struct task_struct *group_leader;
...
};

  可以看到,PCB中记录了进程的ID号、优先级、状态、与其他进程关系等信息,操作系统由此对进程进行管理。

  需要注意的是,在操作系统内核的具体实现中,是将当前的进程全部存入到一个循环链表中来进行管理的。如下图所示:

具体的实验则是利用gdb调试进程创建的函数,实验截图如下:

此次我们在6个函数(or 系统调用)处设置了断点:

1.sys_clone
2.do_fork
3.dup_task_struct
4.copy_process
5.copy_thread
6.ret_from_fork

在实验楼所使用的虚拟系统中,进程创建的底层函数是sys_clone,而sys_clone实际上调用的是do_fork,因此可以说do_fork才是真正实现了创建进程细节的函数。

long do_fork(unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
{
struct task_struct *p;
int trace = ;
long nr; ...... p = copy_process(clone_flags, stack_start, stack_size,
child_tidptr, NULL, trace);
......
}

 在这个函数里,p是记录了新的进程的PCB的变量,通过copy_process,系统将父进程的PCB拷贝并修改到子进程中。

copy_process函数则是首先利用dup_task_struct将父进程的PCB全盘拷贝,之后再具体修改与父进程不同的子部分。

static struct task_struct *copy_process(unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *child_tidptr,
struct pid *pid,
int trace)
{
int retval;
struct task_struct *p; //拷贝父进程的PCB
p = dup_task_struct(current);
if (!p)
goto fork_out; //修改具体的部分结构
p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
p->flags |= PF_FORKNOEXEC;
INIT_LIST_HEAD(&p->children);
INIT_LIST_HEAD(&p->sibling);
rcu_copy_process(p);
p->vfork_done = NULL;
spin_lock_init(&p->alloc_lock);
...
retval=copy_thread(clone_flags,stack_start,stack_size,p);
}

  需要注意的是,在copy_process函数中有一个copy_thread函数,在它的函数实现中,将创建的子进程的栈底空间找到,并根据此修改了子进程的ip和sp数据:sp指向栈底,而ip指向ret_from_fork段。那ret_from_fork段又是什么呢,它其实就是下面一段代码:

ENTRY(ret_from_fork)
CFI_STARTPROC
pushl_cfi %eax
call schedule_tail
GET_THREAD_INFO(%ebp)
popl_cfi %eax
pushl_cfi $0x0202 # Reset kernel eflags
popfl_cfi
jmp syscall_exit
CFI_ENDPROC
END(ret_from_fork)

  可以看到,它最终跳转到了syscall_exit,而syscall_exit就是我们上次分析的中断处理程序sys_call中的代码。这样,sp指向的实际是我们触发终端后存储的上下文的那块儿堆栈,ip则指向syscall_eixt,当新的进程创建时,它会首先执行syscall_exit处的代码,不久就会遇到Restore_All,恢复上下文环境,新的进程得以执行。

总结:

  在linux内核中,创建新的进程时,基本思路是复制父进程的PCB给子进程,如果有不同的数据再进行调整。同时,将子进程执行的第一条命令指向中断恢复的代码,从而实现创建新进程的效果。

Linux进程启动过程简析的更多相关文章

  1. Android 启动过程简析

    首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...

  2. linux文件系统写过程简析

    linux写入磁盘过程经历VFS ->  页缓存(page cache) -> 具体的文件系统(ext2/3/4.XFS.ReiserFS等) -> Block IO ->设备 ...

  3. 【转载】简述Linux的启动过程

    原文:简述Linux的启动过程 本文将简单介绍一下Linux的启动过程,希望对那些安装Linux的过程中遇到了问题的朋友有些帮助 声明:本人没用过UEFI模式和GPT分区格式,所有关于这两部分的内容都 ...

  4. Linux 磁盘分区方案简析

    Linux 磁盘分区方案简析 by:授客 QQ:1033553122   磁盘分区 任何硬盘在使用前都要进行分区.硬盘的分区有两种类型:主分区和扩展分区.一个硬盘上最多只能有4个主分区,其中一个主分区 ...

  5. Linux内存管理机制简析

    Linux内存管理机制简析 本文对Linux内存管理机制做一个简单的分析,试图让你快速理解Linux一些内存管理的概念并有效的利用一些管理方法. NUMA Linux 2.6开始支持NUMA( Non ...

  6. 嵌入式Linux的启动过程

    1.了解 Linux 最初是由瑞典赫尔辛基大学的学生 Linus Torvalds在1991 年开发出来的,之后在 GNU的支持下,Linux 获得了巨大的发展.虽然 Linux 在桌面 PC 机上的 ...

  7. (转)Linux的启动过程

    原文链接:http://www.ruanyifeng.com/blog/2013/08/linux_boot_process.html 半年前,我写了<计算机是如何启动的?>,探讨BIOS ...

  8. Linux的启动过程

    Linux的启动过程,也就是Linux的引导流程,这部分主要是理论知识. Linux的开机启动过程 1.1第一步--加载BIOS 当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的 ...

  9. LINUX开机启动过程

    LINUX开机启动过程 启动第一步--加载BIOS当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它.这是因为BIOS中包含了CPU的相关信息 ...

随机推荐

  1. iOS开发UI篇—在UItableview中实现加载更多功能

    一.实现效果 点击加载更多按钮,出现一个加载图示,三秒钟后添加两条新的数据.                      二.实现代码和说明 当在页面(视图部分)点击加载更多按钮的时候,主页面(主控制器 ...

  2. .htaccess的301重定向代码

    把不带www的域名301到带www的域名 RewriteEngine On RewriteCond %{http_host} ^example.com$ [NC] RewriteRule ^(.*)$ ...

  3. java计算组合数

    import java.util.Scanner; public class Zuheshu { //计算m阶乘    public static int Fun(int m){     int su ...

  4. 什么是CPA, CPS, CPT?

    在互联网上或移动端进行产品推广时,经常听到很多术语,什么CPA,CPS,CPT等等.不知是怎么来的,今天网上搜一下术语,在这里做一下笔记. CPA(Cost Per Action) 每行动成本. CP ...

  5. hdu 1050 (preinitilization or postcleansing, std::fill) 分类: hdoj 2015-06-18 11:33 34人阅读 评论(0) 收藏

    errors, clauses in place, logical ones, should be avoided. #include <cstdio> #include <cstr ...

  6. android recyclerview 更新ui

    http://blog.csdn.net/leejizhou/article/details/51179233

  7. Notification NotificationManager RemoteViews PendingIntent

    Notification和NotificationManager :可以用来实现可视化的消息通知等,比如:下载进度显示,消息显示,广播的内容等 RemoteViews :用于创建自定义的Notific ...

  8. hdu 2059

    ps:终于解决了....卡了我好久.最后用了DP.然后还有记忆化搜索优化了一下.终于AC了 思路:要计算dp[n](就是到第n个站的最短时间,也就是最优方案),必须知道dp[0]到dp[n-1] 设j ...

  9. Qt + FFmpeg 本地音频播放器

    http://pan.baidu.com/s/1hqoYXrI

  10. css中选择器的使用

    css是英文Cascading Style Sheets的缩写.它是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言.我们再将html比喻 ...