1.概述
在应用层调用fork()函数,内核调用函数关系,以及作用?
函数调用关系如下图:
sys_fork()-->do_fork()--->copy_process()--->wake_up_new_task()
2. sys_fork函数
sys_fork函数调用do_fork并传入SIGCHLD参数。
631 asmlinkage int sys_fork(struct pt_regs regs)
632 {
633 return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL);
634 }
3. do_fork函数
1124 long do_fork(unsigned long clone_flags,
1125 unsigned long stack_start,
1126 struct pt_regs *regs,
1127 unsigned long stack_size,
1128 int __user *parent_tidptr,
1129 int __user *child_tidptr)
1130 {
1131 struct task_struct *p;
1132 int trace = 0;
1133 long pid = alloc_pidmap();
1134
1135 if (pid < 0)
1136 return -EAGAIN;
1137 if (unlikely(current->ptrace)) {
1138 trace = fork_traceflag (clone_flags);
1139 if (trace)
1140 clone_flags |= CLONE_PTRACE;
1141 }
1142
1143 p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);
1144 /*
1145 * Do this prior waking up the new thread - the thread pointer
1146 * might get invalid after that point, if the thread exits quickly.
1147 */
1148 if (!IS_ERR(p)) {
1149 struct completion vfork;
1150
1151 if (clone_flags & CLONE_VFORK) {
1152 p->vfork_done = &vfork;
1153 init_completion(&vfork);
1154 }
1155
1156 if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) {
1157 /*
1158 * We'll start up with an immediate SIGSTOP.
1159 */
1160 sigaddset(&p->pending.signal, SIGSTOP);
1161 set_tsk_thread_flag(p, TIF_SIGPENDING);
1162 }
1163
1164 if (!(clone_flags & CLONE_STOPPED))
1165 wake_up_new_task(p, clone_flags);
1166 else
1167 p->state = TASK_STOPPED;
1168
1169 if (unlikely (trace)) {
1170 current->ptrace_message = pid;
1171 ptrace_notify ((trace << 8) | SIGTRAP);
1172 }
1173
1174 if (clone_flags & CLONE_VFORK) {
1175 wait_for_completion(&vfork);
1176 if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
1177 ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
1178 }
1179 } else {
1180 free_pidmap(pid);
1181 pid = PTR_ERR(p);
1182 }
1183 return pid;
1184 }
执行fork()函数后,do_fork()主要执行下面步骤:
1)在1133行,通过alloc_pidmap()获得一个进程号。
2)再1143行,copy_process()给新进程分配struct task和thread info的变量。
2)在1165行,通过wake_up_new_task唤醒这个进程。
3)在1183行,返回进程pid号。
4. copy_process
1111
task_rq_lock
功能: 通过struct task结构变量p,找到对应得cpu,然后得到这个cpu上的percpu变量runqueues(进程运行队列)。
305 static runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
306 __acquires(rq->lock)
307 {
308 struct runqueue *rq;
309
310 repeat_lock_task:
311 local_irq_save(*flags);
312 rq = task_rq(p);
313 spin_lock(&rq->lock);
314 if (unlikely(rq != task_rq(p))) {
315 spin_unlock_irqrestore(&rq->lock, *flags);
316 goto repeat_lock_task;
317 }
318 return rq;
319 }
宏task_rq的定义如下:
task_rq(p)
286 #define cpu_rq(cpu) (&per_cpu(runqueues, (cpu)))
287 #define this_rq() (&__get_cpu_var(runqueues))
288 #define task_rq(p) cpu_rq(task_cpu(p))
1146 static inline unsigned int task_cpu(const struct task_struct *p)
1147 {
1148 return p->thread_info->cpu;
1149 }
展开就是:
1) task_rq(p)=====>cpu_rq(task_cpu(p))
2) cpu_rq(task_cpu(p))==========>cpu_rq(p->thread_info->cpu)
3) cpu_rq(p->thread_info->cpu)=====>&per_cpu(runqueues,p->thread_info->cpu)
per_cpu(arg1,arg2)=====>就是访问arg2编号的cpu上的arg1变量。
task_rq(p)==>就是访问p对应的cpu上的runqueues(类型为percpu)