Detecting child process creation in fork() - c++

The fork() system call makes two identical copies of the address space, one for parent, the other for the child.
When using fork with an if statement, how many times will the child process be created in the following code?
fork();
pid=fork();
if(pid==0)
{
fork();
}

Add a little extra code to get something like:
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
if (pid != 0) printf("%d\n", pid);
pid = fork();
if (pid != 0) printf("%d\n", pid);
if(pid==0)
{
pid = fork();
if (pid != 0) printf("%d\n", pid);
}
return 0;
}
Then compile, execute, and check its output: 5 child process IDs.

Related

Zombie process is not cleanup with waitpid call

I am watching the processes with htop and I see that child process stays as zombie even though I clean up with waitpid call. Any idea why this might happen?
Thank you very much!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
void child_signal_handler(int signal) {
printf("Someone is stabbed me with signal %d\n", signal);
}
int main(int argc, char** argv)
{
const pid_t child = fork();
if (child == 0) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = &child_signal_handler;
sigaction(SIGTERM, &sa, NULL);
printf("Child is started in busy loop\n");
while (true)
;
} else {
const int mercy_period = 3;
printf("Parent is angry and gonna kill his child in %d sec\n", mercy_period);
sleep(mercy_period);
kill(child, SIGTERM);
// clean-up zombie child process as it is terminated before we can wait on
// it
int status = 0;
while(waitpid(-1, &status, WNOHANG) > 0);
}
return EXIT_SUCCESS;
}
waitpid glibc implementation comments
If PID is (pid_t) -1, match any process. If the WNOHANG bit is set in OPTIONS, and that child
is not already dead, return (pid_t) 0.
The while loop clearly exits immediately as 0 > 0 is false.
Change the else and the signal to SIGKILL
} else {
const int mercy_period = 3;
printf("Parent is angry and gonna kill his child in %d sec\n", mercy_period);
sleep(mercy_period);
kill(child, SIGKILL);
int status = 0;
pid_t pid = waitpid(-1, &status, WNOHANG);
while(!pid) {
pid = waitpid(-1, &status, WNOHANG);
printf("%d\n", pid);
}
}
After few attempts waitpid will return the pid of the child process. A success.

waitpid getting hooked and not returning

I have a function that is calling a process called driverclear. Seems like the process starts but it never returns because I never get the output of the process and I never get the "Process Complete" message. Is there something I am doing wrong?
void cleanDriver
{
pid_t pid;
if(chmod("./helpers/driverclear", S_IXUSR) == 0)
{
int status = 0;
pid = fork();
if(pid == 0)
{
if(!execl("./helpers/driverclear", "driverclear", (char*) NULL))
{
perror("execl failed.\n");
}
}
else
{
printf("Process Starting...");
waitpid(pid, &status, 0);
printf("Process Complete\n");
}
}
}
Instead of using execl I just switched to using system("sh root/helpers/driverclear"); which fixes my problems.

How to create one level process tree using fork() system call?

I want to create a one level process tree using fork() system call, which looks as follows
for n = 4 process
I have tried this with the following code but this is not working. (here 1 is a child of parent process )
for(i = 0 ;i < n; i++){
chid = fork();
if ( chid == 0 ){
printf("%d\n",getpid());
while(++i < n){
chid = fork();
if(chid == 0){
printf(" %d ",getpid());
break;
}
}
}
else
break;
}
How can I make this ?
#include<stdio.h>
int main()
{
int i;
pid_t pid;
for(i=0; i<5; i++)
{
pid = fork();
if(pid == 0)
break;
}
printf("pid %d ppid %d\n", getpid(), getppid());
if(pid == 0)
{
/* child process */
}
}
Based on the discussion, here is the modified program.
#include<stdio.h>
#include<unistd.h>
int main()
{
int i;
pid_t pidparent, pid;
if( (pidparent = fork()) == 0 )
{
for(i=0; i<3; i++)
{
pid = fork();
if(pid == 0)
break;
}
if(pid == 0)
{
printf("child %d parent %d\n", getpid(), getppid());
}
}
else
{
printf("parent %d \n", pidparent);
}
/* printf("pid %d ppid %d\n", getpid(), getppid()); */
}

Getting the PID from popen

I have a program that uses popen() in order to open and read the output from a shell command. The problem is, as far as I can tell, there is no easy way to get the PID of the running process, and hence, you can't kill it if it gets stuck. So the question is, how can you retrieve the PID from a process opened with popen?
The solution I came up with (and the general consensus) is to create a new popen function that allows me to retrieve the PID. Since I was unable to find a simple example of this on SO, I wanted to post my implementation in the hopes that it helps somebody else. Feedback and alternate solutions are welcome.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <string>
#include <sstream>
using namespace std;
#define READ 0
#define WRITE 1
FILE * popen2(string command, string type, int & pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == "r")
{
close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[WRITE], 1); //Redirect stdout to pipe
}
else
{
close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[READ], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL);
exit(0);
}
else
{
if (type == "r")
{
close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only
}
}
pid = child_pid;
if (type == "r")
{
return fdopen(fd[READ], "r");
}
return fdopen(fd[WRITE], "w");
}
int pclose2(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}
int main()
{
int pid;
string command = "ping 8.8.8.8";
FILE * fp = popen2(command, "r", pid);
char command_out[100] = {0};
stringstream output;
//Using read() so that I have the option of using select() if I want non-blocking flow
while (read(fileno(fp), command_out, sizeof(command_out)-1) != 0)
{
output << string(command_out);
kill(-pid, 9);
memset(&command_out, 0, sizeof(command_out));
}
string token;
while (getline(output, token, '\n'))
printf("OUT: %s\n", token.c_str());
pclose2(fp, pid);
return 0;
}
CLARIFICATION
I tried to use the defined functions by #Gillespie's answer but found out that the pid in the C/C++ program was different from the one returned by the terminal command pgrep and looking at the output of ps -aux | grep myNameProc it seemed the process of the C program was forked once more.
I think because execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL); is actually equivalent to /bin/sh cmd string. So basically the child process of your C (or C++) program is creating a new process that does /bin/sh yourRealProcess where yourRealProcess is the one specified in the command string.
I solved doing the following: execl(command.c_str(), command.c_str(), (char*)NULL);. However, as specified by #Gillespie in the previous comments, in this way you will not be able to pass arguments to your process.
C IMPLEMENTATION
According to my needs I readapted #Gillespie's functions to include the above discussed modification and to work in the C programming language:
FILE * custom_popen(char* command, char type, pid_t* pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == 'r')
{
close(fd[0]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[1], 1); //Redirect stdout to pipe
}
else
{
close(fd[1]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[0], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl(command, command, (char*)NULL);
exit(0);
}
else
{
printf("child pid %d\n", child_pid);
if (type == 'r')
{
close(fd[1]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[0]); //Close the READ end of the pipe since parent's fd is write-only
}
}
*pid = child_pid;
if (type == 'r')
{
return fdopen(fd[0], "r");
}
return fdopen(fd[1], "w");
}
int custom_pclose(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}

How to access the same variable by multiple processes C/C++

I have recently started learning how to program in C under Linux and have written the following code to create some processes:
void generate()
{
int pid;
for(int i=1;i<=10;i++)
{
pid = fork();
}
if (pid<0)
{
printf("Error Fork");
exit(1);
}
if(pid == 0)
{
printf("Fiu pid: %d --- Parinte pid: %d\n", getpid(), getppid());
//count ++;
}
if(pid > 0 )
{
printf("Parinte pid: %d\n", getpid());
//count++;
wait();
}
}
The question is: how should i declare/increment the count variable in order to print the total number of processes the function has created?
It's simple. Fork produces a child for each parent. The answer is therefore 2^10 or 1024.
Put a printf after the fork and comment out the other extraneous output. Run as
./a.out | sort | uniq | wc
The output is is 1024.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void generate()
{
int pid;
for(int i=1;i<=10;i++)
{
pid = fork();
printf("%d\n", getpid());
}
if (pid<0)
{
//printf("Error Fork");
exit(1);
}
if(pid == 0)
{
//printf("Fiu pid: %d --- Parinte pid: %d\n", getpid(), getppid());
//count ++;
}
if(pid > 0 )
{
//printf("Parinte pid: %d\n", getpid());
//count++;
wait(NULL);
}
}
int main(int argc, char *argv[])
{
generate();
return(0);
}
Probably there are better approaches but.. You can append a new line/character to a temp file every time a child is created. Then you just have to count the lines/characters of the file.