--- title: 'Linux 系統 - 模式 & System call' disqus: kyleAlien --- Linux 系統 - 模式 & System call === ## OverView of Content 使用到指令 cc(編譯 c)、strace(System call 追蹤)、sar(系訊訊息)、**ldd(查看分享庫依賴)**、kill ... [TOC] ## 電腦系統概念 電腦是不斷處理以下幾個步驟 1. 透過輸入裝置 or 網路命令,**委託電腦進行處理**,並將這些指令存在 **記憶體中** 2. 要求 CPU 運算記憶體中的委託命令 3. 將 CPU 計算的結果寫入記憶體 4. 將記憶體上的資料寫入硬碟中 or 透過網路傳至別的電腦 > ![](https://i.imgur.com/XsXSDfK.png) ### 程式分類 1. 分類 | 種類 | 說明 | 舉例 | | -------- | -------- | -------- | | 應用程式 | 直接協助使用者 | Office、APP | | 中介軟體 | 多數應用共通處理,可以算是協助開發的 Library | Web 伺服器、資料庫 | | OS 系統 | 直接操作硬體 (韌體的部分) | Linux、Mac、Windows | > ![](https://i.imgur.com/NGB4Mbc.png) 2. 多行程協作 > ![](https://i.imgur.com/L2h5Gj1.png) ### 程式組成 - Process * 程式的運行最小單位為 Process 行程 (也就是進程),^1^ 程式使用的進程可以是複數 or 單數,^2^ **不同進程之間也可以通訊** > ![](https://i.imgur.com/NsIOTG0.png) ### Linux 驅動裝置 - 概述 * 上面有說到 Linux 會透過驅動裝置進行存取,而 Linux 有特定的規定,必須透過 **==核心模式==才能存取裝置** > ![](https://i.imgur.com/0SU2yfE.png) ## 操作系統 os 操作系統簡單來說就是介於硬體 & 應用之間的東西,**向下負責硬體,向上負責提供高效的 API,可說是 ==硬件管家==** > ![](https://i.imgur.com/FkEAGHX.png) ### OS 作用 * 以 Linux 來說,Linux 的特色之一是外部裝置驅動 1. 如果沒有 OS 的話,每個應用就必須針對各個裝置寫必要的驅動程式 > ![](https://i.imgur.com/vjToeES.png) 2. 有 OS 的話,以 Linux 來說就有共用的裝置驅動程式來做處理 (相當於一個共用的 Lib) > ![](https://i.imgur.com/qPUW7rj.png) ### OS 分類 | 分類角度 | Example | | -------- | -------- | | 應用領域 | 嵌入式系統、桌面操作、服務器類型 | | 用戶數量 | 單用戶:Dos; 多用戶:window, mac, unix | | 實時性(多線程) | 實時操作系統:RTOS、VRTX; 分時操作系統:window, mac, unix| | 指令長度 | 8、16、32、64 bit | | 分佈性 | 分佈式、網路式 | | open source | 開源:Android, Unix; 閉源:Mac、Window | | Unix 系列 | Unix-like:Linux, Mac, Xinu; Non-Unix-like:Windows | | POSIX 兼容性 | Linux 兼容 | ### Android 系統 * **Android os 是基於 Linux Kernel 的**,會使用的原因如下: 1. 進程、記憶體管理 2. 權限安全機制 3. 經過驗證的驅動程序模型 4. 提供多種共享厙 5. Open Source~ ### 資料 & 裝置 - 關係 * 簡單來說資料與裝置的關係如下 1. 資料透過讀取硬體 2. 再將資料儲存到記憶體 3. 最後到 CPU 做運算 4. 將結果存到記憶體 5. 最後存到裝置 or 網路上 > ![](https://i.imgur.com/kZDhzKO.png) ### 記憶體速度 & 價格 & 大小 | 記憶體分類 | 速度 | 價格 | 大小 | | -------- | -------- | -------- | -------- | | Register | 最快 | 最貴 | 最小 | | SDR (靜態、快速記憶體) | 中 | 中 | 中 | | DDR (動態記憶體) | 最慢 | 最便宜 | 最大 | * 雖然 DDR 是記憶體中速度最慢的,但仍比硬碟快得多 ~ > ![](https://i.imgur.com/tWl0det.png) ## 核心模式 & 使用者模式 * Linux 透過 **++硬體++ 的協助,讓行程無法對裝置逕行存取**,**CPU 具備 `核心模式` & `使用者模式` 兩種**,除了 `Linux 驅動裝置` 需透過核心存取外,其他還有 `Process 管理系統`、`Process 排程器`、`Memory 管理系統` * **核心模式**:以核心模式來運作、OS 核心處理的稱為核心 (kernel),它主要管理系統 CPU、Memory (核心有核心專用的 CPU、Memory 區塊,這裡先不說明) > ![](https://i.imgur.com/3UF6Iqm.png) ### System Call - 核心模式 * System Call 是一種統稱 (許多行為都可以稱為 System Call),以下舉例幾個 :::success * 當使用到 System call 時就一定會切換到核心模式 ::: 1. 建立、刪除 Process 2. 確保 (申請)、釋放 Memory 3. 不同行程之間的通訊 (mmap) 4. 網路 5. 檔案系統操作 6. 檔案操作 (裝置 IO 存取) ### CPU 中斷 - 模式轉換 * 當使用者有 **使用到 System call 的動作時,便會觸發 CPU 產生 ==中斷事件==,產生中斷事件時 CPU 就換轉換到 ++核心模式++**,並檢查 System call 要求是否正常 > CPU 收動 System call 中斷事件後會先檢查,eg. 檢查記憶體段是否要求正常 (是否超出 or 不合法) > ![](https://i.imgur.com/myxrMif.png) ### 追蹤 System Call - strace 命令 * 前面有說到 IO 存取會呼叫到 system call,以下就寫一個簡單的 c 語言程式進行 IO 存取 1. **前置作業**: 安裝必要套件 ```shell= # 先安裝 gcc 套件 sudo apt-get install -y gcc # 創建文件 touch hello.c # 編輯文件 vim hello.c ``` 2. 使用 puts 終端機上輸出 `Hello world!` ```c= #include <stdio.h> int main(void) { puts("Hello world!"); return 0; } ``` 3. 使用 gcc 編譯 hello.c 檔案 ```shell= # 編譯 & 輸出可執行檔 cc -o hello hello.c ``` 4. 運行編譯結果 ```shell= # 運行 ./hello ``` > ![](https://i.imgur.com/TS4Cgy4.png) * **使用 `strace` 命令** 追蹤 system call 相關資訊 > ![](https://i.imgur.com/Z9L9WAH.png) ```shell= # -o 另外輸出一個檔案 strace -o hello.log ./hello # 查看 system call 數量 wc -l hello.log # -n 輸出行數 cat -n hello.log ``` 重點是第 28 行的 write ~ > ![](https://i.imgur.com/7a2zcr6.png) * 同樣使用 strace 命令,追蹤 Python 程式試試看,可以看到 python 使用到了 400 多行 system call (因為 Python 包裝較多層) ```shell= # echo 輸出,並重新導向,最終輸出 hello.py echo 'print("Hello world, by py")' > hello.py | cat hello.py # 執行 python3 python3 hello.py # 同上 strace -o hello.py.log python3 hello.py # 同上 cat -n hello.py.log ``` 雖然使用到 400 多次 system call,但最終仍都會用到 write ~ > ![](https://i.imgur.com/aY8slRC.png) ### 測試 System call & CPU 模式 - sar 收集系統資訊 * sar 命令是用來收集系統資訊 1. sar 使用格式 ```shell= # -P 是行程 # ALL 是全部 CPU # 1 是一秒一次 # 10 是監看次數 sar -P ALL 10 ``` 2. 使用者、核心模式 看法 | 模式 | 關注欄位 | | -------- | -------- | | 使用者 | `%user` + `%nice` | | 核心 | `%system` | > ![](https://i.imgur.com/kssZbWQ.png) * 以下做兩個 loop 實驗,使用無限迴圈執行 ^1^ 沒有任何動作的執行檔案,^2^ 執行不斷 system call,並觀察 sar 數據 1. 沒有任何動作的執行檔案 (檔案創建、編輯指令都先略過,需要可以參考上面的) ```c= // loop.c int main(void) { for(;;) ; } ``` * 背景執行 + 監聽 CPU,最終會發現 **loop.c 都是 (觀察 user + nice) 運行在使用者模式** ```shell= # 編譯檔案 cc -o loop loop.c # 背景執行 loop (使用 & 就是背景執行,並且它會返回 PID,方便我們 Kill) ./loop & # 監聽 CPU sar -P ALL 1 ``` > ![](https://i.imgur.com/r7YBDFT.png) * **CPU 概念**:單執行 for 迴圈時 (基本上都消耗在 `%user` 欄位) > ![](https://i.imgur.com/LeJWslr.png) 2. 執行不斷 system call,`getppid` 函數 (取的當前行程的 pid) ```c= // ppid_loop.c #include <sys/types.h> #include <unistd.h> int main(void) { for(;;) getppid(); } ``` * 背景執行應用 (`ppid_loop.c`) + 監聽 CPU,最終會發現 **ppid_loop.c 分別有使用者 + 核心模式** ```shell= # 編譯檔案 cc -o ppid_loop ppid_loop.c # 背景執行 loop (使用 & 就是背景執行,並且它會返回 PID,方便我們 Kill) ./ppid_loop & # 監聽 CPU sar -P ALL 1 ``` > ![](https://i.imgur.com/E168v5B.png) * **CPU 概念**:因為有使用 SystemCall 函數,所以 CPU 消耗會分配部分到 `%system` > ![reference link](https://i.imgur.com/FXMj86a.png) :::success * 最後移除背景運行行程 ```shell= # pid 在 & 之後返回 kill <pid> ``` ::: ### System call 耗時 * strace -T 用來採集各種 System call 的耗時,以 **微秒 (µs) 為單位**,以下運行 ./hello 執行檔案,並監測它輸出 write 的耗時 ```shell= strace -T ./hello ``` 可以看到該裝置運行時耗費了 120 µs 來執行 write 的 System call > ![](https://i.imgur.com/bDGdnLG.png) ## System call 包裝函數 Linux 由提供許多 CPU 架構的 library,**System call 無法由 C 語言這種高等語言來呼叫,必須要使用到與 CPU 架構對應的 ==組合語言== 來進行呼叫** ### OS 包裝 System call * 像是 Linux OS 會提供不同 CPU 架構使用的組合語言 (eg. `x86`、`x86_64`、`arm7`... 等等),如果沒有 OS 的話每個行程就要撰寫對應的 CPU 組語 ```java= // 以 x86_64 為例的組語範例 mov $0x6e,%eax // 將 0x6ax 寫入 eax 暫存器 syscall // 對 cpu 發出 system call,cpu 收到後產生中斷,並進入 ++核心模式++ ``` > ![](https://i.imgur.com/t9Ffiw6.png) ### 標準 C Library - glibc * C 語言有依照 ISO 訂製的標準函數 Library,Linux 也有提供 C 的標準,通常依照 GUN 專案所以提供的 **glibc** 作為標準 C 函數 Library,幾乎所以有的 C 語言程式都會連接到 glibc * 該程式與何種 library 相連可以使用 `ldd` 命令查看 :::info * ldd : print shared object dependencies ldd 後面是添加 **執行檔** 的絕對路徑 ::: * 以下幾個範例都連接到 `libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6` 也就是 glic 1. 查看 echo ```shell= # 查看 echo 命令位置 which echo # ldd 後面要添加絕對路徑 ldd /usr/bin/echo ``` > ![](https://i.imgur.com/ZRhZGOj.png) 2. 查看自己寫的 hello 執行檔 ```shell= # ldd 後面要添加絕對路徑 ldd hello ``` > ![](https://i.imgur.com/0ixFBFh.png) 3. 查看 python3 ```shell= # 查看 python3 命令位置 which python3 # ldd 後面要添加絕對路徑 ldd /usr/bin/python3 ``` > ![](https://i.imgur.com/SR5v6o5.png) ### OS 提供程式 * 以下提幾個常見到的程式 | OS 程式 | 關鍵字 | | -------- | -------- | | 系統初始化 | init | | 變更 OS 行動 | sysctl、nice、sync | | 檔案操作 | touch、mkdir | | 文字加工 | grep、sort、uniq | | 效能測量 | sar、iostat | | 編譯器 | gcc | | 腳本語言執行環境 | perl、python、ruby | | shell | bash | | 視窗系統 | X | ## Appendix & FAQ :::info ::: ###### tags: `Linux 系統核心`