本文共 8033 字,大约阅读时间需要 26 分钟。
在应用层调用fork()函数,内核调用函数关系,以及作用?
函数调用关系如下图:sys_fork()-->do_fork()--->copy_process()--->wake_up_new_task()
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 }
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号。1111
功能: 通过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)
转载地址:http://zofab.baihongyu.com/