【學習&理解】對fork系統調用的理解

来源:https://www.cnblogs.com/aixian/archive/2018/04/04/8717310.html
-Advertisement-
Play Games

這是我在學習Linux0.11內核時做的筆記,以作為以後複習使用。本文解釋為什麼fork()函數會調用一次,返回兩次。以及為什麼返回給父進程的是子進程的pid,而返回給子進程的是0。 大致過程 用戶程式調用fork()函數(標準庫)->中斷處理程式(system_call.s)->sys_fork( ...


這是我在學習Linux0.11內核時做的筆記,以作為以後複習使用。本文解釋為什麼fork()函數會調用一次,返回兩次。以及為什麼返回給父進程的是子進程的pid,而返回給子進程的是0

 

大致過程

用戶程式調用fork()函數(標準庫)->中斷處理程式(system_call.s)->sys_fork()(system_call.s)->find_empty_process()(fork.c)->copy_process()(fork.c)

詳細過程

首先,由用戶程式來調用標準庫提供的API -- fork()函數以進入中斷處理程式(不懂的可以看之前的筆記)。

然後中斷處理程式會根據傳進來的系統調用號參數來得知要執行的系統調用函數,即sys_fork()。在進入中斷處理程式前,就會先壓入ssespeflagscseip寄存器(調用系統調用的必要操作,由硬體完成)。在中斷處理程式中也會先壓入當前進程的一些寄存器,這些寄存器都是在這裡剛好用來當成copy_process()函數的參數(不懂為什麼的可以先看最後的文章後面的解釋)。被中斷處理程式壓入的寄存器有如下:

push ds ;// 保存原段寄存器值。

push es

push fs

push edx ;// ebx,ecx,edx 中放著系統調用相應的C 語言函數的調用參數。

push ecx ;// push %ebx,%ecx,%edx as parameters

push ebx ;// to the system call

然後再進行一些操作之後,就會使用如下語句來調用系統調用:

call [_sys_call_table+eax*4]  ;// eax就是保存著系統調用號

接下來就是進入sys_fork(),這個是由彙編語言編寫於system_call.s文件中。該函數第一步就是尋找能存放新進程信息的進程表空位和空閑PID值,通過如下語句:

call _find_empty_process ;// 調用find_empty_process()(kernel/fork.c,135)

在sys_fork()函數中會壓入當前一些寄存器用來當成copy_process()函數的參數,語句如下:

push gs

push esi

push edi

push ebp

push eax ;// 這裡的eax就是剛剛在find_empty_process()函數中返回的進程表空位的索引(不懂的可以看文章後面的解釋)

接下來就是調用copy_process()函數了,傳入該函數的參數非常多,按照順序來如下:

int nr, long ebp, long edi, long esi, long gs, long none,long ebx, long ecx, long edx,long fs, long es, long ds,long eip, long cs, long eflags, long esp, long ss

函數中,先申請一頁空間來存放進程的信息,而這個空間地址到時候由進程表來索引查找。先設置子進程的狀態為不可中斷等待狀態,以防被錯誤調度。在該空間中填入進程的信息,這些信息基本都是來自之前父進程通過壓棧得來。其中子進程需要在該空間中記下自己的pid、父進程的pid、設置時間片、各種寄存器(幾乎所有都跟父進程的一致,除了內核棧地址esp0、堆棧段選擇符ss0以及eax,該eax設置為0,這就是子進程返回值為0的原因)、分配新的ldt給子進程。由於Linux0.11內核已經有寫時複製機制,所以接下來子進程只複製父進程的頁表項,這樣就可以做到父子進程共用同樣的進程空間了。子進程當然也要對父進程打開的各種文件描述符的打開次數增1。子進程要在GDT 中設置新任務的TSS LDT 描述符項。這時還要對子進程的狀態再做一次設置,設置為就緒狀態,等待調度。函數的最後就是返回子進程的pid。

解釋

·函數的參數是怎麼來的?其實就是取棧中的參數。用戶在調用函數的時候,傳入的參數是被壓入棧中的,而且是從右往左。

如:int func(int a, int b); //b會先被壓入棧,然後再是a。函數在取實參的時候就是從棧頂開始取,即從a開始。

·函數的返回值都是被保存在寄存器eax中的。

如:return a; //寄存器eax就保存著a的值。

 

講到這裡,基本講完了,現在就可以來解決開頭的兩個問題了。

問題

·為什麼fork()函數會調用一次,返回兩次?

首先,我們回憶一下,子進程的寄存器幾乎與父進程的一樣,也就是說其cs、eip也和父進程的一樣。而父進程在進入中斷處理程式的時候壓入了cs、eip,這兩個的組合就是指向fork()函數中從中斷處理程式返回之後的下一條語句。父進程在調用完系統調用返回之後是去執行cs:eip指向的語句,而子進程也是如此。該函數執行到最後是要返回的,所以兩個進程各返回一次。

·為什麼返回給父進程的是子進程的pid,而返回給子進程的是0?

父子進程的返回值不同,就是因為他們的eax存放的值不同。在copy_process()函數最後的return last_pid;是父進程執行的,也就是子進程的pid被保存在了父進程的eax中;而我剛剛前面提到,子進程的eax被設置為0。這就是不同返回值的原因。

 

歡迎各位發現錯誤後指出,本人一定及時改正並致以最誠懇的感謝!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、委托 1. 定義 委托是一個類,它定義了方法的類型,使用委托可以將多個方法綁定到同一個委托變數,當調用此變數時,可以依次調用所有綁定的方法。 2. 測試事例 假如你需要向別人問好,在國際化社會,你可能需要用多種語言問候。 普通的思路可以用 if 或者 swith 判斷然後調用相應的代碼,但是可拓 ...
  • 擁抱.net core的過程中, 將公司的一套java項目改成了.net core 2.0版的. 裡面的tcp服務被我用msdn的SocketAsyncEventArgs方式重寫了, 然而在測試的過程中發現, 偶爾會出現重啟無法再次綁定監聽的情況. 因為缺乏linux上編程的經驗, 對linux的認 ...
  • SqlConnection cn = new SqlConnection("server=my\\my2005;database=rdwhdata2005;user id=zjh;password=321321"); List<string> lis = new List<string>(); vo ...
  • 一、定義 觀察者模式(Observer Pattern)是設計模式中行為模式的一種,它解決了上述具有一對多依賴關係的對象的重用問題。此模式的參與者分為兩大類,一類是被觀察的目標,另一類是觀察該目標的觀察者們。正因為該模式是基於“一對多”的關係,所以該模式一般是應用於由一個目標對象和N個觀察者對象組成 ...
  • 我們都知道 Ubuntu 是一款 Linux 系統,是開源的系統,隨時都在更新,所以人們都說 Linux 系統要比 Windows 系統安全。那麼為了我們的電腦安全,我們如何利用 Ubuntu 命令來進行更新系統呢? 一、運行sudo apt-get update命令 回車之後提示輸入管理員密碼 二 ...
  • |版權聲明:本文為博主原創文章,未經博主允許不得轉載。 AN4069應用筆記中提到MMA8451的三個軸重力校準有兩種方法, 第一種方法是簡易校準,將貼有MMA8451的設備整體,Z軸正面朝上放在校準平面上。此時X軸,Y軸,Z軸的重力加速度理論值分別為0,0,1g。 第二種方法是精確校準,校準MMA ...
  • 以前裝Nginx都是直接百度一下,裝完了事,結果用的時候又有很多不明白的地方,所有今天打算把安裝過程記錄一下。 首先是安裝環境的準備,我的系統環境是Centos 7,用的是虛擬機。因為打算自己編譯安裝,所以先看一下編譯安裝所需要的工具是否都安裝好了。 編譯安裝Nginx需要GCC,PCRE,zlib ...
  • 依賴環境,沒有安裝的需要安裝一下 編寫啟動腳本 腳本內容如下 # !/bin/bash # chkconfig: - 30 21 # description: http service. # Source Function Library ./etc/init.d/functions # Nginx ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...