在分配了栈后,调用setup_thread_stack确定栈内的布局。这个函数完成的操作是:把父进程的thread_info(进程描述结构)值复制给tsk的进程描述结构。然后将tsk的进程描述符中的task域改为tsk. [cpp] #define task_thread_info(task) ((struct thread_info *)(task)->stack) static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org) { *task_thread_info(p) = *task_thread_info(org); task_thread_info(p)->task = p; } 在执行完setup_thread_stack之后,父子进程除了stack的指针之外是完全一样的。 三,检查进程数创建限制 [cpp] rt_mutex_init_task(p);//互斥锁初始化 #ifdef CONFIG_TRACE_IRQFLAGS DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); #endif retval = -EAGAIN; if (atomic_read(&p->user->processes) >= p->signal->rlim[RLIMIT_NPROC].rlim_cur) { if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && p->user != current->nsproxy->user_ns->root_user) goto bad_fork_free; } <span> </span>atomic_inc(&p->user->__count); <span> </span>atomic_inc(&p->user->processes); <span> </span>get_group_info(p->group_info);增加组的使用计数 进程结构task_struct中有一个域,名为:user_struct,这个域保存了当前用户的使用资源计数。 [cpp] struct task_struct{ …… struct user_struct *user; …… }; 在user_struct结构中包含processes表示当前的用户能够创建最多的进程数。如果超过限制,就放弃创建进程。root用户除外。如果没有超过限制,就将user_struct结构的引用计数加1,并将已经创建的进程数加1. 四,线程检查 检查线程创建是否超过最大限制,这个比较简单 [cpp] /* * 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. */ if (nr_threads >= max_threads) goto bad_fork_cleanup_count; 五,写入数据 在这里,进程描述符task_struct已经建立好了,其和父进程是一样的,除了栈地址不一样之外,现在开始修改一些值。 [cpp] if (!try_module_get(task_thread_info(p)->exec_domain->module)) goto bad_fork_cleanup_count; if (p->binfmt && !try_module_get(p->binfmt->module)) goto bad_fork_cleanup_put_domain; p->did_exec = 0;当前还有加载任何执行的系统调用,所以为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); p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); clear_tsk_thread_flag(p, TIF_SIGPENDING); init_sigpending(&p->pending); p->utime = cputime_zero; p->stime = cputime_zero; p->gtime = cputime_zero; p->utimescaled = cputime_zero; p->stimescaled = cputime_zero; p->prev_utime = cputime_zero; p->prev_stime = cputime_zero; #ifdef CONFIG_TASK_XACCT p->rchar = 0; /* I/O counter: bytes read */ p->wchar = 0; /* I/O counter: bytes written */ p->syscr = 0; /* I/O counter: read syscalls */ p->syscw = 0; /* I/O counter: write syscalls */ #endif task_io_accounting_init(p); acct_clear_integrals(p); p->it_virt_expires = cputime_zero; p->it_prof_expires = cputime_zero; p->it_sched_expires = 0; INIT_LIST_HEAD(&p->cpu_timers[0]); INIT_LIST_HEAD(&p->cpu_timers ); INIT_LIST_HEAD(&p->cpu_timers ); 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); #ifdef CONFIG_SECURITY p->security = NULL; #endif p->io_context = NULL; p->audit_context = NULL; cgroup_fork(p); #ifdef CONFIG_NUMA p->mempolicy = mpol_copy(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 这里是对一些值进行初始化,和各种策略相关的值,如调度等等,有些值是很重要的。 六,加入调度 [cpp] /* Perform scheduler related setup. Assign this task to a CPU. */ sched_fork(p, clone_flags); 这可以使用是进程可以参加调度,但此时进程的状态改为正在TASK_RUNNING,这以防止内核的其他部分将其改为可运行状态,因为我们对进程的设置还没有完成,这样调度进程会有问题。 |