So far, we have discussed about processes, its creation, parent and child processes, etc. The discussion will be incomplete without discussing other related processes, such as the Orphan process, Zombie process and Daemon process.
As indicated by the name, orphan implies parentless process. When we run a program or application, the parent process for the application is shell. When we create a process using fork(), the newly created process is the child process and the process that created the child is the parent process. In turn, the parent process of this is shell. Of course, the parent of all the processes is init process (Process ID → 1).
The above is a usual scenario, however, what happens if the parent process exits before the child process. The result is, the child process now becomes the orphan process. Then what about its parent, its new parent is the parent of all the processes, which is nothing but init process (Process ID – 1).
Let us try and understand this using the following example.
#include<stdio.h> #include<stdlib.h> int main() { int pid; system("ps -f"); pid = fork(); if (pid == 0) { printf("Child: pid is %d and ppid is %d\n",getpid(),getppid()); sleep(5); printf("Child: pid is %d and ppid is %d\n",getpid(),getppid()); system("ps -f"); } else { printf("Parent: pid is %d and ppid is %d\n",getpid(),getppid()); sleep(2); exit(0); } return 0; }
UID PID PPID C STIME TTY TIME CMD 4581875 180558 0 0 09:19 ? 00:00:00 sh -c cd /home/cg/root/4581875; timeout 10s main 4581875 180564 180558 0 09:19 ? 00:00:00 timeout 10s main 4581875 180565 180564 0 09:19 ? 00:00:00 main 4581875 180566 180565 0 09:19 ? 00:00:00 ps -f Parent: pid is 180565 and ppid is 180564 UID PID PPID C STIME TTY TIME CMD 4581875 180567 0 0 09:19 ? 00:00:00 main 4581875 180820 180567 0 09:19 ? 00:00:00 ps -f Child: pid is 180567 and ppid is 180565 Child: pid is 180567 and ppid is 0
In simple terms, assume that you have two processes, namely the parent and the child process. It is the responsibility of the parent process to wait for child process and then clean up the child process entry from the process table. What if the parent process is not ready to wait for the child process, and in the meantime the child process gets its job done and exits? Now, the child process would become the zombie process. Of course, the zombie process is cleaned up after the parent process becomes ready.
Let us understand this with the help of an example.
#include<stdio.h> #include<stdlib.h> int main() { int pid; pid = fork(); if (pid == 0) { system("ps -f"); printf("Child: pid is %d and ppid is %d\n",getpid(),getppid()); exit(0); } else { printf("Parent: pid is %d and ppid is %d\n",getpid(),getppid()); sleep(10); system("ps aux|grep Z"); } return 0; }
UID PID PPID C STIME TTY TIME CMD 4581875 184946 0 0 09:20 ? 00:00:00 sh -c cd /home/cg/root/4581875; timeout 10s main 4581875 184952 184946 0 09:20 ? 00:00:00 timeout 10s main 4581875 184953 184952 0 09:20 ? 00:00:00 main 4581875 184954 184953 0 09:20 ? 00:00:00 main 4581875 184955 184954 0 09:20 ? 00:00:00 ps -f Child: pid is 184954 and ppid is 184953
In simple terms, the process which doesn’t have any associated shell or terminal is known as the daemon process. Why this is needed? These are the processes which run in the background to perform actions at predefined intervals and also respond to certain events. The daemon process should not have any user interaction, since it runs as a background process.
The internal Linux daemon processes usually ends with the letter “d” such as Kernel Daemons (ksoftirqd, kblockd, kswapd, etc.), Printing Daemons (cupsd, lpd, etc.), File Service Daemons (smbd, nmbd, etc.), Administrative database daemons (ypbind, ypserv, etc.), Electronic Mail Daemons (sendmail, popd, smtpd, etc.), Remote Login and Command Execution Daemons (sshd, in.telnetd, etc.), Booting and Configuration Daemons (dhcpd, udevd, etc.), init process (init), cron daemon, atd daemon, etc.
Now let us see how to create a daemon process. Following are the steps −
Step 1 − Create a child process. Now we have two processes – the parent process and the child process
Usually the process hierarchy is SHELL → PARENT PROCESS → CHILD PROCESS
Step 2 − Terminate the parent process by exiting. The child process now becomes the orphan process and is taken over by init process.
Now, the hierarchy is INIT PROCESS → CHILD PROCESS
Step 3 − Calling the setsid() system call creates a new session, if the calling process is not a process group leader. Now the calling process becomes the group leader of the new session. This process will be the only process in this new process group and in this new session.
Step 4 − Set the process group ID and session ID to PID of the calling process.
Step 5 − Close the default file descriptors (standard input, standard output, and standard error) of the process as the terminal and shell are now disconnected from the application.
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdlib.h> #include<string.h> int main(int argc, char *argv[]) { pid_t pid; int counter; int fd; int max_iterations; char buffer[100]; if (argc < 2) max_iterations = 5; else { max_iterations = atoi(argv[1]); if ( (max_iterations <= 0) || (max_iterations > 20) ) max_iterations = 10; } pid = fork(); // Unable to create child process if (pid < 0) { perror("fork error\n"); exit(1); } // Child process if (pid == 0) { fd = open("/tmp/DAEMON.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644); if (fd == -1) { perror("daemon txt file open error\n"); return 1; } printf("Child: pid is %d and ppid is %d\n", getpid(), getppid()); printf("\nChild process before becoming session leader\n"); sprintf(buffer, "ps -ef|grep %s", argv[0]); system(buffer); setsid(); printf("\nChild process after becoming session leader\n"); sprintf(buffer, "ps -ef|grep %s", argv[0]); system(buffer); close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); } else { printf("Parent: pid is %d and ppid is %d\n", getpid(), getppid()); printf("Parent: Exiting\n"); exit(0); } // Executing max_iteration times for (counter = 0; counter < max_iterations; counter++) { sprintf(buffer, "Daemon process: pid is %d and ppid is %d\n", getpid(), getppid()); write(fd, buffer, strlen(buffer)); sleep(2); } strcpy(buffer, "Done\n"); write(fd, buffer, strlen(buffer)); // Can't print this as file descriptors are already closed printf("DoneDone\n"); close(fd); return 0; }
Parent: pid is 193524 and ppid is 193523 Parent: Exiting 4581875 193525 0 0 09:23 ? 00:00:00 main 4581875 193526 193525 0 09:23 ? 00:00:00 sh -c ps -ef|grep main 4581875 193528 193526 0 09:23 ? 00:00:00 grep main 4581875 193525 0 0 09:23 ? 00:00:00 main 4581875 193529 193525 0 09:23 ? 00:00:00 sh -c ps -ef|grep main 4581875 193531 193529 0 09:23 ? 00:00:00 grep main