博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux源码解析-copy_process函数
阅读量:4212 次
发布时间:2019-05-26

本文共 11364 字,大约阅读时间需要 37 分钟。

1.copy_process函数是做什么的

   copy_process函数在进程创建的do_fork函数中调用,主要完成进程,各种资源的初始化。初始化方式可以重新分配,也可以共享父进程资源,主要根据传入clone_flags参数来确定。

/*

 * This creates a new process as a copy of the old one,
 * but does not actually start it yet.
 *
 * It copies the registers, and all the appropriate
 * parts of the process environment (as per the clone
 * flags). The actual kick-off is left to the caller.
 */
static struct task_struct *copy_process(unsigned long clone_flags,
                    unsigned long stack_start,
                    struct pt_regs *regs,
                    unsigned long stack_size,
                    int __user *child_tidptr,
                    struct pid *pid,
                    int trace)

2.copy_process解析

1.调用 dup_task_struct 复制当前的 task_struct

2.检查进程数是否超过限制

3.初始化自旋锁、挂起信号、CPU 定时器等
4.调用 sched_fork 初始化进程数据结构,并把进程状态设置为 TASK_RUNNING
5.复制所有进程信息,包括文件系统、信号处理函数、信号、内存管理等
6.调用 copy_thread 初始化子进程内核栈
7终止并返回子进程描述符指针

/* * This creates a new process as a copy of the old one, * but does not actually start it yet. * * It copies the registers, and all the appropriate * parts of the process environment (as per the clone * flags). The actual kick-off is left to the caller. */static struct task_struct *copy_process(unsigned long clone_flags,					unsigned long stack_start,					struct pt_regs *regs,					unsigned long stack_size,					int __user *child_tidptr,					struct pid *pid,					int trace){	int retval;	struct task_struct *p;	int cgroup_callbacks_done = 0;     /*下面为参数有效性检查*/  	if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))		return ERR_PTR(-EINVAL);	/*	 * Thread groups must share signals as well, and detached threads	 * can only be started up within the thread group.	 */	if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))		return ERR_PTR(-EINVAL);	/*	 * Shared signal handlers imply shared VM. By way of the above,	 * thread groups also imply shared VM. Blocking this case allows	 * for various simplifications in other code.	 */	if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))		return ERR_PTR(-EINVAL);	/*	 * Siblings of global init remain as zombies on exit since they are	 * not reaped by their parent (swapper). To solve this and to avoid	 * multi-rooted process trees, prevent global and container-inits	 * from creating siblings.	 */	if ((clone_flags & CLONE_PARENT) &&				current->signal->flags & SIGNAL_UNKILLABLE)		return ERR_PTR(-EINVAL);	retval = security_task_create(clone_flags);	if (retval)		goto fork_out;	retval = -ENOMEM;  /*为新进程创建一个内核栈,thread_info结构和task_struct, 这里完全copy父进程的内容,    所以到目前为止父进程和子进程是没有任何区别的。,从这里也可以看出,这个版本的内核在创建时需要为自己分配内核栈*/ p = dup_task_struct(current);	if (!p)		goto fork_out;	ftrace_graph_init_task(p);	rt_mutex_init_task(p);#ifdef CONFIG_PROVE_LOCKING	DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);	DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);#endif	retval = -EAGAIN;/*对进程占用的资源数做出限制,rlim[RLIMIT_NPROC]限制了改进程用户     可以拥有的总进程数量,如果当前用户所拥有的进程数量超过了     规定的最大拥有进程数量,在内核中就直接goto bad_fork_free了。     第2个if使用了capable()函数来对权限做出检查,检查是否有权     对指定的资源进行操作,该函数返回0则代表无权操作。*/      if (atomic_read(&p->real_cred->user->processes) >=    /*fork失败的一个原因:当前用户所拥有的进程数量超过了固定的最大拥有进程数量*/			task_rlimit(p, RLIMIT_NPROC)) {		if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&		    p->real_cred->user != INIT_USER)			goto bad_fork_free;	}	retval = copy_creds(p, clone_flags);	if (retval < 0)		goto bad_fork_free;	/*	 * If multiple threads are within copy_process(), then this check	 * triggers too late. This doesn't hurt, the check is only there	 * to stop root fork bombs.	 */	retval = -EAGAIN;/*检查创建的进程是否超过了系统进程总量*/         if (nr_threads >= max_threads)		goto bad_fork_cleanup_count;	if (!try_module_get(task_thread_info(p)->exec_domain->module))		goto bad_fork_cleanup_count;/*子进程着手使自己与父进程区别开来,从父进程那继承过来的许多属性都要被清0或设置一个初始值,但task_struct中的大多数数据还是未被修改*/	p->did_exec = 0;	delayacct_tsk_init(p);	/* Must remain after dup_task_struct() */	copy_flags(clone_flags, p);	INIT_LIST_HEAD(&p->children);  //初始化孩子链表	INIT_LIST_HEAD(&p->sibling);   //初始化兄弟链表	rcu_copy_process(p);	p->vfork_done = NULL;	spin_lock_init(&p->alloc_lock);	init_sigpending(&p->pending);   //初始化悬而未决信号集,对应于unix环境高级编程中,子进程的未处理信号集设置为空集 /*进程的各种时间设置为0*/       p->utime = cputime_zero;	p->stime = cputime_zero;	p->gtime = cputime_zero;	p->utimescaled = cputime_zero;	p->stimescaled = cputime_zero;#ifndef CONFIG_VIRT_CPU_ACCOUNTING	p->prev_utime = cputime_zero;	p->prev_stime = cputime_zero;#endif#if defined(SPLIT_RSS_COUNTING)	memset(&p->rss_stat, 0, sizeof(p->rss_stat));#endif	p->default_timer_slack_ns = current->timer_slack_ns;	task_io_accounting_init(&p->ioac);	acct_clear_integrals(p);	posix_cpu_timers_init(p);     //timer初始化	p->lock_depth = -1;		/* -1 = no lock */	do_posix_clock_monotonic_gettime(&p->start_time);	p->real_start_time = p->start_time;	monotonic_to_bootbased(&p->real_start_time);	p->io_context = NULL;	p->audit_context = NULL;	cgroup_fork(p);#ifdef CONFIG_NUMA	p->mempolicy = mpol_dup(p->mempolicy); 	if (IS_ERR(p->mempolicy)) { 		retval = PTR_ERR(p->mempolicy); 		p->mempolicy = NULL; 		goto bad_fork_cleanup_cgroup; 	}	mpol_fix_fork_child_flag(p);#endif#ifdef CONFIG_TRACE_IRQFLAGS	p->irq_events = 0;#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW	p->hardirqs_enabled = 1;#else	p->hardirqs_enabled = 0;#endif	p->hardirq_enable_ip = 0;	p->hardirq_enable_event = 0;	p->hardirq_disable_ip = _THIS_IP_;	p->hardirq_disable_event = 0;	p->softirqs_enabled = 1;	p->softirq_enable_ip = _THIS_IP_;	p->softirq_enable_event = 0;	p->softirq_disable_ip = 0;	p->softirq_disable_event = 0;	p->hardirq_context = 0;	p->softirq_context = 0;#endif#ifdef CONFIG_LOCKDEP	p->lockdep_depth = 0; /* no locks held yet */	p->curr_chain_key = 0;	p->lockdep_recursion = 0;#endif#ifdef CONFIG_DEBUG_MUTEXES	p->blocked_on = NULL; /* not blocked yet */#endif#ifdef CONFIG_CGROUP_MEM_RES_CTLR	p->memcg_batch.do_batch = 0;	p->memcg_batch.memcg = NULL;#endif	p->bts = NULL;	/* Perform scheduler related setup. Assign this task to a CPU. */	sched_fork(p, clone_flags);	retval = perf_event_init_task(p);	if (retval)		goto bad_fork_cleanup_policy;	if ((retval = audit_alloc(p)))		goto bad_fork_cleanup_policy;	/* copy all the process information *//*下面的操作中,根据flag中是否设置了相关标志进行重新分配或者共享父进程的内容*/         if ((retval = copy_semundo(clone_flags, p)))		goto bad_fork_cleanup_audit;	if ((retval = copy_files(clone_flags, p)))		goto bad_fork_cleanup_semundo;	if ((retval = copy_fs(clone_flags, p)))		goto bad_fork_cleanup_files;	if ((retval = copy_sighand(clone_flags, p)))		goto bad_fork_cleanup_fs;	if ((retval = copy_signal(clone_flags, p)))		goto bad_fork_cleanup_sighand;	if ((retval = copy_mm(clone_flags, p)))		goto bad_fork_cleanup_signal;	if ((retval = copy_namespaces(clone_flags, p)))		goto bad_fork_cleanup_mm;	if ((retval = copy_io(clone_flags, p)))		goto bad_fork_cleanup_namespaces;        retval = copy_thread(clone_flags, stack_start, stack_size, p, regs);	if (retval)		goto bad_fork_cleanup_io;	if (pid != &init_struct_pid) {		retval = -ENOMEM;		pid = alloc_pid(p->nsproxy->pid_ns);   //为新进程分配pid		if (!pid)			goto bad_fork_cleanup_io;		if (clone_flags & CLONE_NEWPID) {			retval = pid_ns_prepare_proc(p->nsproxy->pid_ns);			if (retval < 0)				goto bad_fork_free_pid;		}	}	p->pid = pid_nr(pid);	p->tgid = p->pid;	if (clone_flags & CLONE_THREAD)		p->tgid = current->tgid;	if (current->nsproxy != p->nsproxy) {		retval = ns_cgroup_clone(p, pid);		if (retval)			goto bad_fork_free_pid;	}	p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;	/*	 * Clear TID on mm_release()?	 */	p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL;#ifdef CONFIG_FUTEX	p->robust_list = NULL;#ifdef CONFIG_COMPAT	p->compat_robust_list = NULL;#endif	INIT_LIST_HEAD(&p->pi_state_list);	p->pi_state_cache = NULL;#endif	/*	 * sigaltstack should be cleared when sharing the same VM	 */	if ((clone_flags & (CLONE_VM|CLONE_VFORK)) == CLONE_VM)		p->sas_ss_sp = p->sas_ss_size = 0;	/*	 * Syscall tracing and stepping should be turned off in the	 * child regardless of CLONE_PTRACE.	 */	user_disable_single_step(p);	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);#ifdef TIF_SYSCALL_EMU	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);#endif	clear_all_latency_tracing(p);	/* ok, now we should be set up.. */	p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL);	p->pdeath_signal = 0;	p->exit_state = 0;	/*	 * Ok, make it visible to the rest of the system.	 * We dont wake it up yet.	 */	p->group_leader = p;	INIT_LIST_HEAD(&p->thread_group);	/* Now that the task is set up, run cgroup callbacks if	 * necessary. We need to run them before the task is visible	 * on the tasklist. */	cgroup_fork_callbacks(p);	cgroup_callbacks_done = 1;	/* Need tasklist lock for parent etc handling! */	write_lock_irq(&tasklist_lock);	/* CLONE_PARENT re-uses the old parent */	if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) {		p->real_parent = current->real_parent;		p->parent_exec_id = current->parent_exec_id;	} else {		p->real_parent = current;		p->parent_exec_id = current->self_exec_id;	}	spin_lock(¤t->sighand->siglock);	/*	 * Process group and session signals need to be delivered to just the	 * parent before the fork or both the parent and the child after the	 * fork. Restart if a signal comes in before we add the new process to	 * it's process group.	 * A fatal signal pending means that current will exit, so the new	 * thread can't slip out of an OOM kill (or normal SIGKILL). 	 */	recalc_sigpending();	if (signal_pending(current)) {		spin_unlock(¤t->sighand->siglock);		write_unlock_irq(&tasklist_lock);		retval = -ERESTARTNOINTR;		goto bad_fork_free_pid;	}	if (clone_flags & CLONE_THREAD) {		atomic_inc(¤t->signal->count);		atomic_inc(¤t->signal->live);		p->group_leader = current->group_leader;		list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);	}	if (likely(p->pid)) {		tracehook_finish_clone(p, clone_flags, trace);		if (thread_group_leader(p)) {			if (clone_flags & CLONE_NEWPID)				p->nsproxy->pid_ns->child_reaper = p;			p->signal->leader_pid = pid;			tty_kref_put(p->signal->tty);			p->signal->tty = tty_kref_get(current->signal->tty);			attach_pid(p, PIDTYPE_PGID, task_pgrp(current));			attach_pid(p, PIDTYPE_SID, task_session(current));			list_add_tail(&p->sibling, &p->real_parent->children);			list_add_tail_rcu(&p->tasks, &init_task.tasks);			__get_cpu_var(process_counts)++;		}		attach_pid(p, PIDTYPE_PID, pid);		nr_threads++;	}	total_forks++;	spin_unlock(¤t->sighand->siglock);	write_unlock_irq(&tasklist_lock);	proc_fork_connector(p);	cgroup_post_fork(p);	perf_event_fork(p);	return p;bad_fork_free_pid:	if (pid != &init_struct_pid)		free_pid(pid);bad_fork_cleanup_io:	if (p->io_context)		exit_io_context(p);bad_fork_cleanup_namespaces:	exit_task_namespaces(p);bad_fork_cleanup_mm:	if (p->mm)		mmput(p->mm);bad_fork_cleanup_signal:	if (!(clone_flags & CLONE_THREAD))		__cleanup_signal(p->signal);bad_fork_cleanup_sighand:	__cleanup_sighand(p->sighand);bad_fork_cleanup_fs:	exit_fs(p); /* blocking */bad_fork_cleanup_files:	exit_files(p); /* blocking */bad_fork_cleanup_semundo:	exit_sem(p);bad_fork_cleanup_audit:	audit_free(p);bad_fork_cleanup_policy:	perf_event_free_task(p);#ifdef CONFIG_NUMA	mpol_put(p->mempolicy);bad_fork_cleanup_cgroup:#endif	cgroup_exit(p, cgroup_callbacks_done);	delayacct_tsk_free(p);	module_put(task_thread_info(p)->exec_domain->module);bad_fork_cleanup_count:	atomic_dec(&p->cred->user->processes);	exit_creds(p);bad_fork_free:	free_task(p);fork_out:	return ERR_PTR(retval);}

转载地址:http://fiumi.baihongyu.com/

你可能感兴趣的文章
java反射详解
查看>>
JPA 注解
查看>>
JQuery 简介
查看>>
Java创建对象的方法
查看>>
Extjs自定义组件
查看>>
TreeGrid 异步加载节点
查看>>
Struts2 标签库讲解
查看>>
Google Web工具包 GWT
查看>>
材料与工程学科相关软件
查看>>
windows 下AdNDP 安装使用
查看>>
Project 2013项目管理教程(1):项目管理概述及预备
查看>>
ssh客户端后台运行
查看>>
【React Native】把现代web科技带给移动开发者(一)
查看>>
【GoLang】Web工作方式
查看>>
Launch Sublime Text 3 from the command line
查看>>
【数据库之mysql】mysql的安装(一)
查看>>
【数据库之mysql】 mysql 入门教程(二)
查看>>
【HTML5/CSS/JS】A list of Font Awesome icons and their CSS content values(一)
查看>>
【HTML5/CSS/JS】<br>与<p>标签区别(二)
查看>>
【HTML5/CSS/JS】开发跨平台应用工具的选择(三)
查看>>