fork函数调用全过程

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, &regs, 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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值