I run my C program on debian-linux ,the program is expected to output
$ ./kill_raise
Child(pid : 4877) is waiting for any signal
Parent kill 4877
but I just got
Parent kill 4877
the string in subprocess (Child(pid : %d) is waiting for any signal) is not print out,why?
and this is my program
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t pid;
int res;
pid = fork();
if (pid < 0)
{
perror ("Fork error\n");
exit(0);
}
if (pid == 0)
{
printf ("child(pid:%d) is waiting for signal\n", getpid());
raise(SIGSTOP);
exit(0);
}
else
{
if ((waitpid(pid, NULL, WNOHANG)) == 0)
{
if ((res = kill(pid, SIGKILL)) == 0)
{
printf ("parent kill %d\n", pid);
}
}
waitpid(pid, NULL, 0);
exit(0);
}
}
You're hitting a race condition. The parent is executing the kill before the child can execute its printf. Remove WNOHANG so the parent actually waits for the child to stop. Also, you need to add WUNTRACED so that waitpid reports the stop (by default, it will only report termination). Finally, you shouldn't be testing wait()'s return value against 0 in this case.
Related
I am trying to check memory leaks on a C program containing child processes using the "leaks -atExit -- ./PROGRAM_NAME" command. Note that the program returns normally when executed on its own. The leaks command fails to return when the program contains the waitpid() function. Why?
Below is a minimal code example that generates the behavior. Thanks for your help.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
if (pid == -1)
{
printf("Fork error\n");
exit(EXIT_FAILURE);
}
if (pid == 0)
{
printf("Hello from the child process\n");
exit(EXIT_SUCCESS);
}
printf("Hello from the parent process\n");
if (waitpid(pid, NULL, 0) == -1)
{
printf("Waitpid error\n");
exit(EXIT_FAILURE);
}
printf("Child process finished\n");
return (0);
}
I would like to check whether / when a child process has terminated in C on Unix. It's not supposed to be blocking, rather a short check in a loop.
My code:
pid_t pid = fork();
if (pid > 0)
// Parent Process
while (1) {
// Do a short check whether Child has already terminated if yes break the loop.
// Ik that it's possible to use waitpid(pid, &status, 0) but that blocks the whole loop until the child has terminated
}
if (pid == 0)
printf("child process born");
exit(0);
Thx in advance
The third argument to waitpid is a set of flags. If you pass WNOHANG to this argument, the function will return immediately if no children have yet exited.
You can then check if waitpid returned 0. If so, no child exited and you wait and try again.
while (1) {
pid_t rval = waitpid(pid, &status, WNOHANG);
if (rval == -1) {
perror("waitpid failed");
exit(1);
} else if (rval == 0) {
sleep(1);
} else {
break;
}
}
Traditional way is:
#include <errno.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
int exist(pid_t pid) {
return kill(pid, 0) > 0 || errno != ESRCH;
}
int main(int ac, char **av) {
while (--ac > 0) {
pid_t p = strtol(*++av, 0, 0);
printf("%d %s\n", p, exist(p) ? "exists" : "doesn't exist");
}
return 0;
}
It doesn't care about parent : child relation (whereas wait derivatives do), and works even if you don't have permission to affect the process.
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main( ) {
pid_t pid;
int status = -1;
if ((pid = fork()) != 0) {
printf("Father process wait child PID=%d\n", pid);
wait(&status);
printf("Child finish with status: %d\n",WEXITSTATUS(status));
exit(0);
}
else {
printf("Child process running...\n");
execl("/bin/ls","ls", "-la", NULL);
printf("Child ending...\n");
}
}
When compiling this code the last line of the else doesn't print and I don't know why.
http://linux.die.net/man/3/execl
The exec() family of functions replaces the current process image with a new process image.
....
Return Value
The exec() functions only return if an error has occurred. The return
value is -1, and errno is set to indicate the error.
This is my code, I had simplified it.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
void signal_handle(int sig)
{
int status;
wait(&status);
}
int main()
{
pid_t pid = fork();
if (pid > 0)
signal(SIGCHLD, signal_handle);
if (pid == 0) {
if (execl("/bin/ls", "/", (char *)0) < 0)
{
perror("execl");
return -1;
}
}
return 0;
}
When I run it, I found that, son process print the run result, but father process
was blocked.
what should I do, if a father has much son process? set wait(&status) for every one?
I'm very sorry for my bad english!
I don't see why the parent process would hang, and it doesn't on my machine.
After the fork(), the parent process invokes signal() to set the signal handler and immediately exits. The child, meanwhile, executes ls to print the contents of the current directory (because the "/" argument becomes argv[0], the program name, and there are no additional arguments). It then exits too. Except under very unlikely circumstances, the parent has exited long before the child completes.
If you want the parent process to wait until it gets the 'death of a child' signal, add a call to pause() in the parent-only execution path:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
static void signal_handle(int sig)
{
int status;
pid_t pid = wait(&status);
printf("%d: signal %d child %d status 0x%.4X\n", (int)getpid(), sig, (int)pid, status);
}
int main(void)
{
pid_t pid = fork();
if (pid > 0)
{
signal(SIGCHLD, signal_handle);
pause();
}
else if (pid == 0)
{
execl("/bin/ls", "ls", "/", (char *)0);
perror("execl");
return -1;
}
else
perror("fork");
return 0;
}
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
void sig_handler(int signal);
int pid, forkFlag = 0;
int main( int argc, char **argv, char **envp )
{
sigset(SIGINT, sig_handler); //handle ctrl + c
sigignore(SIGTSTP);
sigignore(SIGSTOP);
int ex, rv, status;
forkFlag = 1; //fork is being called
pid = fork();
if(pid == -1){
perror("fork");
exit(2);
}
else if (pid == 0){ //if child process
ex = access(argv[0], X_OK); //check if file is executable
if(ex){
perror("access");
exit(1);
}
else{
rv = execve(argv[0], argv, envp); //run program in child process
if(rv == -1){
perror("execve");
exit(1);
}
}
exit(0); //end child process
}
else{
rv = waitpid(pid, &status, 0); //wait for child
if(rv == -1){
perror("waitpid");
}
if(WEXITSTATUS(status)){ //check status of child if it did ot return 0
printf("The return status of the child was %d\n", WEXITSTATUS(status));
}
}
forkFlag=0;
}
void sig_handler(int signal)
{
if(signal == SIGINT && (pid && forkFlag)){
kill(pid,signal); //send kill to child
}
}
I'm trying to make my program ignore ctrl + C, except when there is a child process running, then it sends the the SIGINT to the child process. However, when I press ctrl + c when the child process is running, waitpid() returns -1 with the error "Interrupted System Call." This makes the child process stop running, but if I use ps, the child process is still there, but now labeled as defunct. I know from printf statements that kill is being calle din the function sig_handler, and that pid and forkFlag are their correct values. Is waitpid() making my program ignore the kill? How do I fix this? I know this code does next to nothing, but it's a small portion of my code (the only part involving fork)
Thanks for any help.
The problem is that the child processes get the same overridden handler for SIGINT. You probably want to reset the signal handler in the child process after the fork, or you might want to install the signal handler in the parent after you've already forked the child, so it doesn't inherit the overriden handler.