怎么在Linux中查看fork函数代码,Linux中fork()调用的源代码在哪里?

以x86平台和2.6.23 Linux内核为参考:

>创建test-fork.c文件:

#include

>使用静态链接编译它:gcc -O0 -static -Wall test-fork.c -o test-fork

>拆卸它:objdump -D -S test-fork>测试fork.dis

>打开test-fork.dis文件并搜索fork:

fork();

80481f4: e8 63 55 00 00 call 804d75c

>然后搜索__libc_fork:

0804d75c

请注意,在此特定硬件/内核上,fork与syscall number 2相关联

>下载Linux内核的副本:wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2

>打开linux-2.6.23 / arch / x86 / kernel / syscall_table_32.S文件

>请注意,系统调用号2与之关联

sys_fork:

.long sys\_fork /* 2 */

>打开linux-2.6.23 / arch / x86 / kernel / process.c文件

>搜索sys_fork:

asmlinkage int sys_fork(struct pt_regs regs)

{

return do_fork(SIGCHLD,regs.esp,&regs,NULL,NULL);

}

请注意,仅使用SIGCHLD参数调用do_fork()

>打开linux-2.6.23 / kernel / fork.c文件.这是do_fork()定义的地方!

> do_fork()然后调用copy_process():

/*

* Ok,this is the main fork-routine.

*

* It copies the process,and if successful kick-starts

* it and waits for it to finish using the VM if required.

*/

long do_fork(unsigned long clone_flags,unsigned long stack_start,struct pt_regs *regs,unsigned long stack_size,int __user *parent_tidptr,int __user *child_tidptr)

{

struct task_struct *p;

int trace = 0;

struct pid *pid = alloc_pid();

long nr;

if (!pid)

return -EAGAIN;

nr = pid->nr;

if (unlikely(current->ptrace)) {

trace = fork_traceflag (clone_flags);

if (trace)

clone_flags |= CLONE_PTRACE;

}

p = copy_process(clone_flags,stack_start,regs,stack_size,\

parent_tidptr,child_tidptr,pid);

/*

* Do this prior waking up the new thread - the thread

* pointer might get invalid after that point,* if the thread exits quickly.

*/

if (!IS_ERR(p)) {

struct completion vfork;

if (clone_flags & CLONE_VFORK) {

p->vfork_done = &vfork;

init_completion(&vfork);

}

if ((p->ptrace & PT_PTRACED) || \

(clone_flags & CLONE_STOPPED)) {

/*

* We'll start up with an immediate SIGSTOP.

*/

sigaddset(&p->pending.signal,SIGSTOP);

set_tsk_thread_flag(p,TIF_SIGPENDING);

}

if (!(clone_flags & CLONE_STOPPED))

wake_up_new_task(p,clone_flags);

else

p->state = TASK_STOPPED;

if (unlikely (trace)) {

current->ptrace_message = nr;

ptrace_notify ((trace << 8) | SIGTRAP);

}

if (clone_flags & CLONE_VFORK) {

freezer_do_not_count();

wait_for_completion(&vfork);

freezer_count();

if (unlikely (current->ptrace & \

PT_TRACE_VFORK_DONE)) {

current->ptrace_message = nr;

ptrace_notify \

((PTRACE_EVENT_VFORK_DONE << 8) | \

SIGTRAP);

}

}

} else {

free_pid(pid);

nr = PTR_ERR(p);

}

return nr;

}

>分叉的大部分工作由do_fork()处理,

在kernel / fork.c中定义. do_fork()执行的操作:

>它通过调用alloc_pid()为子节点分配一个新的PID

>它检查父项的ptrace字段(即current-> ptrace)

>如果它不为零,则父进程将被另一个进程跟踪

>它调用copy_process(),它设置进程描述符和子进程执行所需的任何其他内核数据结构

>其参数与do_fork()加上子项的PID相同

>它检查clone_flags参数中传递的标志是否兼容

>它通过调用security_task_create()和security_task_alloc()执行其他安全检查

>它调用dup_task_struct(),它为新进程创建新的内核堆栈,thread_info和task_struct结构.

>新值与当前任务的值相同

>此时,子进程描述符和父进程描述符完全相同

>它执行alloc_task_struct()宏以获取新进程的task_struct结构,并将其地址存储在tsk局部变量中.

>它执行alloc_thread_info宏以获得一个空闲内存区域来存储新进程的thread_info结构和内核模式堆栈,并将其地址保存在ti局部变量中

>它将当前进程描述符的内容复制到tsk指向的task_struct结构中,然后将tsk-> thread_info设置为ti

>它将当前thread_info描述符的内容复制到ti指向的结构中,然后将ti->任务设置为tsk

>它将新进程描述符的使用计数器(即tsk->用法)设置为2,以指定进程描述符正在使用中,并且相应的进程处于活动状态(其状态不是EXIT_ZOMBIE或EXIT_DEAD)

>它返回新进程的进程描述符指针(即tsk)

> copy_process()然后检查是否未超过当前用户的最大进程数(即大于’max_threads)

>它通过清除或初始化task_struct的各个字段来区分子项与父项

>它调用copy_flags()来更新task_struct的flags字段

> PF_SUPERPRIV(表示任务是否使用超级用户权限)和PF_NOFREEZE标志被清除

>设置PF_FORKNOEXEC标志(表示任务是否未调用`exec())

>它调用`init_sigpending()来清除挂起的信号

>根据传递给do_fork()的参数,copy_process()`然后复制或共享资源

>打开文件

>文件系统信息

>信号处理程序

>地址空间

>它调用sched_fork(),它将父级和子级之间的剩余时间片分开

>最后,它返回一个指向新子节点的指针

>然后,do_fork()在设置了CLONE_STOPPED标志或者必须跟踪子进程的情况下添加一个待处理的SIGSTOP信号(即,在p-> ptrace中设置了PT_PTRACED标志)

>如果未设置CLONE_STOPPED标志,则调用wake_up_new_task()函数,该函数执行以下操作:

>它调整父项和子项的调度参数

>如果子进程与父进程在同一cpu上运行,并且父进程和子进程没有共享同一组页表(即CLONE_VM标志已清除),则会强制子进程在父进程之前运行,方法是将其插入到父进程的运行队列中在父母之前.如果子项刷新其地址空间并在分叉后立即执行新程序,则此简单步骤可以获得更好的性能.如果我们让父进程先运行,则Copy On Write机制会引起一系列不必要的页面重复.

>否则,如果子节点不与父节点在同一cpu上运行,或者父节点和子节点共享同一组页面表(即

CLONE_VM标志设置),它将子项插入父项运行队列的最后位置

>否则,如果设置了CLONE_STOPPED标志,则将子项置于TASK_STOPPED状态

>如果正在跟踪父进程,它将存储子进程的PID

当前的ptrace_message字段并调用

ptrace_notify(),它基本上停止当前进程并向其父进程发送SIGCHLD信号.孩子的“祖父母”是跟踪父母的调试者; SIGCHLD信号通知调试器当前已经分叉了一个子节点,可以通过查看current-> ptrace_message字段来检索其PID.

>如果指定了CLONE_VFORK标志,它会将父进程插入等待队列并暂停它,直到子进程释放其内存地址空间(即,直到子进程终止或执行新程序)

>它通过返回子的PID来终止.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值