fork() and exec() Two Child Processes - c++

I am calling fork() twice to create two child processes. I want child process A to do an exec() call and child process B to also do an exec() call. The problem I am having with the given code is that after the first exec() from child process A, the next fork() does not seem to occur and the program exits. I think that it has to do with how exec() overlays the parent process. What I want to accomplish is to call exec() from each of the child processes created by fork().
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
int main() {
pid_t cpid_a, cpid_b;
cpid_a = fork();
if(cpid_a < 0) {
std::cout << "Fork failed." << '\n';
return 1;
}
else if(cpid_a == 0) { // code for child process A
execlp("/bin/ls", "ls", NULL);
cpid_b = fork();
if(cpid_b < 0) {
std::cout << "Fork failed." << '\n';
return 1;
}
else if(cpid_b == 0) { // code for child process B
execlp("/bin/ls", "ls", NULL);
}
}
else { // code for parent process
while(wait(NULL) != -1);
}
return 0;
}

else if(cpid_a == 0) { // code for child process A
execlp("/bin/ls", "ls", NULL);
If this calls succeeds, the following statement, and nothing that follows will ever be executed. That's how exec() works. The immediately-following fork() never occurs. That's simply how exec() works. If exec() succeeds, it never returns. The replacement process gets executed in its place.
You even added the 100% correct comment, above: "code for child process A". Everything inside the if() statement is "code for child process A", and gets executed when fork() returns 0.
You also correctly stated that you want the parent process to fork a second process. Well, you need to have that code obviously get executed by the parent process, and not the child process:
else if(cpid_a == 0) { // code for child process A
execlp("/bin/ls", "ls", NULL);
exit(1);
} else {
cpid_b = fork();
// The rest of the code.
Now, the parent process goes ahead and fork() a second time, proceeded on the rest of your plan.
P.S. The exit() is just for a good measure. The only time exec() returns is when exec() fails to execute the given process. Highly unlikely, in the case of /bin/ls; if it's missing you have bigger problems to worry about. Still, that's the technically correct thing to do, since continuing execution at that point will result in complete chaos. Again, if /bin/ls is missing that's going to be the least of the problems, but this can also happen if, say, the system ran out of memory and can't execute it for that reason; in which case there's no need to add fuel to the fire; but rather have the process die anyway.

Related

Is there way to detach process from out-stream after some time?

I am using boost::process::child to spawn new process.
Start time of process which I am start isn't instant, so I have to wait some time until full initialization of it.
auto is_ptr = std::make_shared<bp::ipstream>();
auto child_pr = std::make_shared<bp::child>(executable, args, bp::std_out > *is_ptr);
m_childs[port] = {child_pr, is_ptr};
std::string line;
while (child_pr->running() && std::getline(*is_ptr, line)) {
std::cerr <<"SI: \t" << line << std::endl;
if( 0 == line.compare(0, string_to_find.size(), string_to_find)){
break;
}
}
...
After this cycle I don't need to have ipstream anymore. Is any way to detach it from the child process?
Since you asked to provide answer, I'll put some additional information here, although I am not sure it will completely answer your question.
Assuming the target platform is Linux, once ipstream is destroyed in the parent process, it effectively means that the file descriptor for the associated pipe between the parent and child process is closed in the parent process. Once the child process writes to the pipe after the parent process closed its read end of the pipe, SIGPIPE is generated for the child process, which will cause it to terminate in case no extra measures are taken.
To prevent this, one option is to ignore SIGPIPE in the child. This will now cause errors in the child process when writing to that pipe. It depends on the implementation of the child process what cause that will have. A solution in your case could be to ignore SIGPIPE, and take measures in the child process once it can no longer successfully write data, to prevent a lot of wasted CPU cycles.
To experiment with this on a lower level, you can use the following program. It will fork a child process that will keep on writing to some output as long as that succeeds. The parent process will close the corresponding pipe as soon as it has read some data from it.
The behavior of the program differs depending on how SIGPIPE is handled in the child process. In case it is ignored, the write() in the child process will fail, and the child process will exit with a non-zero exit code. In case the SIGPIPE is not ignored, the child process is terminated by the operating system. The parent process will tell you what happened in the child process.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char** argv)
{
int pipe_fds[2];
if (pipe(pipe_fds) < 0) {
perror("pipe");
exit(1);
}
pid_t pid;
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0)
{
close(pipe_fds[0]); /* close read-end in the child */
/* Uncomment the following line, and the child will terminate as soon
as the parent closes the read end of the pipe...This is here merely
for illustrative purposes, production code should use either
sigaction() or pthreads related signal functionality in case of a
multi-threaded program. */
/* signal(SIGPIPE, SIG_IGN); */
/* Child process, start writing to the write-end of the pipe. */
const char message[] = "Hello world!\n";
while (write(pipe_fds[1], message, strlen(message)) >= 0);
exit(1);
}
close(pipe_fds[1]);
char buf[256];
ssize_t count;
while ((count = read(pipe_fds[0], buf, sizeof(buf) - 1)) == 0);
if (count < 0) {
perror("read");
exit(1);
}
buf[count] = '\0';
printf("%s", buf);
/* Close read-end in the parent, this will trigger SIGPIPE in the child
once the child writes to the pipe. */
close(pipe_fds[0]);
int stat;
if (waitpid(pid, &stat, 0) < 0) {
perror("waitpid");
exit(1);
}
if (WIFSIGNALED(stat) && WTERMSIG(stat) == SIGPIPE) {
printf("\nChild terminated by SIGPIPE\n");
}
if (WIFEXITED(stat)) {
printf("\nChild exited with exit code %d\n", WEXITSTATUS(stat));
}
exit(0);
}

I want to restart my program after the few seconds what I set

In present, I try to make a watchdog for my project.
Also, I want to make a restart timer.
I mean if the few seconds pass, the program will start from first.
Surely, I can use while loop in main function. I don't want this.
I just want to make some class such as a timer or watchdog,
After the main function passes the time I set, I want to let my program start again.
Is there any good idea?
int main(void)
{
Timer timer(5) // setting my timer to 5 secs
//If time takes over the 5 secs in this loop,
//I want to restart the main loop.
while(1)
{
//Do Something...
}
return 0;
}
If you can get your code to keep an eye on the clock and voluntarily return after so-many-seconds have elapsed, that's usually the best way; however, since you mentioned a watchdog, it sounds like you don't want to trust your code to do that, so (assuming you have an OS that supports fork()) you can spawn a child process to run the code, and then the parent process can unilaterally kill() the child process after 5 seconds and then launch a new one. Here's an example, with a child process counting a random number of potatoes, one per second; if it tries to count more than 5 of them, it will be killed by the parent process.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
// The code you want to be able to abort and restart would go in here
static void FunctionThatMightTakeALongTime()
{
srand(time(NULL)); // just so we get different random values each time
const int countTo = (rand()%12)+1;
for (int i=0; i<countTo; i++)
{
printf("%i potato... (out of %i)\n", i+1, countTo);
sleep(1);
}
}
int main(int argc, char ** argv)
{
while(1)
{
pid_t pid = fork();
if (pid == -1)
{
perror("fork"); // fork() failed!?
return 10;
}
else if (pid == 0)
{
// We're in the child process -- do the thing
printf("Starting child process...\n");
FunctionThatMightTakeALongTime();
printf("Child process completed!\n");
return 0;
}
else
{
// We're in the parent/watchdog process -- wait
// 5 seconds, and then if the child process is
// still running, send it a SIGKILL signal to kill it.
// (if OTOH it has already exited, the SIGKILL isn't
// required but it won't do any harm either)
sleep(5);
printf("Watchdog: killing child process now\n");
if (kill(pid, SIGKILL) != 0) perror("kill");
// Now call waitpid() to pick up the child process's
// return code (otherwise he'll stick around as a zombie process)
if (waitpid(pid, NULL, 0) == -1) perror("waitpid");
}
}
}
Note: If your OS doesn't support fork() (i.e. your OS is Windows), this technique is still possible, but it requires the use of Windows-specific APIs and is significantly more work to implement.

child process hanging while reading from stdin (fork/dup2 race condition)?

I have a process that forks in order to execute a subprocess, which receive an entry from stdin and writes to stdout.
My code in short is as follows:
int fd[2];
int fd2[2];
if (pipe(fd) < 0 || pipe(fd2) < 0)
throws exception;
pid_t p = fork();
if (p == 0) // child
{
close(fd[0]); //not needed
dup2( fd[1],STDOUT_FILENO);
dup2( fd[1],STDERR_FILENO);
close(fd2[1]); //not needed
//what if write calls on parent process execute first?
//how to handle that situation
dup2( fd2[0],STDIN_FILENO);
string cmd="./childbin";
if (execl(cmd.c_str(),(char *) NULL) == -1)
{
exit (-1);
}
exit(-1);
}
else if (p > 0) // parent
{
close(fd[1]); //not needed
close(fd2[0]);
if (write(fd2[1],command.c_str(),command.size())<0)
{
throw exception;
}
close(fd2[1]);
//waits for child to finish.
//child process actually hangs on reading for ever from stdin.
pidret=waitpid(p,&status,WNOHANG))==0)
.......
}
The child process remains waiting forever for data in STDIN. Is there maybe a race condition between the child and parent process? I think that could be the problem but not quite sure and also not sure how to fix it.
Thanks in advance.
Update:
Some useful information.
The parent process is a daemon and this code runs several times per second. It works 97% of the times (~3% of the cases, the child process remains in the state described before).
UPDATE 2
After added validation in dup2 call, there is no error there, next condition is never raised.
if(dup2(...) == -1) {
syslog(...)
}
Your missing a wait that is why you in 3% of the cases run the parent before the child. See the example at the bottom.
Also you should call close on the fd's you don't use before doing anything else.

Input command with system() and sleep()

Is there a way to use system() and ask for the code to wait a few seconds?
I have been trying something like:
system("MyCmd");
sleep(8000);
However, sleep() terminates "MyCmd" execution.
Any thoughts?
However, sleep() terminates "MyCmd" execution.
No. The sleep() expression doesn't terminate the child process created with the system() call, the expressions
system("MyCmd");
sleep(8000);
will just be executed sequentially.
What you can do is to call fork() to create a child process, call sleep() in the parent process, and kill() the child process, if it's still running after the parent process awakes:
pid_t pid = fork();
if (pid == 0) {
// child process
execl ("/bin/MyCmd", "MyCmd", (char *)0);
}
else if (pid > 0) {
// parent process
sleep(8000);
kill(pid,SIGKILL);
}
else {
// fork failed
printf("fork() failed!\n");
return 1;
}

How to handle execvp(...) errors after fork()?

I do the regular thing:
fork()
execvp(cmd, ) in child
If execvp fails because no cmd is found, how can I notice this error in parent process?
The well-known self-pipe trick can be adapted for this purpose.
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <sysexits.h>
#include <unistd.h>
int main(int argc, char **argv) {
int pipefds[2];
int count, err;
pid_t child;
if (pipe(pipefds)) {
perror("pipe");
return EX_OSERR;
}
if (fcntl(pipefds[1], F_SETFD, fcntl(pipefds[1], F_GETFD) | FD_CLOEXEC)) {
perror("fcntl");
return EX_OSERR;
}
switch (child = fork()) {
case -1:
perror("fork");
return EX_OSERR;
case 0:
close(pipefds[0]);
execvp(argv[1], argv + 1);
write(pipefds[1], &errno, sizeof(int));
_exit(0);
default:
close(pipefds[1]);
while ((count = read(pipefds[0], &err, sizeof(errno))) == -1)
if (errno != EAGAIN && errno != EINTR) break;
if (count) {
fprintf(stderr, "child's execvp: %s\n", strerror(err));
return EX_UNAVAILABLE;
}
close(pipefds[0]);
puts("waiting for child...");
while (waitpid(child, &err, 0) == -1)
if (errno != EINTR) {
perror("waitpid");
return EX_SOFTWARE;
}
if (WIFEXITED(err))
printf("child exited with %d\n", WEXITSTATUS(err));
else if (WIFSIGNALED(err))
printf("child killed by %d\n", WTERMSIG(err));
}
return err;
}
Here's a complete program.
$ ./a.out foo
child's execvp: No such file or directory
$ (sleep 1 && killall -QUIT sleep &); ./a.out sleep 60
waiting for child...
child killed by 3
$ ./a.out true
waiting for child...
child exited with 0
How this works:
Create a pipe, and make the write endpoint CLOEXEC: it auto-closes when an exec is successfully performed.
In the child, try to exec. If it succeeds, we no longer have control, but the pipe is closed. If it fails, write the failure code to the pipe and exit.
In the parent, try to read from the other pipe endpoint. If read returns zero, then the pipe was closed and the child must have exec successfully. If read returns data, it's the failure code that our child wrote.
You terminate the child (by calling _exit()) and then the parent can notice this (through e.g. waitpid()). For instance, your child could exit with an exit status of -1 to indicate failure to exec. One caveat with this is that it is impossible to tell from your parent whether the child in its original state (i.e. before exec) returned -1 or if it was the newly executed process.
As suggested in the comments below, using an "unusual" return code would be appropriate to make it easier to distinguish between your specific error and one from the exec()'ed program. Common ones are 1, 2, 3 etc. while higher numbers 99, 100, etc. are more unusual. You should keep your numbers below 255 (unsigned) or 127 (signed) to increase portability.
Since waitpid blocks your application (or rather, the thread calling it) you will either need to put it on a background thread or use the signalling mechanism in POSIX to get information about child process termination. See the SIGCHLD signal and the sigaction function to hook up a listener.
You could also do some error checking before forking, such as making sure the executable exists.
If you use something like Glib, there are utility functions to do this, and they come with pretty good error reporting. Take a look at the "spawning processes" section of the manual.
1) Use _exit() not exit() - see http://opengroup.org/onlinepubs/007908775/xsh/vfork.html - NB: applies to fork() as well as vfork().
2) The problem with doing more complicated IPC than the exit status, is that you have a shared memory map, and it's possible to get some nasty state if you do anything too complicated - e.g. in multithreaded code, one of the killed threads (in the child) could have been holding a lock.
Not should you wonder how you can notice it in parent process, but also you should keep in mind that you must notice the error in parent process. That's especially true for multithreaded applications.
After execvp you must place a call to function that terminates the process in any case. You should not call any complex functions that interact with C library (such as stdio), since effects of them may mingle with pthreads of libc functionality of parent process. So you can't print a message with printf() in child process and have to inform parent about the error instead.
The easiest way, among the other, is passing return code. Supply nonzero argument to _exit() function (see note below) you used to terminate the child and then examine the return code in the parent. Here's the example:
int pid, stat;
pid = fork();
if (pid == 0){
// Child process
execvp(cmd);
if (errno == ENOENT)
_exit(-1);
_exit(-2);
}
wait(&stat);
if (!WIFEXITED(stat)) { // Error happened
...
}
Instead of _exit(), you might think of exit() function, but it's incorrect, since this function will do a part of the C-library cleanup that should be done only when parent process terminates. Instead, use _exit() function, that doesn't do such a cleanup.
Well, you could use the wait/waitpid functions in the parent process. You can specify a status variable that holds info about the status of the process that terminated. The downside is that the parent process is blocked until the child process finishes execution.
Anytime exec fails in a subprocess, you should use kill(getpid(),SIGKILL) and the parent should always have a signal handler for SIGCLD and tell the user of the program, in the appropriate way, that the process was not successfully started.