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);