I'm currently trying to:
Execute a background process with a fork() call and execvp() inside the children.
If the call to execvp() was successful, adding the PID of the child process to a list.
If the call to execvp() returned -1 (error), do not add the PID to the list.
My problem is: if execvp() returns -1 (for instance, if the executable isn't found) I can't "communicate" with the parent proccess since I'm inside the child process in the fork(). And if I use waitpid() to wait for the child, I'm not running a background process (since I lose the concurrency).
I tried using WNOHANG and checking *status with (WEXITSTATUS(status) == 1) but it doesn't work (since the parent process executes "instantly" and doesn't know if the child has exited yet, or that's what I think)
My current code:
void background(char *vector[]) {
pid_t childp;
int status;
childp=fork();
if (childp==-1){
perror("Error using fork \n");
return;
}
if (childp==0) { //Child process
if (execvp(vector[0],vector)==-1) {
perror("exec");
exit(1);
}
}
waitpid(-1, &status, WNOHANG);
if(WIFEXITED(status)) {
//Child exited
if (WEXITSTATUS(status) == 1) {
//Child exited with error
return;
}
}
if (insertProcess(childp,vector)==-1)
perror("Full list");
else
updateList();
}
The only solution I've found at the moment is inserting a sleep(1) call before waitpid (Source: https://stackoverflow.com/a/26617152/1339354 ), but this looks more like a hack than something well done. Any other ideas?
If you are using waitpid() with WNOHANG, be sure to especify the child process. If you don't, waitpid() returns status of the last child dead.
I'm not sure if you are trying to save on a list all process that was success. If you are trying it, why not instert always and then delete the process when they die? Control the signal SIGCHLD. In that, use the waitpid for look what process died and delete it in the list. Just deactivate the signal SIGCHLD when you create the process, insert the process on the list and then active again the signal.
Related
I'm trying to run a series of commands through execv() and forking a new process in C to run each one, and yet for some reason they aren't running in parallel. The following code is run for each process, with "full" being the filepath and "args" being the arguments. I know that the execv() part isn't the issue, it has to do with the way I'm forking and waiting.
int status;
pid_t pid = fork();
if (pid == 0) {
execv(full, args);
//perror("execv");
} else if (pid < 0) {
printf("%s\n", "Failed to fork");
status = -1;
} else {
if (waitpid(pid, &status, 0) != pid) {
status = -1;
return status;
}
}
When running this code, the forked commands simply run one after the other. I don't know how this could be happening.
If you don't want to wait for each child process, don't call waitpid immediately; as written, you fork a child, then immediately stop all processing in the parent until the child process exits, preventing you from forking any further children. If you want to launch multiple children without leaving zombie processes lying around (and possibly monitoring them all at some point to figure out their exit status), you can do one of:
Store off the pids from each fork in an array, and call waitpid on them one by one after you've launched all the processes you need to launch
Store a count of successfully launched child processes and call wait that many times to wait on them in whatever order they complete.
Ignore the SIGCHLD from the child processes entirely, for when you don't care when they exit, don't need to know their status, etc.
In my program I am forking (in parallel) child processes in a finite while loop and doing exec on each of them. I want the parent process to resume execution (the point after this while loop ) only after all children have terminated. How should I do that?
i have tried several approaches. In one approach, I made parent pause after while loop and sent some condition from SIGCHLD handler only when waitpid returned error ECHILD(no child remaining) but the problem I am facing in this approach is even before parent has finished forking all processes, retStat becomes -1
void sigchld_handler(int signo) {
pid_t pid;
while((pid= waitpid(-1,NULL,WNOHANG)) > 0);
if(errno == ECHILD) {
retStat = -1;
}
}
**//parent process code**
retStat = 1;
while(some condition) {
do fork(and exec);
}
while(retStat > 0)
pause();
//This is the point where I want execution to resumed only when all children have finished
Instead of calling waitpid in the signal handler, why not create a loop after you have forked all the processes as follows:
while (pid = waitpid(-1, NULL, 0)) {
if (errno == ECHILD) {
break;
}
}
The program should hang in the loop until there are no more children. Then it will fall out and the program will continue. As an additional bonus, the loop will block on waitpid while children are running, so you don't need a busy loop while you wait.
You could also use wait(NULL) which should be equivalent to waitpid(-1, NULL, 0). If there's nothing else you need to do in SIGCHLD, you can set it to SIG_DFL.
I think you should use the waitpid() call. It allows you to wait for "any child process", so if you do that the proper number of times, you should be golden.
If that fails (not sure about the guarantees), you could do the brute-force approach sitting in a loop, doing a waitpid() with the NOHANG option on each of your child PIDs, and then delaying for a while before doing it again.
I have simple C program which executes an application using fork() and execl(). If execl() fails to run the application, then I have to call a function in the parent process and exit from the child process. If execl() successfully runs the application, then I have show a success log from the parent process. So, parent process should wait for the child's execl() call (just the call, not till the end of execution of the application), get some information about it status, and then make decisions and continue its own execution. Here is my code.
int main()
{
int iExecRetVal, pid;
pid = fork();
if (pid == -1)
{
}
else if (pid > 0)
{
}
else
{
iExecRetVal = execl("./flute-static", "./flute-static", "-send", "-a192.168.190.1/6666", "JFlute.1.2.tar.gz", NULL);
if (iExecRetVal == -1)
{
/*execl() failed, need some error handling in the parent process*/
}
_exit(0);
}
/*Parent's normal execution*/
}
int HandleSuccessFromParent()
{
/*Should be called when exec call was successful*/
}
int HandleFailureFromParent()
{
/*Should be called when exec call was NOT successful*/
}
We know execl() does not return on success. So, how to call HandleSuccessFromParent() and HandleFailureFromParent() functions properly after the execl() call in the child. Please help me.
The child process needs to exit with an error status (non-zero; 1 is common, EXIT_FAILURE is standard C).
The parent process needs to wait for the child to finish, and capture the child's exit status, using wait() or
waitpid().
If you need to know whether the child died but don't want to wait for it to complete, use waitpid() with WNOHANG after a small pause to let the child try and run (a sub-second delay is likely to be long enough).
One possible solution involves ptrace. The outline is as follows:
Let the child call ptrace(PTRACE_TRACEME). Let the parent enable PTRACE_O_TRACEEXEC option and waitpid on the child. In this setup waitpid would return upon successful execl. Test the status to see if it has a SIGTRAP flag set. Let the child continue with PTRACE_DETACH.
In the below code, if there is a problem creating a child process or something happens to the child process what happens to wait(&status)?
pid_t pid;
int status;
if(pid=fork()){
printf("Parent Process\n");
wait(&status);
} else... child process here
If there is a problem creating a child process, fork will return -1, so this code will never wait.
If there's something happend to the child process, wait will return, and you can observe status.
If the child cannot be created, fork() will return with -1, you should look at errno after that. No error process is created here. Your code does not check this case.
If the child is created and dies, wait() will return the PID of the terminated process, the reason for the child's death is given in status. See the man page for wait on how to extract meaning from status.
So basically what i need is:
pid = fork();
if (pid == -1)
exit(1);
if (pid == 0)
{
// do stuff in child
}
else
{
// ONLY do stuff while child is running
}
would I need to create a tmp file right before the child exits saying that it is no longer running so the parent knows the child has exited when that file exists, or is there a simpler way to do this?
You can use waitpid to know if a child process is still running:
int status;
if (waitpid(pid, &status, WNOHANG) == 0) {
// still running
}
With WNOHANG, waitpid returns immediately so that the program can do something else.
When you have nothing to do other than waiting for the child process to terminate, call waitpid without WNOHANG.
The standard way to know that the child has terminated (and get its exit code) is to use the waitpid() system call.
Check wait () and waitpid () : http://linux.die.net/man/2/wait
Here is some more resource: http://users.actcom.co.il/~choo/lupg/tutorials/multi-process/multi-process.html#child_death_wait_syscall
There's a bunch of ways to do it. If you don't need to do anything with the child output, you can set a SIGCHLD handler to reap the child when it exits, and then forget about it in your main thread of execution. You can use the SIGCHLD handler to flag the exit of the child process via an IPC mechanism.
Or you can add a while loop that checks waitpid in your else clause. You would be doing discrete units of work between polls of the child state and you wouldn't get interrupted immediately on child exit.
Use the system wait() call if you just need to check if the child has stopped running.
int pid;
int status;
while (true)
{
pid = wait(&status);
if (pid < 0)
//keep waiting
else if (pid == 0)
//child is done
}