本文主要针对在linux 2.6.11.12内核源码中,fork系统调用的实现过程。
假设我们的程序源文件名为main.c,内容是:
Void main()
{
Pid_t pid = fork();
If(pid == 0)
{
Printf(“child\n”);
}
else
{
printf(“father\n”);
}
}
在用户代码执行到fork时,将系统调用号写入eax寄存器,然后调用系统中断0x80, 操作系统开始运行,进入内核态。先从eax中将系统调用号读出来,再根据系统调用号在系统调用表中找到相应的处理函数sys_fork。操纵系统开始执行sys_fork()函数。执行完成后再将返回值写入eax中,返回用户态的应用程序。应用程序从eax中读出返回值,再继续执行程序。下面给出部分重要源码,有点枯燥,但很重要!!!
#define_syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile("int $0x80" \ //调用系统中断0x80
: "=a" (__res) \ //_res用来承载中断返回值
: "0" (__NR_##name)); \ //输入系统中断调用号_NR_fork(2)
__syscall_return(type,__res);\
}
其中的系统调用中断号在include/asm-i386/unistd.h文件中定义,fork的中断号为2:
//在此只列出了常见的几个系统调用号
#ifndef_ASM_I386_UNISTD_H_
#define_ASM_I386_UNISTD_H_
/*
* This file contains the system call numbers.
*/
#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
#define __NR_creat 8
#define __NR_link 9
#define __NR_unlink 10
……
在inux/arch/i386/entry.S文件中可以查看系统调用表
ENTRY(sys_call_table)
.long sys_restart_syscall /* 0 - old "setup()" system call,used for restarting */
.long sys_exit
.long sys_fork
.long sys_read
.long sys_write
.long sys_open /* 5 */
.long sys_close
.long sys_waitpid
.long sys_creat
.long sys_link
.long sys_unlink /* 10 */
......asmlinkage int sys_fork(struct pt_regs regs)
{
return do_fork(SIGCHLD, regs.esp, ®s,0, NULL, NULL);
}
可见sys_fork底层实现调用do_fork.