Child process still does not run after receiving signal - c

The code is one of the answers to this question.
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void
sigusr1( int pidno )
{
fprintf(stderr, "Caught\n");
}
int
main()
{
pid_t pid;
signal( SIGINT, sigusr1 );
if( (pid = fork()) == 0 ){
pause();
fprintf(stderr, "Child\n");
}
else
{
fprintf(stderr, "Parent\n");
kill( pid , SIGINT ); //parent sends signal to child
}
pause();
return 0;
}
The child waits for a signal, and after receiving it continues execution.
Running it I get
Parent
Caught
It seems that the child does not runs after receiving the signal. Pressing Ctrl+c:
Parent
Caught
^CCaught
Caught
Child
Can somebody explain me what is happening here?

pause() gets invoked after the signal has been received and handled by the child. Unfortunately, pause() easily introduces this kind of race condition:
time you parent child
---- --- ------ -----
0 signal(SIGINT,handler)
1 fork() (hello)
2 print("Parent") (waking up)
3 kill(..., SIGINT) <<SIGINT>> # RACE kill v pause
4 handler: print("Caught")
5 pause() pause()
6 ^C <<SIGINT>> <<SIGINT>>
7 handler: print("Caught") handler: print("Caught")
8 exit pause()
9 (still running)
To check what exactly goes on, try adding %i, getpid() to printfs, and maybe also one more printf() before the pause() call in the child branch.
sigsuspend() and explicit signal masking might be a better choice here.

Related

Child doesn't continue running after receiving signal using pause()

...
signal( SIGUSR1, sigusr);
bla = 0;
for(;;)
{
if(pid=fork()==0)
{
fprintf(stderr,"Child %d: Waiting in queue.\n",getpid());
pause();
fprintf(stderr,"im here"); //can't get to this line
kill(deque(q),SIGUSR1)
_exit(0);
}
else
{
sem_wait(&q2);
enque(q,pid);
sem_post(&q2);
if(!bla)
{
bla=1;
sem_wait(&q2);
kill(deque(q),SIGUSR1);
sem_post(&q2);
}
sleep(n);
}
}
...
void sigusr()
{
signal(SIGUSR1, sigusr);
fprintf(stderr, "Child %d: Got it.\n", getpid());
}
Child doesn't continue running after receiving signal using pause(), parent send signal to the first child, I get output "Got it." but can't get pass pause();. after the parent send the signal, the first child needs to send signal to the next child.. etc...
The expression pid=fork()==0 does not work as you expect it to. It assigns the valie of fork() == 0 to the variable pid, because of the operator precedence for equality is higher than for assignment.
That means that pid will be either 0 or 1, neither a correct process identifier.
Change to (pid = fork()) == 0 instead.
In addition to pid=fork()==0 there is a race condition, the child may receive the signal before the call to pause(), and then wait for another signal in pause().
To avoid this problem:
Block the signal using sigprocmask.
Check if is appropriate to wait.
Wait for the signal using sigsuspend.
Unblock the signal.

How to know which signals are passed when the orphand process created?

I read when the parent process terminates before the child execute that time the child process will send the SIGHUP and SIGCONT signal. then this will work under the init process.
so i want to know child process generate a signal or not?
for that i work out the program like this, but i didn't receive any messages like signal received.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
void handler(int signo)
{
if(signo == SIGHUP)
printf("SIGHUP present\n");
else if (signo == SIGCONT)
printf("SIGCONT present\n");
}
main()
{
pid_t pid;
signal(SIGCONT,handler);
signal(SIGHUP,handler);
if((pid=fork()) == 0)
{
sleep(5);
printf("Child terminated\n");
exit(0);
}
exit(0);
}
The child is not notified by signal if the parent dies.
The parent receives SIGCHLD if a child dies.
As I know, the signal handler works when the process (which registers the handler) receives any signal and not the other way around.
In your case, if the parent process or the child process receives any signal then the handler will be called.
Since here the child process is itself generating the signal (as you said, I have not read about this yet), the handler will not called.
Correct me if I am wrong.

pthreads and signal handling C ending early

This program is supposed to
The parent simply waits indefinitely for any child to return (hint, waitpid).
b. The child sets up two signal handlers (hint, signal) and goes to sleep for 5 minutes.
i. The first signal handler listens for the USR1 signal, and upon receiving it:
1. Creates a thread (hint, pthread_create).
a. Basically, all that the thread needs to do is “say hello” and sleep for 60
seconds.
ii. The second signal handler listens for the USR2 signal, and upon receiving it:
1. Destroys the thread (hint, pthread_cancel).
When this program receives the first signal to create the thread, it outputs
"[thread] sleeping for 1 m[thread] sleeping for 1 minute"
and then ends, it never waits for the 2nd signal, what am i doing wrong?
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
pthread_t thread;
void* temp()
{
printf("[thread] hello professor\n");
printf("[thread] sleeping for 1 minute\n");
sleep(60);
}
void handle_USR1(int x)
{
int s;
printf("[signal] creating the thread\n");
s = pthread_create(&thread, NULL, &temp, NULL);
}
void handle_USR2(int x)
{
int s;
printf("[signal] destroying the thread\n");
s = pthread_cancel(thread);
}
int main(void)
{
int status = 0;
if(fork() != 0)
{
printf("[parent] waiting.....\n");
waitpid(-1, &status, 0);
}
else
{
printf("[child] to create the thread: kill -USR1 %d\n", getpid());
printf("[child] to end the thread: kill -USR2 %d\n", getpid());
printf("[child] setting up signal handlers\n");
signal(SIGUSR1, handle_USR1);
signal(SIGUSR2, handle_USR2);
printf("[child] waiting for signals\n");
sleep(300);
}
return (0);
}
As Charlie Burns pointed out, both processes eventually exit as a consequence of the signal, but for different reasons.
Child
During its sleep, the child is blocked in a system call (the actual system call is nanosleep, used to implement the sleep() function). When a process receives a signal while in a system call, the corresponding signal handler is executed and the system call returns an error, EINTR, which means it has been interrupted and couldn't fulfill its duty. You can then decide if you want to restart the system call or not. Upon receiving SIGUSR1, the nanosleep system call executed by the child is interrupted, the handler is executed and sleep() returns immediately. Notice what man 3 sleep says about the return value of sleep():
Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was interrupted by a signal handler.
The correct way would be for the child to check for the return value of sleep (number of seconds left to sleep), and sleep again for that duration.
Parent
Unlike what Charlie Burns pointed out, waitpid() in the parent does not return because of the child receiving a signal. It returns because of the child exiting. It would return because of the child IF the child did not handle the signal, and thus was killed by it (an unhandled signal causes the process to die). You can (and should) check that using the WIFEXITED macro and its companions as described in man 2 waitpid. The example at the bottom of this man page is very good:
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
Basically, what this code does is wait on the child until it has exited normally or has exited because of an unhandled signal. In your case, it would be a good idea for the parent to check the status variable to make sure that waitpid returned because of the event it expects (a child exiting) and not something else.
Place a pthread_join after your pthread_create.
Ok, I see what is going on.
When you send a signal, without otherwise directing it to a particular thread by masking, any thread within a process can get it. When SIGUSR1 gets delivered main in the child gets blown out of the sleep and the main thread terminates killing the thread created in the handler.
There are plenty of questions here covering how to direct signals to a single thread and/or using sigaction to restart a system call if that is also a direction you want to go in to resolve it.

Understanding SIGCHLD when the child process terminates

I am not able to understand the output for the following program. I observed that after the child process returns, parent process is not sleeping for 3 sec before wait(). If SIGCHLD is set to default handler, then it sleeping for 3 sec, calling wait and returning as expected. What is exactly happening here ??
# include <unistd.h>
# include <sys/types.h>
# include <stdio.h>
# include <sys/wait.h>
# include <signal.h>
void handler(int sig) {
printf("Iam in handler ...\n");
}
main() {
int status;
pid_t pid;
struct sigaction act;
//act.sa_flags=SA_NOCLDSTOP;
act.sa_handler=handler;
sigaction(SIGCHLD,&act,NULL);
if(!fork()) {
printf("child process id is %d\n",getpid());
return 1;
}
printf("xxx ...\n");
sleep(3);
pid = wait(&status);
printf("process terminated is %d\n",pid);
}
output::
xxx ...
child process id is 2445
Iam in handler ...
process terminated is 2445
From the man for sleep():
sleep() makes the calling thread sleep until seconds seconds have elapsed or a signal arrives which is not ignored.
Your child terminating causes a signal to wake you up.
The return value from sleep():
Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was interrupted by a signal handler.
Can be used if you'd like to help you "finish" the sleep.
unsigned sleep_time = 3;
...
while((sleep_time = sleep(sleep_time)) > 0) {}
pid = wait(&status);
...
When the child process dies a SIGCHLD is sent to the parent. In your case it interrupts the sleep and it looks as if the process doesn't sleep.
The gist of the issue: sleep isn't restarted when interrupted by a signal.

Will a child process send SIGCHLD on abort()?

If an application does a fork() and the child dies with an abort() (due to failing an assert()), will the parent process receive a SIGCHLD?
If it's relevant this is on Debian 4 (gcc version 4.1.2).
If you want to check the same,write a sample code which forks a child and the child calls abort() (To raise the sigabrt signal). Check its output on strace.(strace executable)
For the following code:
#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t pid;
if(pid=fork()<0)
{
fprintf(stderr,"Error in forking");
}
else if(pid==0)
{
/*The child*/
abort();
}
else {
waitpid(pid,(int *)0,0);
}
return 0;
}
I get this output:
--- SIGCHLD (Child exited) # 0 (0) ---
gettid() = 4226
tgkill(4226, 4226, SIGABRT) = 0
--- SIGABRT (Aborted) # 0 (0) ---
+++ killed by SIGABRT +++
So the answer is yes, at least on Ubuntu distro.
You would expect the parent to get a SIGCHLD any time a child terminates unless the child has separated itself off from the parent (IIRC using setsid() or setpgrp()). The main reason for a child doing this is if the child is starting a daemon process. See Here or Here for a deeper treatment of daemon processes.

Resources