fork属于系统调用,首先从用户态切换到内核态,这个过程前面已经说过了,到了内核态之后就是调用sys_fork(),然后调用do_fork():
asmlinkage int sys_fork(struct pt_regs regs)
{
return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL);
}
这个过程会传递一些信号值和寄存器进去。
do_fork功能概要:
1、为子进程分配pid,
2、调用copy_process()函数进行一系列的copy
3、将子进程加入进程调度队列,等待cpu的调度
copy_process()功能概要:
1、为子进程申请一个PCB(task_struct)
调用dup_task_struct()函数,一般分配8k的物理页面,1k用于保存task_struct(PCB),另外一部分用作子进程的内核堆栈
p = dup_task_struct(current);
if (!p)
goto fork_out;
2、对PCB进行初始化,如自旋锁,定时器
INIT_LIST_HEAD(&p->children);
INIT_LIST_HEAD(&p->sibling);
p->vfork_done = NULL;
spin_lock_init(&p->alloc_lock);
spin_lock_init(&p->proc_lock);
clear_tsk_thread_flag(p, TIF_SIGPENDING);
init_sigpending(&p->pending);
3、将父进程的拷贝内存管理mm_struct,文件描述符files,文件系统fs,信号,信号处理函数
if ((retval = copy_semundo(clone_flags, p)))
goto bad_fork_cleanup_audit;
if ((retval = copy_files(clone_flags, p)))
goto bad_fork_cleanup_semundo;
if ((retval = copy_fs(clone_flags, p)))
goto bad_fork_cleanup_files;
if ((retval = copy_sighand(clone_flags, p)))
goto bad_fork_cleanup_fs;
if ((retval = copy_signal(clone_flags, p)))
goto bad_fork_cleanup_sighand;
if ((retval = copy_mm(clone_flags, p)))
goto bad_fork_cleanup_signal;
if ((retval = copy_keys(clone_flags, p)))
goto bad_fork_cleanup_mm;
if ((retval = copy_namespace(clone_flags, p)))
goto bad_fork_cleanup_keys;
这里还对寄存器的值进行了copy和初始化,把eax的值设为0(所以子进程返回值为0),并设置EIP为ret_from_fork的起始地址(子进程从此处开始执行)
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
if (retval)
goto bad_fork_cleanup_namespace;
4、调用sched_fork()对子进程的静态优先级初始化,并设置子进程为TASK_RINNING状态
sched_fork(p);