Cannot detect if child process has been killed - c++

I been reading a countless time on stackoverflow that to determine if a process is running, one should use kill(pid,0) but I cant make it work
here is my code, , it cannot detect when the child process has been killed and I dont understand why
(sorry for the ident, but hte code escaping on stackoverflow is just a pain for long pieces of codes)
#include <sys/signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int main()
{
int pid = fork();
if (pid < 0)
{
printf("Forking failed\n");
}
else if (pid == 0) // child process
{
do
{
printf("child process\n");
sleep(1);
}while(1);
//execvp("ls", NULL); //launches the application
}
else //parent process
{
printf("parent process\n");
for(int i=0;i<10;i++)
{
if(i==5)
kill(pid,SIGTERM); //kills the child process
if(kill(pid, 0) == 0)
printf("process child %d is runnig\n",pid);
else if(kill(pid, 0) == -1)
{
switch(errno)
{
case ESRCH: printf("process child %d is not runnig\n",pid); break;
case EPERM: printf("process child %d cannot be killed\n",pid); break;
default: printf("%s\n",strerror(errno)); break;
}
}
sleep(1);
}
}
}
here is the output
parent process
process child 1918 is runnig
child process
process child 1918 is runnig
child process
process child 1918 is runnig
child process
process child 1918 is runnig
child process
process child 1918 is runnig
child process
process child 1918 is runnig
process child 1918 is runnig
process child 1918 is runnig
process child 1918 is runnig
process child 1918 is runnig

Until the killed child process gets reaped by wait(), its PID is still valid, and kill(pid, 0); will succeed, since the PID exists. Your code attempts to kill() the child process, but fails to wait() for it.
Note that even in the best case, kill(pid, 0); is not reliable. With only 32766 different PIDs, it doesn't take long before process IDs get recycled.

alright I finaly figured it out
kill(pid,SIGTERM); //kills the child process
do
{
pid = waitpid(-1, NULL, WNOHANG);
if(pid == 0)
sleep(1);
}while(pid<=0);

Related

waitPID function not checking if the child process exited

I am unable to get the waitPid to tell me if the child process exited or not.
In the parent process this is what I am doing:
if (forkID != 0) {
pid_t result = waitpid(forkID, &status, WNOHANG);
if (result == 0) {
// Child still alive
std::cout<<"Child Alive"<<std::endl;
} else if (result == -1) {
// Error
std::cout<<"Error"<<std::endl;
} else {
// Child exited
std::cout<<"Child Exited"<<std::endl;
}
DriverParser P;
while (!std::cin.eof()) {
std::string line;
std::getline(std::cin, line);
arguments = P.BeginParsing(line);
if (arguments.size() > 0) {
for (int k = 0; k < 4; k++) {
finalArguments[k] = arguments[k];
}
close(fd[0]);
write(fd[1],finalArguments,4*sizeof(int));
close(fd[1]);
}
}
// pid = wait(&status);
// std::cout<<waitpid(forkID, &status, 0)<<std::endl;
}else if (forkID == 0) {
// child: reading only, so close the write-descriptor
std::cout<<"I am child process my PID is: "<<getpid()<<std::endl;
execv("./a.out", argList);
// close the read-descriptor
close(fd[0]);
}
I am basically sending the result of the parser as it reads from the stdin via pipe to child process, and then executing a process in execv. Now when this program exits using exit(0) - I am not seeing Child Exited on the terminal which means the waitpid is essentially not working for me.
What should I do?
You are calling waitpid with WNOHANG:
pid_t result = waitpid(forkID, &status, WNOHANG);
I shared with you the documentation, which says:
If WNOHANG was specified in options and there were no children in a waitable state, then waitid() returns 0 immediately and the state of the siginfo_t structure pointed to by infop is unspecified. To distinguish this case from that where a child was in a waitable state, zero out the si_pid field before the call and check for a nonzero value in this field after the call returns.
It also says:
WNOHANG
return immediately if no child has exited.
Considering that the call to waitpid happens immediately after fork, the chances are that the child is still running.
If you want to wait for the child process to end, just remove the WNOHANG option (pass 0 instead):
pid_t result = waitpid(forkID, &status, 0);

Wait for child process to terminate when using waitpid

Here is my example code
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
id_t pid;
void handle_sigterm(int sig)
{
printf("handle me \n");
}
void forkexample()
{
// child process because return value zero
pid = fork();
int status = 0;
if (pid == 0)
{
printf("Hello from Child!\n");
char *newargv[] = { "test2", NULL };
char *newenviron[] = { NULL };
newargv[0] = "test2";
execve("test2", newargv, newenviron);
printf("error -> %d", errno);
fflush(stdout);
}
// parent process because return value non-zero.
else
{
struct sigaction psa;
psa.sa_handler = handle_sigterm;
sigaction(SIGTERM, &psa, NULL);
printf("Hello from Parent!\n");
fflush(stdout);
int result = waitpid(pid, &status, 0);
printf("result -> %d\n", result);
fflush(stdout);
}
}
int main()
{
printf("pid -> %d\n", getpid());
forkexample();
return 0;
}
test2 is just a while(true). Lets say both parent and child process receive SIGTERM at the time, how can I make parent process wait until child process terminates and then exit? I've read from documentation that:
The wait() function shall cause the calling thread to become blocked
until status information
generated by child process termination is made available to the thread, or until delivery of a
signal whose action is either to execute a signal-catching function or to terminate the process
So it means that when SIGTERM is received in parent, it exits the wait() and the process is killed. But I want it to wait until child terminates and then exit. How can I achieve that?
You can use waitpid() to wait for the child inside signal handler of parent also. This does make sure that parent will wait for child even though it receives signal. Some advices are as below.
Why do you think it is a C++ program?
signal handler name you set for sa_handler is wrong. handle_sigint()
is not defined.

Hung parent while reading stderr from child process through pipe in C++

I fork a child process which in turn spawns a grand-child process and returns. If there are any errors in spawning that grand-child, the child writes to stderr using fprintf statements and exits.
I am trying to read stderr from the child process in the parent. But, the parent gets hung in the while loop reading from child process. When I look at ps -ef the child is <defunct>.
Following is the code I wrote to accomplish this. I am new to this and the search on web does not give enough information about why the parent is hung when the child is
int pipe_out[2];
// Create the pipe
if (pipe(pipe_out) < 0) {
perror("Failed pipe");
exit(1);
}
// Create the child process
int status;
pid_t pid = fork();
switch(pid) {
case -1:
perror("Failed fork");
exit(1);
case 0: { // Child
close(pipe_out[0]); // close read end
// Make stderr go to pipe write end
dup2(pipe_out[1], STDERR_FILENO);
close(pipe_out[1]);
// start my process
execvp(inp_args[0], inp_args);
_exit(EXIT_FAILURE);
break;
}
default: { // Parent
close(pipe_out[1]); // close write end
// read from child
while( read(pipe_out[0], buffer, sizeof(buffer)) )
log(stdout, "%s\n",buffer);
}
// wait for end then close other end of pipe
waitpid(pid, &status, 0);
if (WIFSIGNALED(status))
log(stdout, "killed by signal %d\n", WTERMSIG(status));
close(pipe_out[0]);
}
}

Exec after forking a process doesn't return the result before the program finishes

I'm trying to make a program that forks once and while the parent waits for the child terminates, this child forks again and then executes two execs. There is a Pipe on the program and I've checked the return values of every dup2() and pipe() on the program -just omitted them here to make it looks more concise-. The problem is that I only get the result of ls -a | sort -r AFTER the program finishes.
The code is:
#include <cstdio>
#include <cstring>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int main(int argc, char *argv[]) {
printf("Shell> \n"); fflush(stdout);
pid_t pid1;
pid_t pid2;
int status = 0;
int fd[2];
if(pipe(fd) < 0) {
printf("FATAL ERROR.\n");
}
pid1 = fork();
if(pid1 > 0) { // Parent
waitpid(pid1, &status, 0);
printf("\t\t------PID1 Complete-------\n\n");
}
else { // Child
if(pid1 == 0) {
printf("ON CHILD\n");
pid2 = fork();
if(pid2 > 0) { // Child -> Parent
printf("ON CHILD-Parent\n");
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
waitpid(pid2, &status, 0);
printf("ON CHILD-Parent after wait\n");
execlp("sort", "sort", "-r", NULL);
perror("Problem with execlp\n");
exit(1);
}
else { // Child -> Child
printf("ON CHILD->Child\n");
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
execlp("ls", "ls", "-a", NULL);
perror("Problem with execvp\n");
exit(1);
}
} // End of if(pid1 == 0)
} // End of Child
printf("\nEnd of program.\n");
return 0;
}
My current output is:
Shell>
ON CHILD
ON CHILD-Parent
ON CHILD->Child
ON CHILD-Parent after wait
I think the problem is on the waits, but I just can't figure out how to make this work. Any ideas? Thanks!
The problem is that you call pipe in the grandparent process. After the grandchild process (ls -a) exits, the parent process (sort -r) blocks indefinitely waiting to read more input from the pipe since some process - the grandparent - holds an open descriptor to the write end of the pipe.
If you close the pipe descriptors in the grandparent process, or better yet move the pipe call into the first forked process, then the sort process will terminate when the last process with an open descriptor for the write end of the pipe exits (DEMO):
int main() {
// Turn off buffering of stdout, to help with debugging
setvbuf(stdout, NULL, _IONBF, 0);
printf("Shell> \n");
pid_t pid1 = fork();
if(pid1 < 0) {
perror("fork failed");
}
if(pid1 > 0) { // Parent
int status;
waitpid(pid1, &status, 0);
printf("\t\t------PID1 Complete (%d) -------\n\n", status);
} else { // Child
printf("ON CHILD\n");
int fd[2];
if(pipe(fd) < 0) {
perror("pipe failed");
return 1;
}
pid_t pid2 = fork();
if(pid2 < 0) {
perror("fork failed");
}
if(pid2 > 0) { // Child -> Parent
printf("ON CHILD-Parent\n");
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
execlp("sort", "sort", "-r", NULL);
perror("Problem with execlp");
return 1;
} else { // Child -> Child
printf("ON CHILD->Child\n");
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
execlp("ls", "ls", "-a", NULL);
perror("Problem with execvp");
return 1;
}
}
printf("\nEnd of program.\n");
}
The other problem with the program is the one #nategoose commented on: the call to waitpid could lead to a deadlock if the output of "ls -a" is too large to fit in the pipe's buffer. There's no reason to wait, so it should simply be eliminated.
This isn't a real answer, but I have some into that I'd like to share.
To make sure that your output comes out in the order that it should, I'm flushing a lot more than you were. Remember that when you are calling functions like fork(), clone(), vfork(), dup(), dup2(), close(), or any of the exec() family of functions you are doing stuff that is BELOW the C runtime environment, which includes stdio. If you do:
printf("cat");
fork();
fflush(stdout);
You are very likely to get:
catcat
as your output because you've duplicated the stdout structure, including all buffered data, so unless stdio decided that it was time to flush anyway before the end of the printf function, then "cat" is in each process's stdout buffer.
There's also the fact that since data can stay buffered when you run a function in the exec family your data may not be flushed before your program is replaced with the new program. When your program is replaced by ls or sort then any data pending in stdout gets lost forever.
Also, when you use dup you have the another issue since you are swapping the file descriptor out from under stdio so it may not have flushed yet and the data may end up getting flushed to the new file after the dup.
Because of these things you should have a lot more calls to fflush, but I don't think that's your problem here.

How do I get the return value of a execv?

I am really new to C++ and I am trying to get the output from:
execv("./rdesktop",NULL);
I am programming in C++ and on RHEL 6.
Like a FTP client, I would like to get all the status updates from my external running program. Can someone please tell me how I could do this?
execv replaces the current process, so immediately after executing it what's executing will be whatever executable you specified.
Normally you do a fork, and then execv only in the child process. The parent process receives the PID of the new child, which it can use to monitor the child's execution.
You can examine the exit status of a child process by calling wait, waitpid, wait3 or wait4.
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main () {
pid_t pid = fork();
switch(pid) {
case 0:
// We are the child process
execl("/bin/ls", "ls", NULL);
// If we get here, something is wrong.
perror("/bin/ls");
exit(255);
default:
// We are the parent process
{
int status;
if( waitpid(pid, &status, 0) < 0 ) {
perror("wait");
exit(254);
}
if(WIFEXITED(status)) {
printf("Process %d returned %d\n", pid, WEXITSTATUS(status));
exit(WEXITSTATUS(status));
}
if(WIFSIGNALED(status)) {
printf("Process %d killed: signal %d%s\n",
pid, WTERMSIG(status),
WCOREDUMP(status) ? " - core dumped" : "");
exit(1);
}
}
case -1:
// fork failed
perror("fork");
exit(1);
}
}