潘恆 原創做品轉載請註明出處《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000node
task_struct結構:linux
struct task_struct {
volatile long state;進程狀態
void *stack; 堆棧
pid_t pid; 進程標識符
unsigned int rt_priority;實時優先級
unsigned int policy;調度策略
struct files_struct *files;系統打開文件
...
}
內核處理函數sys_clone:
系統調用經過do_fork實現進程的建立:
return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
linux系統是經過複製父進程的信息來建立子進程,在do_fork函數中,真正實現複製的是copy_process函數:
p = copy_process(clone_flags, stack_start, stack_size,child_tidptr, NULL, trace);
p = dup_task_struct(current);建立內核棧
retval = security_task_create(clone_flags);
retval = sched_fork(clone_flags, p);和調度相關的設置,cpu將調度這個task
retval = copy_thread(clone_flags, stack_start, stack_size, p); 複製父進程堆棧的內容到子進程的堆棧中去.這其中,copy_thread函數中的語句p->thread.ip = (unsigned long) ret_from_fork決定了新進程的第一條指令地址.
建立棧函數dup_task_struct:
tsk = alloc_task_struct_node(node);開闢內存空間
ti = alloc_thread_info_node(tsk, node);ti指向thread_info的首地址,同時也是系統爲新進程分配的兩個連續頁面的首地址。
err = arch_dup_task_struct(tsk, orig);複製父進程的task_struct信息到新的task_struct裏
tsk->stack = ti;task對應棧
setup_thread_stack(tsk, orig);初始化thread info結構
set_task_stack_end_magic(tsk);棧結束的地址設置數據爲棧結束標示
新進程從哪裏開始執行:
在以前的分析中,談到copy_process中的copy_thread()函數,正是這個函數決定了子進程從系統調用中返回後的執行.ret_from_fork決定了新進程的第一條指令地址。p->thread.ip = (unsigned long) ret_from_fork;將子進程的ip設置爲ret_from_fork的首地址,子進程從ret_from_fork開始執行
實驗:分析Linux內核建立一個新進程的過程c#
1.Linux經過複製父進程來建立一個新進程,經過調用do_fork來實現。函數
2.Linux爲每一個新建立的進程動態地分配一個task_struct結構。線程
3.爲了把內核中的全部進程組織起來,Linux提供了幾種組織方式,其中哈希表和雙向循環鏈表方式是針對系統中的全部進程(包括內核線程),而運行隊列和等待隊列是把處於同一狀態的進程組織起來。code
4.fork()函數被調用一次,但返回兩次。blog