From 5f802ced145a3176ec9c27c92c1caf824a8a30ad Mon Sep 17 00:00:00 2001 From: gatieme Date: Sun, 29 May 2016 22:53:42 +0800 Subject: [PATCH] ... --- .../02-create/04-kthreadd/README.md | 266 ++++++++++++++++++ .../01-process/02-create/04-kthreadd/test.c | 221 +++++++++++++++ .../kernel_thread/Makefile | 0 .../kernel_thread/test_kernel_thread.c | 0 .../.test_kthread_create.ko.cmd | 0 .../.test_kthread_create.mod.o.cmd | 0 .../kthread_create/.test_kthread_create.o.cmd | 0 .../kthread_create/Makefile | 0 .../kthread_create/Module.symvers | 0 .../kthread_create/modules.order | 0 .../kthread_create/test_kthread_create.c | 0 .../kthread_create/test_kthread_create.c.2 | 0 .../kthread_create/test_kthread_create.mod.c | 0 .../kthread_run/Makefile | 0 .../kthread_run/test_kthread_run.c | 0 .../kthread_run/test_kthread_run.c.2 | 0 study/kernel/process/management/README.md | 28 ++ 17 files changed, 515 insertions(+) create mode 100644 study/kernel/01-process/02-create/04-kthreadd/README.md create mode 100644 study/kernel/01-process/02-create/04-kthreadd/test.c rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kernel_thread/Makefile (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kernel_thread/test_kernel_thread.c (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_create/.test_kthread_create.ko.cmd (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_create/.test_kthread_create.mod.o.cmd (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_create/.test_kthread_create.o.cmd (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_create/Makefile (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_create/Module.symvers (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_create/modules.order (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_create/test_kthread_create.c (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_create/test_kthread_create.c.2 (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_create/test_kthread_create.mod.c (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_run/Makefile (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_run/test_kthread_run.c (100%) rename study/kernel/01-process/02-create/{kernel_thead => 06-kernel_thead}/kthread_run/test_kthread_run.c.2 (100%) create mode 100644 study/kernel/process/management/README.md diff --git a/study/kernel/01-process/02-create/04-kthreadd/README.md b/study/kernel/01-process/02-create/04-kthreadd/README.md new file mode 100644 index 0000000..b6a20f1 --- /dev/null +++ b/study/kernel/01-process/02-create/04-kthreadd/README.md @@ -0,0 +1,266 @@ +Linux下1号进程的前世(kernel_init)今生(init进程) +======= +http://zhidao.baidu.com/link?url=S5YkWyeZt4EtesIashfhTP27QbzVgm844EtNNWYGIDtbbWwRwTC7kdoh_bXrUPV4XhRlkxfp3WVjfExP_LZD_K + +| 日期 | 内核版本 | 架构| 作者 | GitHub| CSDN | +| ------------- |:-------------:|:-------------:|:-------------:|:-------------:|:-------------:| +| 2016-05-12 | [Linux-4.5](http://lxr.free-electrons.com/source/?v=4.5) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux进程管理与调度-之-进程的创建](http://blog.csdn.net/gatieme/article/category/6225543) | + +#前言 +------- + +Linux下有3个特殊的进程,idle进程($PID = 0$), init进程($PID = 1$)和kthreadd($PID = 2$) + + +* idle进程由系统自动创建, 运行在内核态 + + idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产生的进程。完成加载系统后,演变为进程调度、交换 + + +* init进程由idle通过kernel_thread创建,在内核空间完成初始化后, 加载init程序, 并最终用户空间 + + 由0进程创建,完成系统的初始化. 是系统中所有其它用户进程的祖先进程 + Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程。在系统启动完成完成后,init将变为守护进程监视系统其他进程。 + + + +* kthreadd进程由idle通过kernel_thread创建,并始终运行在内核空间, 负责所有内核线程的调度和管理 + + 它的任务就是管理和调度其他内核线程kernel_thread, 会循环执行一个kthreadd的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread, 当我们调用kernel_thread创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程 + + + + +我们下面就详解分析2号进程kthreadd + + + + +#2号进程 +------- + +内核初始化rest_init函数中,由进程 0 (swapper 进程)创建了两个process + +* init 进程 (pid = 1, ppid = 0) + +* kthreadd (pid = 2, ppid = 0) + +所有其它的内核线程的ppid 都是 2,也就是说它们都是由kthreadd thread创建的 + +所有的内核线程在大部分时间里都处于阻塞状态(TASK_INTERRUPTIBLE)只有在系统满足进程需要的某种资源的情况下才会运行 + + +它的任务就是管理和调度其他内核线程kernel_thread, 会循环执行一个kthreadd的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread, 当我们调用kernel_thread创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程 + + + +#2号进程的创建 +------- + +在rest_init函数中创建2号进程的代码如下 + +```c +pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); +rcu_read_lock(); +kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); +rcu_read_unlock(); +complete(&kthreadd_done); +``` + + + +#2号进程的事件循环 +------- + + +```c +int kthreadd(void *unused) +{ + struct task_struct *tsk = current; + + /* Setup a clean context for our children to inherit. */ + set_task_comm(tsk, "kthreadd"); + ignore_signals(tsk); + set_cpus_allowed_ptr(tsk, cpu_all_mask); // 允许kthreadd在任意CPU上运行 + set_mems_allowed(node_states[N_MEMORY]); + + current->flags |= PF_NOFREEZE; + + for (;;) { + /* 首先将线程状态设置为 TASK_INTERRUPTIBLE, 如果当前 + 没有要创建的线程则主动放弃 CPU 完成调度.此进程变为阻塞态*/ + set_current_state(TASK_INTERRUPTIBLE); + if (list_empty(&kthread_create_list)) // 没有需要创建的内核线程 + schedule(); // 什么也不做, 执行一次调度, 让出CPU + + /* 运行到此表示 kthreadd 线程被唤醒(就是我们当前) + 设置进程运行状态为 TASK_RUNNING */ + __set_current_state(TASK_RUNNING); + + spin_lock(&kthread_create_lock); // 加锁, + while (!list_empty(&kthread_create_list)) { + struct kthread_create_info *create; + + /* 从链表中取得 kthread_create_info 结构的地址,在上文中已经完成插入操作(将 + kthread_create_info 结构中的 list 成员加到链表中,此时根据成员 list 的偏移 + 获得 create) */ + create = list_entry(kthread_create_list.next, + struct kthread_create_info, list); + + /* 完成穿件后将其从链表中删除 */ + list_del_init(&create->list); + + /* 完成真正线程的创建 */ + spin_unlock(&kthread_create_lock); + + create_kthread(create); + + spin_lock(&kthread_create_lock); + } + spin_unlock(&kthread_create_lock); + } + + return 0; +} +``` + +kthreadd的核心是一for和while循环体。 + +在for循环中,如果发现kthread_create_list是一空链表,则调用schedule调度函数,因为此前已经将该进程的状态设置为TASK_INTERRUPTIBLE,所以schedule的调用将会使当前进程进入睡眠。 + +如果kthread_create_list不为空,则进入while循环,在该循环体中会遍历该kthread_create_list列表,对于该列表上的每一个entry,都会得到对应的类型为struct kthread_create_info的节点的指针create. + +然后函数在kthread_create_list中删除create对应的列表entry,接下来以create指针为参数调用create_kthread(create). + +create_kthread的过程如下 + +#create_kthread完成内核线程创建 +------- + +```c +static void create_kthread(struct kthread_create_info *create) +{ + int pid; + +#ifdef CONFIG_NUMA + current->pref_node_fork = create->node; +#endif + /* We want our own signal handler (we take no signals by default). + 其实就是调用首先构造一个假的上下文执行环境,最后调用 do_fork() + 返回进程 id, 创建后的线程执行 kthread 函数 + */ + pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD); + if (pid < 0) { + /* If user was SIGKILLed, I release the structure. */ + struct completion *done = xchg(&create->done, NULL); + + if (!done) { + kfree(create); + return; + } + create->result = ERR_PTR(pid); + complete(done); + } +} +``` + +在create_kthread()函数中,会调用kernel_thread来生成一个新的进程,该进程的内核函数为kthread,调用参数为 +``` +pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD); +``` +我们可以看到,创建的内核线程执行的事件[kthread](http://lxr.free-electrons.com/source/kernel/kthread.c#L177) + +此时回到 kthreadd thread,它在完成了进程的创建后继续循环,检查 kthread_create_list 链表,如果为空,则 kthreadd 内核线程昏睡过去 + +那么我们现在回想我们的操作 +我们在内核中通过kernel_create或者其他方式创建一个内核线程, 然后kthreadd内核线程被唤醒, 来执行内核线程创建的真正工作,于是这里有三个线程 + +1. kthreadd已经光荣完成使命(接手执行真正的创建工作),睡眠 + +2. 唤醒kthreadd的线程由于新创建的线程还没有创建完毕而继续睡眠 (在 kthread_create函数中) + +3. 新创建的线程已经正在运行kthread,但是由于还有其它工作没有做所以还没有最终创建完成. + + +#新创建的内核线程kthread函数 +------- + +```c +static int kthread(void *_create) +{ + /* Copy data: it's on kthread's stack + create 指向 kthread_create_info 中的 kthread_create_info */ + struct kthread_create_info *create = _create; + + /* 新的线程创建完毕后执行的函数 */ + int (*threadfn)(void *data) = create->threadfn; + /* 新的线程执行的参数 */ + void *data = create->data; + struct completion *done; + struct kthread self; + int ret; + + self.flags = 0; + self.data = data; + init_completion(&self.exited); + init_completion(&self.parked); + current->vfork_done = &self.exited; + + /* If user was SIGKILLed, I release the structure. */ + done = xchg(&create->done, NULL); + if (!done) { + kfree(create); + do_exit(-EINTR); + } + /* OK, tell user we're spawned, wait for stop or wakeup + 设置运行状态为 TASK_UNINTERRUPTIBLE */ + __set_current_state(TASK_UNINTERRUPTIBLE); + + /* current 表示当前新创建的 thread 的 task_struct 结构 */ + create->result = current; + complete(done); + /* 至此线程创建完毕 , 执行任务切换,让出 CPU */ + schedule(); + + ret = -EINTR; + + if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) { + __kthread_parkme(&self); + ret = threadfn(data); + } + /* we can't just return, we must preserve "self" on stack */ + do_exit(ret); +} +``` + +线程创建完毕: + +创建新 thread 的进程恢复运行 kthread_create() 并且返回新创建线程的任务描述符 +新创建的线程由于执行了 schedule() 调度,此时并没有执行. + +直到我们使用wake_up_process(p);唤醒新创建的线程 + +线程被唤醒后, 会接着执行threadfn(data) +```c + ret = -EINTR; + + if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) { + __kthread_parkme(&self); + ret = threadfn(data); + } + /* we can't just return, we must preserve "self" on stack */ + do_exit(ret); +``` + +#总结 +------- +kthreadd进程由idle通过kernel_thread创建,并始终运行在内核空间, 负责所有内核线程的调度和管理,它的任务就是管理和调度其他内核线程kernel_thread, 会循环执行一个kthreadd的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread, 当我们调用kernel_thread创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程 + +我们在内核中通过kernel_create或者其他方式创建一个内核线程, 然后kthreadd内核线程被唤醒, 来执行内核线程创建的真正工作,新的线程将执行kthread函数, 完成创建工作,创建完毕后让出CPU,因此新的内核线程不会立刻运行.需要手工 wake up, 被唤醒后将执行自己的真正工作函数 + +* 任何一个内核线程入口都是 kthread() + +* 通过 kthread_create() 创建的内核线程不会立刻运行.需要手工 wake up. + +* 通过 kthread_create() 创建的内核线程有可能不会执行相应线程函数threadfn而直接退出 + diff --git a/study/kernel/01-process/02-create/04-kthreadd/test.c b/study/kernel/01-process/02-create/04-kthreadd/test.c new file mode 100644 index 0000000..8d2adbc --- /dev/null +++ b/study/kernel/01-process/02-create/04-kthreadd/test.c @@ -0,0 +1,221 @@ + +#include + + +#include + + +#include + + +#include + + +#include + + +#include + + +#include + + + + +#define + sleep_millisecs 1000*60 + + + +static + +int +thread(void + +*arg) + +{ + + long + +ns1, ns2, delta; + + unsigned +int + +cpu; + + struct + +timespec ts1, ts2; + + + + cpu + = *((unsigned int + +*)arg); + + + + printk(KERN_INFO +"### + [thread/%d] test start \n", + cpu); + + + + while + +(!kthread_should_stop()) { + + /* + + * + Do What you want + + */ + + schedule_timeout_interruptible( + + msecs_to_jiffies(1)); + + } + + + + printk(KERN_INFO +"### + [thread/%d] test end \n", + cpu); + + + + return + +0; + +} + + + +static + +int +__init XXXX(void) + +{ + + int + +cpu; + + unsigned +int + +cpu_count = num_online_cpus(); + + unsigned +int + +parameter[cpu_count]; + + struct + +task_struct *t_thread[cpu_count]; + + + + for_each_present_cpu(cpu){ + + parameter[cpu] + = cpu; + + + + t_thread[cpu] + = kthread_create(thread, + (void + +*) (parameter+cpu), "thread/%d", + cpu); + + + + if + +(IS_ERR(t_thread[cpu])) { + + printk(KERN_ERR +"[thread/%d]: + creating kthread failed\n", + cpu); + + + + goto + +out; + + } + + + + kthread_bind(t_thread[cpu], + cpu); + + wake_up_process(t_thread[cpu]); + + } + + + + schedule_timeout_interruptible( + + msecs_to_jiffies(sleep_millisecs)); + + + + for + +(cpu = 0; cpu < cpu_count; cpu++) { + + kthread_stop(t_thread[cpu]); + + } + + + +out: + + return + +0; + +} + + + +static + +void +__exit XXXX_exit(void) + +{ + +} + + + +module_init(XXXX); + +module_exit(XXXX_exit); + + + +MODULE_LICENSE("GPL"); + +MODULE_AUTHOR("bluezd"); + +MODULE_DESCRIPTION("Kernel + study"); \ No newline at end of file diff --git a/study/kernel/01-process/02-create/kernel_thead/kernel_thread/Makefile b/study/kernel/01-process/02-create/06-kernel_thead/kernel_thread/Makefile similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kernel_thread/Makefile rename to study/kernel/01-process/02-create/06-kernel_thead/kernel_thread/Makefile diff --git a/study/kernel/01-process/02-create/kernel_thead/kernel_thread/test_kernel_thread.c b/study/kernel/01-process/02-create/06-kernel_thead/kernel_thread/test_kernel_thread.c similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kernel_thread/test_kernel_thread.c rename to study/kernel/01-process/02-create/06-kernel_thead/kernel_thread/test_kernel_thread.c diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_create/.test_kthread_create.ko.cmd b/study/kernel/01-process/02-create/06-kernel_thead/kthread_create/.test_kthread_create.ko.cmd similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_create/.test_kthread_create.ko.cmd rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_create/.test_kthread_create.ko.cmd diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_create/.test_kthread_create.mod.o.cmd b/study/kernel/01-process/02-create/06-kernel_thead/kthread_create/.test_kthread_create.mod.o.cmd similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_create/.test_kthread_create.mod.o.cmd rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_create/.test_kthread_create.mod.o.cmd diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_create/.test_kthread_create.o.cmd b/study/kernel/01-process/02-create/06-kernel_thead/kthread_create/.test_kthread_create.o.cmd similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_create/.test_kthread_create.o.cmd rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_create/.test_kthread_create.o.cmd diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_create/Makefile b/study/kernel/01-process/02-create/06-kernel_thead/kthread_create/Makefile similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_create/Makefile rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_create/Makefile diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_create/Module.symvers b/study/kernel/01-process/02-create/06-kernel_thead/kthread_create/Module.symvers similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_create/Module.symvers rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_create/Module.symvers diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_create/modules.order b/study/kernel/01-process/02-create/06-kernel_thead/kthread_create/modules.order similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_create/modules.order rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_create/modules.order diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_create/test_kthread_create.c b/study/kernel/01-process/02-create/06-kernel_thead/kthread_create/test_kthread_create.c similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_create/test_kthread_create.c rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_create/test_kthread_create.c diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_create/test_kthread_create.c.2 b/study/kernel/01-process/02-create/06-kernel_thead/kthread_create/test_kthread_create.c.2 similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_create/test_kthread_create.c.2 rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_create/test_kthread_create.c.2 diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_create/test_kthread_create.mod.c b/study/kernel/01-process/02-create/06-kernel_thead/kthread_create/test_kthread_create.mod.c similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_create/test_kthread_create.mod.c rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_create/test_kthread_create.mod.c diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_run/Makefile b/study/kernel/01-process/02-create/06-kernel_thead/kthread_run/Makefile similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_run/Makefile rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_run/Makefile diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_run/test_kthread_run.c b/study/kernel/01-process/02-create/06-kernel_thead/kthread_run/test_kthread_run.c similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_run/test_kthread_run.c rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_run/test_kthread_run.c diff --git a/study/kernel/01-process/02-create/kernel_thead/kthread_run/test_kthread_run.c.2 b/study/kernel/01-process/02-create/06-kernel_thead/kthread_run/test_kthread_run.c.2 similarity index 100% rename from study/kernel/01-process/02-create/kernel_thead/kthread_run/test_kthread_run.c.2 rename to study/kernel/01-process/02-create/06-kernel_thead/kthread_run/test_kthread_run.c.2 diff --git a/study/kernel/process/management/README.md b/study/kernel/process/management/README.md new file mode 100644 index 0000000..5e629e5 --- /dev/null +++ b/study/kernel/process/management/README.md @@ -0,0 +1,28 @@ +| 日期 | 内核版本 | 架构| 作者 | GitHub| CSDN | +| ------------- |:-------------:|:-------------:|:-------------:|:-------------:|:-------------:| +| 2016-05-12 | [Linux-4.5](http://lxr.free-electrons.com/source/?v=4.5) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux-进程管理与调度](http://blog.csdn.net/gatieme/article/category/6225543) | + +#进程复制Duplication--fork,vfork,clone +------- +Unix标准的复制进程的系统调用时fork(即分叉),但是Linux,BSD等操作系统并不止实现这一个,确切的说linux实现了三个,fork,vfork,clone(确切说vfork创造出来的是轻量级进程,也叫线程,是共享资源的进程) + +| 系统调用 | 描述 | +|:-------------:|:-------------:| +| fork | fork创造的子进程是父进程的完整副本,复制了父亲进程的资源,包括内存的内容task_struct内容 | +| vfork | vfork创建的子进程与父进程共享数据段,而且由vfork()创建的子进程将先于父进程运行 | + + +vfork()用法与fork()相似.但是也有区别,具体区别归结为以下3点 + +1. fork() 子进程拷贝父进程的数据段,代码段. + vfork() 子进程与父进程共享数据段. + +2. fork() 父子进程的执行次序不确定. + vfork():保证子进程先运行,在调用exec或_exit之前与父进程数据是共享的,在它调用exec +或_exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。当需要改变共享数据段中变量的值,则拷贝父进程 + +vfork用于创建一个新进程,而该新进程的目的是exec一个新进程,vfork和fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,不会复制页表。因为子进程会立即调用exec,于是也就不会存放该地址空间。不过在子进程中调用exec或exit之前,他在父进程的空间中运行。 +为什么会有vfork,因为以前的fork当它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,而往往在子进程中会执行exec调用,这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子“霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec或者exit后,相当于儿子买了自己的房子了,这时候就相当于分家了。 +vfork和fork之间的另一个区别是: vfork保证子进程先运行,在她调用exec或exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。由此可见,这个系统调用是用来启动一个新的应用程序。其次,子进程在vfork()返回后直接运行在父进程的栈空间,并使用父进程的内存和数据。这意味着子进程可能破坏父进程的数据结构或栈,造成失败。 +为了避免这些问题,需要确保一旦调用vfork(),子进程就不从当前的栈框架中返回,并且如果子进程改变了父进程的数据结构就不能调用exit函数。子进程还必须避免改变全局数据结构或全局变量中的任何信息,因为这些改变都有可能使父进程不能继续。通常,如果应用程序不是在fork()之后立即调用exec(),就有必要在fork()被替换成vfork()之前做仔细的检查。 +用vfork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序,当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其main函数开始执行,因为调用exec并不创建新进程,所以前后的进程id 并未改变,exec只是用另一个新程序替换了当前进程的正文,数据,堆和栈段。 \ No newline at end of file