了解process daemond定義
了解busybox的background帶起的方式
更新記錄
item | note |
---|---|
20170513 | 第一版 |
目錄
總結
tty關閉, 相同sid的prcoess產生終結
由SIGHUP來通知
不會通知backgroudsession id
The session ID of a process is the process group ID of the session leader.
若是開一個tty登入,再帶程式,此時帶起的程式皆為相同的sidbusybox &(即backgroud)
同 daemon:使用fork,close stdin/stdout/stderr
不同 daemon:帶起之後的ppid還是此tty,當tty關閉後會被init接受,不會處理相關SIGdaemon
fork : 產生新的process
setsid: 產生新的session id(分離目前的tty,防止SIGHUP訊息)
catch signal: 自行處理SIGCHILD/SIGPIPE等訊息
for again: 讓process直接由init接管(此時ppid為1)
chdir: 切換預期工作目錄
umask: 設定檔案權限
close: 關關stdin/stdout/stderr,改由檔案來log
Daemon
Daemon程序
來源:Linux Daemon Writing HOWTO,創建 Daemon 程式
- daemon starts up
- Fork off the parent process : fork出新的processs
- Change file mode mask (umask)
- Open any logs for writing
- Create a unique Session ID (SID) : setsid()
- Change the current working directory to a safe place
- Close standard file descriptors : close std in, std out and std err
- Enter actual daemon code
來源:Linux中创建守护程序
- busybox的daemon (即&)
- 與一般daemon程序比較來少了
- fork agin (?)
在tty關閉之後會被init接收 - catch signal
- fork agin (?)
item | daemon | busybox & | telnetd |
---|---|---|---|
fork | V | V | V |
setsid | V | V | V |
Catch signals | V | X | V |
fork again | V | X? | X? |
chdir | V | X | X |
umask | V | X | X |
close | V | V | V |
- fork off the parent process & let it terminate if forking was successful. -> Because the parent process has terminated, the child process now runs in the background.
- setsid - Create a new session. The calling process becomes the leader of the new session and the process group leader of the new process group. The process is now detached from its controlling terminal (CTTY).
- Catch signals - Ignore and/or handle signals.
- fork again let the parent process terminate to ensure that you get rid of the session leading process. (Only session leaders may get a TTY again.)
fork兩次,這樣讓子進程直接退出,孫進程結束後就成了孤兒進程,會被init接管,直接回收,不用祖父進程管了 - chdir Change the working directory of the daemon
- umask - Change the file mode mask according to the needs of the daemon.
- close - Close all open file descriptors that may be inherited from the parent process.
telnetd : 處理SIGPIPE/SIGCHLD信號
github daemon
daemon example
關閉tty將會產生SIGHUP訊息,關閉相同sid的process
使用telnet登入,板端
- login[1399]: root login on ‘pts/0’
- 1399即telnet
- 1403為a.out的process
1
2
3
4
5
61399 root 3180 S -sh
1403 root 1732 S ./a.out
1404 root 3180 R ps
# cat /tmp/showppid.1403.txt
cnt:3, getppid = 1399
#
關閉telnet, 因此a.out收到SIGHUP訊息關閉
- pid 1399 (即telnet),1403(即a.out)皆被終結
1
2
3
41221 root 3508 S telnetd
1346 root 3180 S -sh
1407 root 3180 R ps
#
- pid 1399 (即telnet),1403(即a.out)皆被終結
showppid.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30/* showppid.c */
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int cnt=0;
FILE *fp;
char path[80];
//sleep(30);
snprintf(path, sizeof(path) - 1, "/tmp/showppid.%d.txt", getpid());
fp = fopen(path, "w+");
if(fp == 0){
return 0;
}
fprintf(fp, "getppid = %d\n", getppid());
fclose(fp);
while(1){
printf("showip\n");
fp = fopen(path, "w+");
if(fp != 0){
fprintf(fp, "cnt:%d, getppid = %d\n",cnt++,getppid());
fclose(fp);
}
sleep(3);
}
return 0;
}
使用nohup不會受到SIGHUP影響
nohup ./a.out
1
2
3
4
5
61346 root 3180 S -sh
1408 root 3180 S -sh
1410 root 1732 S ./a.out
1411 root 3180 R ps
# cat /tmp/showppid.1410.txt
cnt:4, getppid = 1408pid 1410(即a.out)還在存,pid 1408(telnet)關閉
1
2
3
4
5
61346 root 3180 S -sh
1410 root 1732 S ./a.out
1413 root 3180 R ps
# cat /tmp/showppid.1410.txt
cnt:22, getppid = 1
#
使用background方式(即busybox &)
./a.out&
1
2
3
4
5
61419 root 3180 S -sh
1420 root 1732 S ./a.out
1421 root 3180 R ps
# cat /tmp/showppid.1420.txt
cnt:2, getppid = 1419
#關閉telnet(即pid 1419),此時a.out還在存(即pid 1420),但由init接收
1
2
3
4
5
61346 root 3180 S -sh
1420 root 1732 S ./a.out
1423 root 3180 R ps
# cat /tmp/showppid.1420.txt
cnt:12, getppid = 1
#
session id
getsid - get session ID
The session ID of a process is the process group ID of the session leader.session即為tty的pid
使用&帶起
sid應該要不同,因為setsid()?1
2
3
4
5
6
7a2.out&
1443 root 3180 S -sh
1445 root 1732 S ./a2.out
1446 root 3180 R ps
# cat /tmp/showppid.1445.txt
cnt:3, getppid = 1443, getsid(0):1443使用nohup帶起,之後關閉tty
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16nohup a2.out
1346 root 3180 S -sh
1465 root 3180 S -sh
1469 root 1732 S ./a2.out
1470 root 3180 R ps
# cat /tmp/showppid.1469.txt
cnt:3, getppid = 1465, getsid(0):1465
#
1346 root 3180 S -sh
1469 root 1732 S ./a2.out
1473 root 3180 R ps
# cat /tmp/showppid.1469.txt
cnt:12, getppid = 1, getsid(0):1465
#
busybox
來源:daemon 與 background process 的差異
background
- 在ash環境下使用a.out& (即帶&:表示background)
注意,未設定: 忽略SIGHUP信號
此訊息為關閉console/tty時會,發給所有相同session id的prcoessbusybox下使用&, 處理程序如下: (ex. ./a.out&)
- bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS);
1 | debianutils/start_stop_daemon.c |
telnetd
- telnetd處理SIGPIPE/SIGCHLD信號
- busybox telnetd如下
- bb_daemonize_or_rexec()
- signal(SIGPIPE, SIG_IGN);
- signal(SIGCHLD, SIG_IGN);
1 | busybox-1.16.1/networking/telnetd.c |
busybox daemon
- bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS);
- FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
- DAEMON_DEVNULL_STDIO: 關閉標準輸入/輸出/錯誤判面,將這些導到/dev/null
- fork_or_rexec(): fork出1個thread
- setsid
1 | include/libbb.h |
nohup
nohup - run a command immune to hangups, with output to a non-tty
- 關閉stdin
- 將stdout/stderr,導到/root/nohup.out
- signal(SIGHUP, SIG_IGN),不理SIGHUP訊息
1 | coreutils/nohup.c |
參考
- Linux Daemon Writing HOWTO
- The Process Model of Linux Application Development
- Sessions
When a user logs out of a system, the kernel needs to terminate all the processes the user had running (otherwise, users would leave a slew of old processes sitting around waiting for input that can never arrive)
- Sessions
use-and-meaning-of-session-and-process-group-in-unix
A session is a collection of process groups, which are either attached to a single terminal device (known as the controlling terminal) or not attached to any terminal.Who should kill jobs
當關閉tty或console時,
kernel將會送出訊息給相同session id下的所有的process SIGHUP訊號,終結procss
(在hi3535 ash裡面是不會送出SIGHUP給backgroud process)signal小知識
terminal 斷線 (hangup) 時, terminal 的主控 process 會收到 SIGHUP。而它的預設行為是終結程式, 所以關掉 terminal 時, 裡面的程式會直接結束regarding-background-processes-using-fork-and-child-processes-in-my-dummy-shel
You do not want to use the double-fork() method in a shell
(that is for writing daemons that specifically want to escape from supervision by the shell that ran them)- 防止殭屍行程產生
當程序經由系統呼叫 fork() 產生另一個 程序時,這兩個程序間就存在了父子關係
- 當子程序結束時,系統會將子程序的結束狀態保存起來,接著發出訊號 SIGCHLD 通 知父程序來取子程序的結束狀態碼
- 如果父程序比子程序早結束的話,則子程序將成為孤兒,那麼系統會將此孤兒交給 程序 init (pid = 0)
- 父程序根本忘了要處理的話,那麼就會形成一個 zombie 程序,已經完全沒有活 動,所使用的資源也都被系統回收了,但是仍然佔了處理程序表的一筆記錄
- 因為系統對於 SIGCHLD 訊號的處理方式,預設是不理會,如果父程序忘了設定捕捉 SIGCHLD 訊號
在一般的daemon中會看到fork二次,來產生孤兒,因此自然由init接管
- 利用兩次 fork() ,形成祖孫關係,由於系統只承認程序間的父子關係,並不承認 祖孫關係,這樣可讓新生的程序在結束時,自然地形成孤兒,由系統交給 init 程 序執行
- zombie殭屍進程、孤兒進程和守護進程
如何避免殭屍進程
fork兩次,這樣讓子進程直接退出,孫進程結束後就成了孤兒進程,會被init接管,直接回收,不用祖父進程管了Github