fork/clone进程的产生

	linux在UBoot执行run_command("bootcmd",0)之后内核启动。然后执行 init/main.c 中的 start_kernel 函数进行一些初始化,如中断RAM 磁盘。start_kernel最后调用rest_init.
/* We need to finalize in a non-__init function or else race conditions
 * between the root thread and the init thread may cause start_kernel to
 * be reaped by free_initmem before the root thread has proceeded to cpu_idle.
 * gcc-3.4 accidentally inlines this function, so use noinline. */
static noinline void __init_refok rest_init(void)__releases(kernel_lock)
{	int pid;
	kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
	numa_default_policy();
	pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
	kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
	unlock_kernel();

	/** The boot idle thread must execute schedule()
	 * at least once to get things moving:	 */
	init_idle_bootup_task(current);
	rcu_scheduler_starting();
	preempt_enable_no_resched();
	schedule();.}//调度器接管理了。
static int __init kernel_init(void * unused){
	.......
	init_post();
}
/* This is a non __init function. Force it to be noinline otherwise gcc
 * makes it inline to init() and it becomes part of init.text section */
static noinline int init_post(void)__releases(kernel_lock)
{
	/* need to finish all async __init code before freeing the memory */
	async_synchronize_full();
	free_initmem();
	unlock_kernel();
	mark_rodata_ro();
	system_state = SYSTEM_RUNNING;
	numa_default_policy();
	if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
		printk(KERN_WARNING "Warning: unable to open an initial console.\n");

	(void) sys_dup(0);
	(void) sys_dup(0);

	current->signal->flags |= SIGNAL_UNKILLABLE;

	if (ramdisk_execute_command) {
		run_init_process(ramdisk_execute_command);
		printk(KERN_WARNING "Failed to execute %s\n",
				ramdisk_execute_command);
	}

	/** We try each of these until one succeeds.
	 * The Bourne shell can be used instead of init if we are
	 * trying to recover a really broken machine.	 */
	.....run_init_process("/sbin/init");
	run_init_process("/etc/init");
	run_init_process("/bin/init");
	run_init_process("/bin/sh");

	panic("No init found.  Try passing init= option to kernel.");
}
从上面代码可以看到:start_kernel->rest_init->kernel_init->init_post->run_init_process
其中run_init_process就是执行文件系统中的一些用户空间进程,从而若要使内核启动后执行我们想要的进程,可以修改init_post这个函数,若修改run_init_process所执行的文件,或添加一些要执行的文件。
当内核启动init进程后(kernel_thread函数执行),在用户空间的进程的产生方式只有fork、vfork、clone等这几个函数来产生,它们是以复制的方式而不是新创建一个。fork()函数经常与exec系列函数一起用,fork之后立即调用exec,执行一个可执行文件, 
fork,vfork它们是通过clone实现的,clone中的一些参数可以细化新进程复制产生的方式,而前两个函数是对这些参数进行了实例化。但在内核中它们都是通过do_fork()实现的。 看P118深入理解Linux内核。
Sys_arm.c (arch\arm\kernel)	
 

用户空间fork()系统调用包含的头文件

#include<unistd.h>/*#包含<unistd.h>*/
#include<sys/types.h>/*#包含<sys/types.h>*/
pid_t fork(void)//pid_t 是一个,其实质是int 被定义在#include<sys/types.h中

返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1
出错返回错误信息如下:
EAGAIN:达到进程数上限.
ENOMEM:没有足够空间给一个新进程分配.
	两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。
	子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本,并继承用户代码、组代码、环境变量、已打开的文件代码、工作目录等。COW技术使得只有其中一个进程修改时才拷贝。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。
	UNIX将复制父进程地址空间内容给子进程,因此,子进程有了独立的地址空间。在不同的UNIX (Like)系统下,我们无法确定fork之后是子进程先运行还是父进程先运行,这依赖于系统的实现。所以在移植代码的时候我们不应该对此作出任何的假设。
	但子进程不会继承文件的锁定和未处理的信号。

——————————————————————————————————————————————————————————

用户空间的CLONE

int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);
<pre name="code" class="objc">extern int clone (int (*__fn) (void *__arg), void *__child_stack,
		  int __flags, void *__arg, ...) __THROW;

/* Unshare the specified resources.  */
extern int unshare (int __flags) __THROW;

 
这里fn是函数指针, arg就是传给子进程的参数,当这个函数返回时,子进程终止。 child_stack明显是为子进程分配系统堆栈空间(在linux下系统堆栈空间是2页面,就是8K的内存,其中在这块内存中,低地址上放入了值,这个值就是进程控制块task_struct的值),flags就是标志用来描述你需要从父进程继承那些资源 

/* Cloning flags.  */
# define CSIGNAL       0x000000ff /* Signal mask to be sent at exit.  */
# define CLONE_VM      0x00000100 /* Set if VM shared between processes.  */地址空间
# define CLONE_FS      0x00000200 /* Set if fs info shared between processes.  */文件系统共享
# define CLONE_FILES   0x00000400 /* Set if open files shared between processes.  */
# define CLONE_SIGHAND 0x00000800 /* Set if signal handlers shared.  */进程间共享信号处理程序 
# define CLONE_PTRACE  0x00002000 /* Set if tracing continues on the child.  */
# define CLONE_VFORK   0x00004000 /* Set if the parent wants the child to  wake it up on mm_release.  */
# define CLONE_PARENT  0x00008000 /* Set if we want to have the same   parent as the cloner.  */
# define CLONE_THREAD  0x00010000 /* Set to add to same thread group.  */
# define CLONE_NEWNS   0x00020000 /* Set to create new namespace.  */
# define CLONE_SYSVSEM 0x00040000 /* Set to shared SVID SEM_UNDO semantics.  */
# define CLONE_SETTLS  0x00080000 /* Set TLS info.  */
# define CLONE_PARENT_SETTID 0x00100000 /* Store TID in userlevel buffer   before MM copy.  */
# define CLONE_CHILD_CLEARTID 0x00200000 /* Register exit futex and memory	    location to clear.  */
# define CLONE_DETACHED 0x00400000 /* Create clone detached.  */
# define CLONE_UNTRACED 0x00800000 /* Set if the tracing process can't   force CLONE_PTRACE on this clone.  */
# define CLONE_CHILD_SETTID 0x01000000 /* Store TID in userlevel buffer in the child.  */
# define CLONE_NEWUTS	0x04000000	/* New utsname group.  */
# define CLONE_NEWIPC	0x08000000	/* New ipcs.  */
# define CLONE_NEWUSER	0x10000000	/* New user namespace.  */
# define CLONE_NEWPID	0x20000000	/* New pid namespace.  */
# define CLONE_NEWNET	0x40000000	/* New network namespace.  */
# define CLONE_IO	0x80000000	/* Clone I/O context.  */
转载的例子。
#include "stdio.h"
#include "sched.h"
#include "signal.h"
#define FIBER_STACK 8192
int a;
void * stack;
int do_something(){
        printf("This is son, the pid is:%d, the a is: %d/n", getpid(), ++a);
        free(stack); //这里我也不清楚,如果这里不释放,不知道子线程死亡后,该内存是否会释放,知情者可以告诉下,谢谢
        exit(1);
}
int main() {
        void * stack;
        a = 1;
        stack = malloc(FIBER_STACK);//为子进程申请系统堆栈
        if(!stack) {
                printf("The stack failed/n");
                exit(0);
        }
        printf("creating son thread!!!/n");
        clone(&do_something, (char *)stack + FIBER_STACK, CLONE_VM|CLONE_VFORK, 0);//创建子线程
         printf("This is father, my pid is: %d, the a is: %d/n", getpid(), a);
         exit(1);
}
[root@liumengli program]# gcc test_clone.c -o test_clone
[root@liumengli program]# ./test_clone
creating son thread!!!
This is son, the pid is:7326, the a is: 2
This is father, my pid is: 7325, the a is: 2




http://blog.csdn.net/caianye/article/details/5947282

http://www.embedu.org/Column/Column472.htm

http://blog.csdn.net/kennyrose/article/details/7532912

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值