3.8. 程序與 Daemon

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

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

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

通常來說做為 Deamon 執行的程式名字後面都會加一個字母 dBIND 是 Berkeley Internet Name Domain 的縮寫,但實際上執行的程式名稱是 namedApache 網頁伺服器的程式名稱是 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 是執行這個程式的指令。

有幾個不同的選項組合可以用來變更顯示出來的資訊,其中一個最有用的組合是 auxwwa 可以顯示所有正在跑的程序的指令,不只是您自已的。 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) 給該程式。

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

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

其他常用的信號有:SIGHUP, SIGUSR1SIGUSR2。 這些是通用的信號,對不同的應用程式會有不同的反應。

舉例來說,當您更動了網頁伺服器的設定檔,您想要叫網頁伺服器去重新讀取設定。 重新啟動 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

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

重要:

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



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

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

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

關於本文件的問題,請洽詢 <doc@FreeBSD.org>。