Linux Process understanding and practice (5) discuss the daemon process
1. daemon process and Its Features
The most important feature of a daemon is that it runs in the background. At this point, the TSR of the resident memory program under DOS is similar. Second, the daemon must be isolated from the environment before running. These environments include unclosed file descriptors, control terminals, sessions and process groups, working directories, and file creation masks. These environments are generally inherited by the daemon from the parent process (especially the shell) that executes the daemon. Finally, the daemon startup method has its own special features. It can be started from the startup script/etc/rc. d when the Linux system is started. It can be started by the job planning process crond and executed by the user terminal (usually shell.
In short, apart from these special features, the daemon process is basically no different from the common process. Therefore, writing a daemon actually transforms a common process into a daemon according to the features of the preceding daemon. If you have a deep understanding of the process, it is easier to understand and program the process.
II. Key Points of daemon Programming
As mentioned above, the programming rules of daemon in different Unix environments are inconsistent. Fortunately, the programming principles of the daemon process are the same. The difference is that the specific implementation details are different. This principle is to satisfy the characteristics of the daemon process. At the same time, Linux is a SVR4 Based on Syetem V and complies with the Posix standard, which is easier to implement than bsd4. The main points of programming are as follows;
1. Run in the background.
To avoid pending the control terminal, place the Daemon in the background for execution. The method is to call fork in the process to terminate the parent process and run Daemon in the background of the child process.
If (pid = fork ())
Exit (0); // indicates the parent process. The parent process ends and the child process continues.
2. log on to the session and process group from the control terminal.
It is necessary to first introduce the relationship between processes and control terminals, logon sessions, and process groups in Linux: Processes belong to a process group, process group number (GID) is the process ID (PID) of the process leader ). A logon session can contain multiple Process Groups. These process groups share a control terminal. This control terminal is usually the login terminal that creates a process.
Control terminal, logon sessions and process groups are generally inherited from the parent process. Our goal is to get rid of them so that they are not affected. The method is to call setsid () on the basis of to make the process a session leader:
The setsid function is used to create a new session and act as the group leader. Calling setsid has the following three functions:
(1) Let the process get rid of the control of the original session
(2) Remove the process from the control of the original Process Group
(3) freeing the process from the control of the original control terminal
That is to say, because the fork function is called to create a child process in the first step of daemon creation, the parent process is exited. When the fork function is called, the sub-process completely copies the session period, process group, and control terminal of the parent process. Although the parent process exits, however, the session period, process group, and control terminal are not changed. Therefore, this is not truly independent, and the setsid function can make the process completely independent, to get rid of the control of other processes.
Note: setsid () fails to be called when the process is a session leader. However, the first point is that the process is not the session leader. After the setsid () call is successful, the process becomes a new session leader and a new process leader, and is detached from the original logon session and process group. Because the session process is dedicated to the control terminal, the process is separated from the control terminal at the same time.
3. Prohibit the process from re-opening the control terminal
Now, the process has become the no-end session leader. But it can re-apply to open a control terminal. You can disable the process from re-opening the control terminal by making the process no longer the session leader:
If (pid = fork ())
Exit (0); // end the first child process and the second child process (the second child process is no longer the session leader)
Note: many readers may ask, why do we need to create two processes? This is because after Step 2 ends, the process creates a new session group and becomes the session leader, and the session leader may obtain the control terminal, if the control terminal is obtained, or this process is not a daemon process. Therefore, the code is added so that the process loses the identity of the session leader and thus does not have the permission to control the terminal.
4. Disable open file descriptors
Like the File Permission Code, the child process created using the fork function will inherit some opened files from the parent process. These opened files may never be read or written by the daemon, But they consume the same system resources and may cause the file system to be unable to be detached. After step 2, the daemon has lost contact with the control terminal. Therefore, the characters entered from the terminal cannot reach the daemon process, and the characters output by conventional methods (such as printf) in the daemon cannot be displayed on the terminal. Therefore, the three files whose file descriptors are 0, 1, and 2 (input, output, and error) have lost value and should be disabled. Usually close the file descriptor as follows: for (I = 0; I 5. Change the current working directory
This step is also necessary. The child process created using fork inherits the current working directory of the parent process. Because the file system in the current directory (such as "/mnt/usb") cannot be detached while the process is running, this will cause a lot of trouble for future use (for example, the system needs to enter the single-user mode for some reason ). Therefore, the common practice is to make "/" the current working directory of the daemon, so as to avoid the above problems. Of course, if you have special requirements, you can also change the current working directory to another path, such as/tmp. Change the common functional chdir of the working directory.
6. Reset the file to create a mask
A process inherits the file creation mask from the parent process that created it. It may modify the access bit of the file created by the daemon. To prevent this, clear the file creation mask: umask (0 );
7. Process SIGCHLD Signal
It is not necessary to process SIGCHLD signals. However, some processes, especially server processes, usually generate sub-processes to process requests when requests arrive. If the parent process does not wait for the child process to end, the child process will become a zombie process, occupying system resources. If the parent process waits for the child process to end, it will increase the burden on the parent process and affect the concurrent performance of the server process. In Linux, you can set the SIGCHLD signal operation to SIG_IGN.
Signal (SIGCHLD, SIG_IGN );
In this way, the kernel will not generate zombie processes when the child process ends. This is different from BSD4. In BSD4, you must explicitly wait for the child process to end before releasing the zombie process.
Because all processes in linux belong to a tree, the root node of the tree is the init process started at the end of linux system initialization. The pid of the process is 1, all other processes are their children. In addition to init, any process must have its parent process, and the parent process will be responsible for allocating (fork) and revoking (wait4) The process resources it applies. This tree-like relationship is also robust. When a process is still running, its parent process exits, but this process does not become an orphan process, because linux has a mechanism, the init process takes over it and becomes its parent process. This is also the origin of the daemon process, because one of the requirements of the daemon process is that it wants init to become the parent process of the daemon process.
If a process terminates itself, it will enter the ZOMBIE state after calling exit to clear related content files and other resources, and its parent process will call wait4 to recycle the task_struct, however, if the parent process has never called wait4 to release the task_struct of the child process, the problem arises. Who will recycle this task_struct? No one will ever be there unless the parent process is terminated and the init process takes over the ZOMBIE process, and then wait4 is called to recycle the process descriptor. If the parent process is running all the time, ZOMBIE will occupy the system resources forever and use KILL to send any semaphores. This is terrible because numerous ZOMBIE processes may occur on the server, causing the machine to crash.
8. Daemon exit handling
When a user needs to stop a daemon from running, the user often uses the kill command to stop the daemon. Therefore, the daemon must be encoded to process the signal sent by kill to exit the process normally.
====================================
Signal (SIGTERM, sigterm_handler );
Void sigterm_handler (int arg)
{
_ Running = 0;
}
====================================
In this way, a simple daemon is established.
# Include <unistd. h> # include <signal. h> # include <sys/param. h> # include <sys/types. h> # include <sys/stat. h> void init_daemon (void) {int pid; int I; if (pid = fork () exit (0); // It is the parent process, stop the parent process else if (pid <0) exit (1); // fork failed, exit // is the first sub-process, and the background continues to execute setsid (); // The first sub-process becomes the new session leader and process leader // and is separated from the control terminal if (pid = fork () exit (0); // is the first sub-process, stop the first sub-process else if (pid <0) exit (1); // fork failed, exit // is the second sub-process, continue // the second sub-process is no longer the session leader for (I = 0; I <NOFILE; ++ I) // close the opened file descriptor close (I ); chdir ("/tmp"); // change the working directory to/tmp umask (0); // reset the file creation mask return;} 2. test. c LIST # include <stdio. h> # include <time. h> void init_daemon (void); // Daemon initialization function main () {FILE * fp; time_t t; init_daemon (); // initialize to Daemon while (1) // test every minute. log reports the running status {sleep (60); // if (fp = fopen ("test. log "," a ")> = 0) {t = time (0); fprintf (fp," Im here at % s/n ", asctime (localtime (& t); fclose (fp );}}}
View process: ps-ef
From the output, we can find that the various features of the test daemon meet the above requirements.