Linux system () and Popen () Differences 1. Introduction to System () and Popen ()
In Linux we can execute a shell command through system (), and Popen () executes shell commands and communicates through pipelines and shell commands.
System (), Popen () gives us a series of processing processes such as fork, exec, waitpid, and so on, so that we only need to focus on the final return result (the function's return value).
2. System (), Popen () source code
First, let's look at the differences between the two functions in the source code (pseudocode).
intSystemConst Char*command) {structSigaction Sa_ignore, Sa_intr, Sa_quit; sigset_t Block_mask, Orig_mask; pid_t pid; Sigemptyset (&block_mask); Sigaddset (&block_mask, SIGCHLD); Sigprocmask (Sig_block, &block_mask, &orig_mask);//1. Block SIGCHLDSa_ignore. Sa_handler= Sig_ign; Sa_ignore. Sa_flags=0; Sigemptyset (&sa_ignore. Sa_mask); Sigaction (SIGINT, &sa_ignore, &sa_intr);//2. Ignore SIGINT signalSigaction (Sigquit, &sa_ignore, &sa_quit);//3. Ignore Sigquit signal Switch(PID = fork ())) { Case-1:return-1; Case 0: Sigaction (SIGINT, &sa_intr,NULL); Sigaction (Sigquit, &sa_quit,NULL); Sigprocmask (Sig_setmask, &orig_mask,NULL); EXECL ("/bin/sh","sh","-C", Command, (Char*)0); Exit127);default: while(Waitpid (PID,NULL,0) == -1)//4. Wait Child process exit{if(errno! = eintr) { Break; } } }}return 0;
Above is a not complete system function source code, the latter need our attention and popen the difference of the part has been marked out with numbers.
static pid_t *childpid =NULL;/ * ptr to array allocated at Run-time * /static int maxfd;/* from our Open_max (), {Prog OpenMAX} */ #define SHELL "/bin/sh"FILE * Popen (constChar*cmdstring, constChar*type) {int I, pfd[2]; pid_t pid; FILE *FP;/* Only allow "R" or "W" * / if((type[0] !=' R '&& type[0] !=' W ') || type[1] !=0) {errno = EINVAL;/ * required by POSIX.2 * / return(NULL); }if(Childpid = =NULL) {/* First time through * / / * Allocate zeroed out array for child PIDs * /MAXFD = Open_max ();if(Childpid = calloc (maxfd, sizeof (pid_t)) = =NULL)return(NULL); }if(Pipe (PFD) <0)return(NULL);/* errno set by pipe () */ if(PID = fork ()) <0)return(NULL);/* errno set by fork () */ Else if(PID = =0) {/ * Child * / if(*type = =' R ') {Close(pfd[0]);if(pfd[1] = Stdout_fileno) {dup2 (pfd[1], Stdout_fileno);Close(pfd[1]); } }Else{Close(pfd[1]);if(pfd[0] = Stdin_fileno) {dup2 (pfd[0], Stdin_fileno);Close(pfd[0]); } }/ * Close all descriptors in childpid[] * / for(i =0; i < maxfd; i++)if(childpid[i] >0)Close(i); Execl (SHELL,"sh","-C", Cmdstring, (Char*)0);_exit(127); }/ * Parent * / if(*type = =' R ') {Close(pfd[1]);if(fp = Fdopen (pfd[0], type) = =NULL)return(NULL); }Else{Close(pfd[0]);if(fp = Fdopen (pfd[1], type) = =NULL)return(NULL); } childpid[fileno (fp)] = pid;/ * Remember child pid for this FD * / return(FP); }
Above is the source code of Popen.
3. Execution process
From the source above you can see that both the system and the Popen are performing similar running processes, roughly fork->execl->return. But we see that the call process during system execution waits until the shell command finishes (Waitpid waits for the child process to end) to return, but Popen does not have to wait for the shell command to complete. We can understand that system is serial execution, and during execution the calling process discards "control" and Popen is executed in parallel.
Popen in the process of the child no one gave it a corpse? Yes, if you do not call Pclose after calling Popen, then this subprocess may become "zombie".
Above we did not give Pclose source code, in fact, we according to the system source code almost can guess the Pclose source code is the system in part 4 of the content.
4. Signal Processing
We see that the SIGCHLD, SIGINT, and Sigquit are handled in the system, but no signal is processed in the Popen.
SIGCHLD is a signal sent to the parent process when the child process exits, why the system () is shielded from the SIGCHLD signal can be consulted: summary of the system functions, waitpid (or wait) and sigchild relationship, the summary is for the system () call is able to exit in a timely manner and get the exit status of the child process correctly (the child process is successfully recycled).
Popen does not block sigchld, the main reason is that Popen is "parallel". If we block SIGCHLD when calling Popen, then if the call process is called between Popen and Pclose, another child process is created and the calling process registers the SIGCHLD signal processing handle to handle the child process's recycling (WAITPID) Then this recycling will be blocked until the pclose call. This also means that if the calling process executes a wait () operation before Pclose, it is possible to obtain the state of the child process created by Popen, so that when the pclose is invoked, the (WAITPID) child process fails, returns 1, and the errno is set to ECHLD, Flag Pclose cannot get child process status.
The reasons for masking SIGINT, sigquit in System () can continue to refer to the summary of the system functions mentioned above, the reason why the Popen () function does not mask SIGINT, sigquit, or because Popen is "parallel" and does not affect other "parallel" Process.
4. function
From the above chapters we have basically analyzed the two functions almost, the difference between the two functions is more obvious, the system is the execution of the shell command finally returns whether the execution succeeds, Popen executes the command and communicates through the pipeline and the shell command.
NOTE
Be careful not to use system and Popen in the privileged (setuid, setgid) session.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Linux system () and popen () differences