博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
fork函数调用全过程
阅读量:2384 次
发布时间:2019-05-10

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

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)

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

你可能感兴趣的文章
打开word2010每次都要配置进度的解决办法
查看>>
略论并行处理系统的日志设计
查看>>
开发人员应具备的产品设计意识
查看>>
MSComDlg.CommonDialog服务器不能创建对象错误的解决
查看>>
ArcGIS二次开发之读取遥感图像像素值的做法
查看>>
netcdf源码在windows上的编译
查看>>
慎用VC 6.0
查看>>
游戏杆编程心得
查看>>
周例会的作用
查看>>
字符集研究之多字节字符集和unicode字符集
查看>>
字符集研究之不同字符集的转换方式
查看>>
一个应用程序无法启动错误的解决过程
查看>>
除虫记——有关WindowsAPI文件查找函数的一次压力测试
查看>>
Incredibuild导入key的方式
查看>>
跨平台C++开源代码的两种常用编译方式
查看>>
Eclipse的搜索技巧
查看>>
centos常用命令二
查看>>
通过修改kong属性解决不能获取外网域名的问题
查看>>
Eclipse带命令行参数调试
查看>>
php smtp发送邮件
查看>>