進程的描述和進程的建立node
1、進程的描述linux
一、進程描述符task_struct數據結構(一)編程
操做系統的三大功能:進程管理(核心)、內存管理、文件系統。數據結構
進程控制塊PCB——task_struct(進程描述符):爲了管理進程,內核必須對每一個進程進行清晰的描述,進程描述符提供了內核所需瞭解的進程信息。dom
操做系統原理中有三個狀態:就緒狀態、運行狀態。阻塞狀態。函數
調用fork建立一個新進程的時候實際上的狀態是TASK_RUNNING(就緒但沒有在運行),當調度器選擇一個task時仍是切換到TASK_RUNNING,(爲何呢?當進程是TASK_RUNNING狀態時是可運行的,可是否運行仍是看是否得到CPU的控制權(有沒有在CPU上實際的執行))進程調用do_exit()停止執行,進入TASK_ZOMBIE(殭屍進程)this
一個正在運行的進程在等待特定的事件或者是資源的時候會進入阻塞態,當阻塞的條件沒有了的時候,就進入就緒態。atom
pid及tpid用來標識進程的spa
二、進程描述符task_struct數據結構(二)操作系統
閱讀理解task_struct數據結構
struct task_struct {
1236 volatile long state; /*state是運行狀態*/
1237 void *stack;/*指定了進程的內核堆棧 */
1238atomic_tusage;
1239 unsigned int flags; /* 標識符*/
1240 unsigned int ptrace;
1241
1242#ifdef CONFIG_SMP/*條件編譯多處理器用到*/
1243 struct llist_nodewake_entry;
1244 int on_cpu;
1245 struct task_struct *last_wakee;
1246 unsigned long wakee_flips;
1247 unsigned long wakee_flip_decay_ts;
1248
1249 int wake_cpu;
1250#endif
1251 int on_rq;/*運行隊列和進程調度相關程序*/
1252
1253 int prio, static_prio, normal_prio;
1254 unsigned int rt_priority;
1255 const struct sched_class *sched_class;
1256 struct sched_entityse;
1257 struct sched_rt_entityrt;
1258#ifdef CONFIG_CGROUP_SCHED
1259 struct task_group *sched_task_group;
1260#endif
1295 struct list_head tasks;/*進程鏈表*/
/*雙向鏈表*/
1296#ifdef CONFIG_SMP
1297 struct plist_nodepushable_tasks;
1298 struct rb_nodepushable_dl_tasks;
1299#endif
1300
1301 struct mm_struct *mm, *active_mm;/*進程管理進程的地址空間相關*/ 每一個進程有獨立的進程地址空間4G,32位x86。
1302#ifdef CONFIG_COMPAT_BRK
1303 unsigned brk_randomized:1;
1304#endif
1305 /* per-thread vma caching */
1306 u32 vmacache_seqnum;
1307 struct vm_area_struct *vmacache[VMACACHE_SIZE];
1308#if defined(SPLIT_RSS_COUNTING)
1309 struct task_rss_statrss_stat;
1310#endif
1330 pid_t pid;/*標識*/
1331pid_ttgid;
1337 /*
1338 * pointers to (original) parent process, youngest child, younger sibling,/*進程的父子關係*/
1339 * older sibling, respectively. (p->father can be replaced with
1340 * p->real_parent->pid)
1341 */
1342 struct task_struct __rcu *real_parent; /* real parent process */
1343 struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
1344 /*
1345 * children/sibling forms the list of my natural children
1346 */
1347 struct list_head children; /* list of my children */
1348 struct list_head sibling; /* linkage in my parent's children list */
1349 struct task_struct *group_leader; /* threadgroup leader */
1411/*當前任務和CPU相關的狀態,在進程上下文切換的過程當中起着重要的做用 */
1412 struct thread_struct thread;
1413/* filesystem information */
1414 struct fs_struct *fs;/*文件系統相關的數據結構*/
1415/* open file information */
1416 struct files_struct *files;/*打開的文件描述符列表*/
1417/* namespaces */
1418 struct nsproxy *nsproxy;
1419/* signal handlers *//*與信號處理相關的工做*/
2、進程的建立
一、進程的建立概覽及fork一個進程的用戶態代碼
進程描述符是整個系統管理中挈領性的東西。
瞭解進程是如何建立的?進程之間如何調度切換的?
一號進程的建立:複製了0號進程的pcb,而後根據1號進程的須要修改,再加載一個init執行程序 。
fork一個子進程的代碼
fork系統調用在子進程和父進程各返回一次。子進程中pid的返回值是:0。父進程中pid的返回值是:子進程的ID。
fork以後兩個進程。
二、理解進程建立過程複雜代碼的方法
在進程調度的過程當中,調度到一個未調度的新進程,執行的起點是咱們設定的my process的ip。
建立一個新進程就是複製當前進程的信息來實現的。
一個父進程建立一個子進程,有一個地方複製子進程的pcb,修改複製出來的pcb.
要給新進程分配一個新的內核堆棧.
回顧:系統調用的進程建立過程
Linux中建立進程一共有三個函數:
這裏值得注意的是,Linux中得線程是經過模擬進程實現的,較新的內核使用的線程庫通常都是NPTL。
三、瀏覽進程建立過程相關的關鍵代碼
四、建立的新進程是從哪裏開始執行的
fork,vfork,clone均可以建立新進程,他們都是經過調用do_fork來實現的。
ip指向ret_from_fork
fork()系統調用產生的子進程在系統調用處理過程當中從ret_from_fork開始執行。
只複製了部份內核堆棧
五、使用gdb跟蹤建立新進程的過程
爲了減小對以後實驗的影響,刪除test_fork.c以及test.c,編譯內核:
gdb調試,設斷點:
執行fork,發現fork函數停在了父進程中。
特別關注新進程是從哪裏開始執行的?爲何從哪裏能順利執行下去?即執行起點與內核堆棧如何保證一致。
3、總結
fork()函數建立新進程是經過下列一系列函數實現的:fork() -> sys_clone() -> do_fork() -> dup_task_struct() -> copy_process() -> copy_thread() -> ret_from_fork()。操做系統的三大功能:進程管理(核心)、內存管理、文件系統。進程控制塊PCB——task_struct(進程描述符):爲了管理進程,內核必須對每一個進程進行清晰的描述,進程描述符提供了內核所需瞭解的進程信息。Linux經過複製父進程來建立一個新進程,fork系統調用在子進程和父進程各返回一次。子進程中pid的返回值是:0。父進程中pid的返回值是:子進程的ID。