Wrong status during using waitpid with WHOHANG - c

I want to know, when my child process is exiting. But I don't want to block my application, so I use WNOHANG.
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void handler(int nsig) {
int status;
waitpid(-1, &status, WNOHANG);
printf("nsig=%i; status=%i\n", nsig, status);
if (WIFEXITED(status)) {
printf("Exited\n");
}
}
int main() {
struct sigaction act;
act.sa_handler = handler;
if (sigaction(SIGCHLD, &act, 0) < 0) {
fprintf(stderr, "sigaction failed\n");
exit(-1);
}
pid_t fpid;
fpid = fork();
if (fpid == 0) {
execlp("okular", "okular", 0);
}
while(1);
return 0;
}
It works fine if I close "okular" as usual.
$ ./test
nsig=17; status=0
Exited
But if I do something like
kill -STOP OKULAR_PID
I have the same output and that's wrong for me, because okular didn't exit in fact.

I think it is right, because SIGCHLD is defined as Child terminated or stopped as can be seen in this man page for signal. SIGCLD is a synonym for SIGCHLD.

Related

Child not Responding

Hello I'm having issues with sending signals from the father process to the child process. The Child doesn't respond to the signed sent by the father process:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
if(pid > 0) {
printf("Hello, my son!\n");
sleep(5); /* Sleep for 5 seconds... */
kill(pid, SIGUSR1);
printf("Goodbye, son!\n");
}
else {
printf("Son is running\n");
pause(); /* Wait for some signal... */
printf("I received the signal!");
}
}
The son doesn't received the signal it only says it's running here is the output:
output
The default behavior when SIGUSR1 is received is termination, so the child never prints the message. To handle the signal, you can use sigaction:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
void handle(int sig, siginfo_t *i, void *v) { return; }
int
main(void)
{
pid_t pid = fork();
if( pid > 0 ){
printf("Hello, my child!\n");
sleep(1); /* Sleep for 1 second. */
kill(pid, SIGUSR1);
printf("Goodbye, child!\n");
} else {
struct sigaction act;
memset(&act, 0, sizeof act);
act.sa_sigaction = handle;
if( sigaction( SIGUSR1, &act, NULL ) ){
perror("sigaction");
exit(1);
}
printf("Child is running\n");
pause(); /* Wait for some signal... */
printf("I received the signal!\n");
}
}

Is there a way to execute code in the parent process after the child, which is created using fork and execl?

I am having a parent process play that creates a fork and runs foo using execl
Code for play.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
if (fork() == 0) {
execl("./foo", "", NULL);
} else {
wait(0);
write(STDOUT_FILENO, "in parent after waiting", 5);
}
printf("outside everything");
return 0;
}
Code for foo.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void signal_handler() {
write(STDOUT_FILENO, "\nBye!\n", 6);
exit(1);
}
int main() {
struct sigaction sa;
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, NULL);
while (1) {
printf("Wasting time...%d \n", getpid());
sleep(1);
}
return 0;
}
My questions are,
Why aren't the print statements after the wait(0) statement executed?
Why isn't the signal handler in the child process triggered when Ctrl + C?
You should ensure that the sa_flags and sa_mask fields of struct sigaction are set. You can initialize them — struct sigaction sa = { 0 }; will probably do the job. Or you can use sigemptyset(&sa.sa_mask); and sa.sa_flags = 0; to assign values. Or you can set them to some non-zero value. Not setting sa_flags means you've no idea what operation you requested. You also need a signal handler in play.c. You need to ignore SIGINT before the fork(), then in the child re-enable the signal before executing foo. The write() in the parent does not print much; it may once have printed "\nBar!\n" or something.
Here's some working code.
play.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
struct sigaction sa = { 0 };
sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &sa, NULL);
if (fork() == 0)
{
sa.sa_handler = SIG_DFL;
sigaction(SIGINT, &sa, NULL);
execl("./foo", "", NULL);
exit(1);
}
else
{
wait(0);
printf("in parent after waiting\n");
}
printf("outside everything\n");
return 0;
}
foo.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void signal_handler(int signum)
{
char message[] = "\nBye (XX)\n";
message[6] = signum / 10 + '0';
message[7] = signum % 10 + '0';
write(STDOUT_FILENO, message, sizeof(message) - 1);
exit(1);
}
int main(void)
{
struct sigaction sa = { 0 };
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, NULL);
while (1)
{
printf("Wasting time...%d \n", getpid());
sleep(1);
}
return 0;
}
Example output
$ play
Wasting time...11383
Wasting time...11383
Wasting time...11383
Wasting time...11383
^C
Bye (02)
in parent after waiting
outside everything
$

Process dies after SIGINT signal

I don't understand what is happening here, I have a parent process which handles the SIGINT signal and then makes a child. What I expect when I press Ctrl+C is that both processes will print "SIGINT received" and then continue but it turns out that the parent process dies after receiving SIGINT but the child is still there. I can't understand that.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <string.h>
void handler (int sig) {
printf("SIGINT received\n");
}
void child() {
while (1) {
printf("I'm the child\n");
sleep(1);
}
exit(0);
}
int main(int argc, char *argv[]) {
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = &handler;
// Link SIGINT with the handler
sigaction(SIGINT, &act, NULL);
// Create child
if (fork() == 0) child();
wait(NULL);
return 0;
}
An example of execution:
$ ./test_signals
I'm the child
^CSIGINT received
I'm the child
SIGINT received
$ I'm the child
I'm the child
So both processes handle SIGINT but the parent dies while the child continues...
The parent process is blocked in the main function and upon receiving the signal, handles it and returns from the call to wait with an error.
The child is just looping in the while handling SIGINT. When handled code returns where it was (probably blocked in sleep) and it continues to loop.
That code may illustrates what happens:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <string.h>
#include <sys/errno.h>
void handler (int sig) {
printf("SIGINT received %d\n",getpid());
}
void child() {
while (1) {
printf("I'm the child\n");
sleep(1);
}
exit(0);
}
int main(int argc, char *argv[]) {
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = &handler;
// Link SIGINT with the handler
sigaction(SIGINT, &act, NULL);
// Create child
if (fork() == 0) child();
int r = wait(NULL);
if (r==-1 && errno==EINTR) printf("signal probably received in parent\n");
return 0;
}
Be aware that calling printf in a signal handler is forbidden.

signal handling on background process and file output

I have been considering the following code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
FILE* file;
void signal_handler(int _signal) {
switch(_signal){
case SIGTERM:
fprintf(file, "Ouch, the Daemon Child was killed!\n");
fflush(file);
abort();
default:
fprintf(file, "So what?!\n");
fflush(file);
}
}
int main() {
pid_t pid;
int status;
pid = fork();
if(pid != 0) {
// parent
waitpid(pid, &status, WNOHANG); // daemonize the child
} else {
// child
signal(SIGTERM, signal_handler);
file = fopen("daemon.txt", "w");
while(1) {
sleep(1);
fprintf(file, "Daemon child is alive.\n");
fflush(file);
}
}
return 0;
}
and I expected I could find at the end of daemon.txt the string Ouch, the Daemon Child was killed!, after sudo kill -KILL . However, this is not the case. Where is my fault?
You appear to be catching SIGTERM, and then sending SIGKILL, which you do not have a handler for. You will probably see your expected output if you use kill -TERM $pid rather than kill -KILL.

In c, linux , about kill and raise

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.

Resources