3.8. 程序與 Daemon
前一頁 | 章 3. FreeBSD 基礎 | 下一頁

## 3.8. 程序與 Daemon

FreeBSD 是一個多工的作業系統，也就是說在同一時間內可以跑超過一個程式。 每一個正在花時間跑的程式就叫做程序 (Process)。 您下的每個指令都至少會開啟一個新的程序， 而有些系統程序是一直在跑以維持系統正常運作的。

每一個程序都有一個獨一無二的數字叫做 程序代號 (Process ID, PID)，而且就像檔案一樣，每一個程序也有擁有者及群組。 擁有者及群組的資訊是用來決定什麼檔案或裝置是這個程序可以開啟的 (前面有提到過檔案權限)。 大部份的程序都有父程序。 父程序是開啟這個程序的程序，例如：您對 Shell 輸入指令，Shell 本身就是一個程序，而您執行的指令也是程序。 每一個您用這種方式跑的程序的父程序都是 Shell。 有一個特別的程序叫做 init(8) 是個例外，在 FreeBSD 開機的時候 init 會自動地被開啟，init 永遠是第一個程序，所以他的 PID 一直都會是 `1`。

有些程式並不是設計成一直在接收使用者的輸入的， 而是在開始執行的時候就從中斷與終端機的連線。 例如說， 網頁伺服器整天都在回應網頁方面的要求，它通常不需要您輸入任何東西。 另外，像是把信從一個站傳送到另一個站的程式，也是這種類型的應用程式。我們把這種程式稱作 Daemon。 Daemon 一詞是來自是希臘神話中的角色：祂們既不屬於善良陣營或邪惡陣營，祂們在背地裡做一些有用的事情。這也就是為何 BSD 的吉祥物，是一隻穿著帆布鞋拿著三叉耙的快樂小惡魔的原因。

通常來說做為 Deamon 執行的程式名字後面都會加一個字母 “d”。 BIND 是 Berkeley Internet Name Domain 的縮寫，但實際上執行的程式名稱是 `named`、Apache 網頁伺服器的程式名稱是 `httpd`、行列式印表機緩衝服務 (Line Printer Spooling) Daemon 是 `lpd`，依此類推。 但這是習慣用法，並沒有硬性規定，例如 Sendmail 主要的寄信 Daemon 是叫做 `sendmail` 而不是 `maild`。

### 3.8.1. 檢視程序

要看系統執行中的程序，有兩個相當有用的指令可用： ps(1) 以及 top(1)。ps(1) 指令是用來列出正在執行之程序，而且可以顯示它們的 PID、用了多少記憶體、執行的指令名稱及其後之參數是什麼等等。 top(1) 指令則是顯示所有正在執行的程序， 並且數秒鐘更新一次。因此您可以互動式的觀看您的電腦正在做什麼。

在預設的情況下，ps(1) 指令只會顯示使用者所擁有的的程序。 例如：

    % ps
     PID TT  STAT    TIME COMMAND
    8203  0  Ss   0:00.59 /bin/csh
    8895  0  R+   0:00.00 ps

在這個範例裡可以看到 ps(1) 的輸出分成好幾個欄位。 `PID` 就是前面有提到的程序代號。 `PID` 的分配是從 1 開始一直到 99999，如果用完的話又會繞回來重頭開始分配 (若該 PID 已經在用了，則 PID 不會重新分配)。 `TT` 欄位是指這個程式在哪個 Console (tty) 上執行，在這裡可以先忽略不管。`STAT` 是程式的狀態，也可以先不要管。`TIME` 是這個程式在 CPU 上執行的時間—這通常不是程式總共花的時間， 因為當您開始執行程式後，大部份的程式在 CPU 上執行前會先花上不少時間等待 。 最後，`COMMAND` 是執行這個程式的指令。

有幾個不同的選項組合可以用來變更顯示出來的資訊，其中一個最有用的組合是 `auxww`。 `a` 可以顯示所有正在跑的程序的指令，不只是您自已的。 `u` 則是顯示程序的擁有者名稱以及記憶體使用情況。 `x` 可以把 daemon 程序顯示出來， 而 `ww` 可讓 ps(1) 顯示出每個程序完整的內容， 而不致因過長而被螢幕截掉了。

top(1) 也有類似的輸出。 一般的情況看像是這樣：

    % top
    last pid:  9609;  load averages:  0.56,  0.45,  0.36              up 0+00:20:03  10:21:46
    107 processes: 2 running, 104 sleeping, 1 zombie
    CPU:  6.2% user,  0.1% nice,  8.2% system,  0.4% interrupt, 85.1% idle
    Mem: 541M Active, 450M Inact, 1333M Wired, 4064K Cache, 1498M Free
    ARC: 992M Total, 377M MFU, 589M MRU, 250K Anon, 5280K Header, 21M Other
    Swap: 2048M Total, 2048M Free

      PID USERNAME    THR PRI NICE   SIZE    RES STATE   C   TIME   WCPU COMMAND
      557 root          1 -21  r31   136M 42296K select  0   2:20  9.96% Xorg
     8198 dru           2  52    0   449M 82736K select  3   0:08  5.96% kdeinit4
     8311 dru          27  30    0  1150M   187M uwait   1   1:37  0.98% firefox
      431 root          1  20    0 14268K  1728K select  0   0:06  0.98% moused
     9551 dru           1  21    0 16600K  2660K CPU3    3   0:01  0.98% top
     2357 dru           4  37    0   718M   141M select  0   0:21  0.00% kdeinit4
     8705 dru           4  35    0   480M    98M select  2   0:20  0.00% kdeinit4
     8076 dru           6  20    0   552M   113M uwait   0   0:12  0.00% soffice.bin
     2623 root          1  30   10 12088K  1636K select  3   0:09  0.00% powerd
     2338 dru           1  20    0   440M 84532K select  1   0:06  0.00% kwin
     1427 dru           5  22    0   605M 86412K select  1   0:05  0.00% kdeinit4

輸出的資訊分成兩個部份。開頭 (前五行或六行) 顯示出最近一個程序的 PID、系統平均負載 (系統忙磁程度評估方式)、系統的開機時間 (自上次重新開機) 以及現在的時間等。 在開頭裡面的其他數字分別是在講有多少程序正在執行、有多少記憶體及交換空間被占用了，還有就是系統分別花了多少時間在不同的 CPU 狀態上。若有載入 ZFS 檔案系統模組，會有一行 `ARC` 標示有多少資料從磁碟改由記憶體快取中取得。

接下來的部份是由好幾個欄位所構成，和 ps(1) 輸出的資訊類似。 就如同前例，您可以看到 PID、使用者名稱、CPU 花費的時間以及正在執行的指令。 top(1) 在預設的情況下還會告訴您程序用掉了多少的記憶體空間。 在這邊會分成兩欄，一個是總用量 (Total size)，另一個是實際用量 (Resident size)——總用量是指這個應用程式需要的記憶體空間，而實際用量則是指目前實際上該程式的記憶體使用量。

top(1) 每隔 2 秒鐘會自動更新顯示內容，可用 `-s` 選項來改變間隔的時間。

### 3.8.2. 終止程序

要與執行中的程序或 Daemon 溝通唯一的方法是透過 kill(1) 指令傳送信號 (Signal)。 信號有很多種，有些有特定的意義，有些則是會由應用程式來解讀，應用程式的說明文件會告訴您該程式是如何解讀信號。 使用者只能送信號給自己所擁有的程序，送信號給其他人的程序會出現權限不足的錯誤。 唯一的例外是 `root`使用者，他可以送信號給任何人的程序。

作業系統在某些情況也會送信號給應用程式。 假設有個應用程式寫得不好，企圖要存取它不該碰的記憶體的時候，FreeBSD 會送一個 “Segmentation Violation” 信號 (`SIGSEGV`) 給這個程序。 如果有一個應用程式用了 alarm(3) 的系統呼叫 (System call) 要求系統在過一段時間之後發出通知，時間到了的時候系統就會發出“通知”信號 (`SIGALRM`) 給該程式。

`SIGTERM` 與 `SIGKILL` 這兩個信號可以拿來終止程序。 用 `SIGTERM` 結束程序是比較有禮貌的方式，該程序收到信號後可以把自已所使用的日誌檔關閉及其他要在結束前要做的事完成， 然後在關掉程序之前結束掉手邊的工作。 在某些情況下程序有可能會忽略 `SIGTERM`，如它正在做一些不能中斷的工作的話。

`SIGKILL` 就沒有辦法被程序忽略。 傳送 `SIGKILL` 信號給程序通常會將程序直接中止[1]。

其他常用的信號有：`SIGHUP`, `SIGUSR1` 及 `SIGUSR2`。 這些是通用的信號，對不同的應用程式會有不同的反應。

舉例來說，當您更動了網頁伺服器的設定檔，您想要叫網頁伺服器去重新讀取設定。 重新啟動 `httpd` 會造成網頁伺服器暫停服務一段時間，我們可以傳送 `SIGHUP` 信號來取代關掉重開。 不同的 Daemon 會有不同的行為，所以使用前請先參考 Deamon 的說明文件查看是否可以達到想要的結果。

過程 3.1. 送信號給程序

這個範例將會示範如何送一個信號給 inetd(8)。inetd(8) 的設定檔是 `/etc/inetd.conf`，而 inetd(8) 會在收到 `SIGHUP` 的時候重新讀取這個設定檔。

1. 使用 pgrep(1) 來查詢要傳送信號的目標程序。 在這個例子中 inetd(8) 的 PID 為 198：

       % pgrep -l inetd
       198  inetd -wW

2. 使用 kill(1) 來發送信號。因為 inetd(8) 是 `root` 所有，因此必須先用 su(1) 切換成 `root` 先。

       % su
       Password:
       # /bin/kill -s HUP 198

   對大多數 UNIX® 指令來講，kill(1) 執行成功時並不會輸出任何訊息。 假設您送一個信號給某個不是使用者所擁有的程序， 那麼就會顯示這個錯誤訊息： kill: `PID`: Operation not permitted。 若打錯 PID 的話，那就會把信號送給錯誤的程序，並把該程序關閉，或者是把信號送給一個非使用中的 PID，那您就會看到錯誤：kill: `PID`: No such process。

   ### 為何要使用 `/bin/kill`？ :

   多數 Shell 都有提供內建的 `kill` 指令。 也就是說這種 shell 會直接發送信號，而不是執行 `/bin/kill`。 但要小心不同的 shell 會有不同的語法來指定信號的名稱等。 與其嘗試去把它們通通學會，不如就單純的直接用 `/bin/kill`。

要送其他的信號的話也是非常類似，就視需要把指令中的 `TERM` 或 `KILL` 替換成其他信號的名稱即可。

### 重要:

隨便抓一個系統中的程序然後把他砍掉並不是個好主意。 特別是 init(8)， PID 1 是一個非常特別的程序。 執行 `/bin/kill -s KILL 1` 的結果就是系統立刻關機。 因此在您按下 Return 要執行 kill(1) 之前， 請一定要記得再次確認您下的參數。

[1] 還是有少數東西不能被中斷。 例如有個程序正在從網路上的別的電腦讀一個檔案， 而那部電腦因為某些理由連不到，那這個程序就是一個 “不能中斷的” 程序。 通常在經過 2 分鐘左右之後這個程序會逾時。 當發生逾時的時候這個程序就會被結束掉了。

前一頁 | 上一層 | 下一頁
3.7. 掛載與卸載檔案系統 | 起始頁 | 3.9. Shell

本文及其他文件，可由此下載： ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/。

若有 FreeBSD 方面疑問，請先閱讀 FreeBSD 相關文件，如不能解決的話，再洽詢 <questions@FreeBSD.org>。
關於本文件的問題，請洽詢 <doc@FreeBSD.org>。