I am trying to send a child's pid to his father using SIGUSR1 and sigqueue. But the signal is never sent, or it appears not to be sent.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
void handler(int signum, siginfo_t *info, void *extra)
{
void *ptr_val = info->si_value.sival_ptr;
int int_val = info->si_value.sival_int;
printf("Child: Father, I am %d!\n",int_val);
}
int main()
{
int pid;
printf("Father: I am %d\n",getpid());
if ( (pid=fork()) <0 )
{
perror("fork");
exit(EXIT_FAILURE);
}
else
if ( pid==0 )
{
printf("Child: I am My father is %d.\n",getppid());
sigqueue(getppid(),SIGUSR1,(const union sigval) getpid());
}
else
{
struct sigaction action;
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask,SIGUSR1);
action.sa_flags = SA_SIGINFO;
action.sa_mask =mask;
action.sa_sigaction = &handler;
if (sigaction(SIGUSR1,&action,NULL)==-1)
{
perror("sigaction");
exit(EXIT_FAILURE);
}
printf("Father: Welcome home, son!\n");
}
return 0;
}
Running the code above I get the following output:
Father: I am 18990
Father: Welcome home, son!
Child: My father is 18990.
And that's not all. If I run it again, all my apps close(editor,terminal,etc.) and I need to sign in again. (kind of a switch user operation) What's wrong with the code? Thanks.
The reason the signal is not caught is that parent is exiting before the child queues up the signal. Just add a delay inside the parent and you can see that it catches the signal.
This fact is further strengthened by a different output that I get on my system for your same program
Father: I am 18990
Father: Welcome home, son!
Child: My father is 1.
The child notes the father's pid as 1, because the father has exited leaving the child as orphan and being adopted by init.
A very related question
getpid and getppid returns two different values
Related
I`m writing the program in which parent and child processes synchronize their actions with signals.
So, as result, I need a repeated cycle:
The parent process should send signal SIGUSR1 to a group of the child processes.
After getting the signal from the parent, the child processes should send signal SIGUSR2 to the parent.
After getting the signals from all child processes, the parent process should sleep for 1 s. But if the parent process gets signal SIGTERM from the child, the parent should send SIGTERM to all child processes and they should stop working.
I`ve already written how to create the group of child processes and send to them signal SIGUSR1. But I don't know how to send signal SIGUSR2 from child processes to the parent process and verify if all child processes sent a signal and if the sent signals contain SIGTERM signal.
Please, help me!
##include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
static volatile sig_atomic_t got_signal;
void sig_child(int signo){
printf("Signal caught.");
}
void handler(int sig)
{
printf("caught signal: %d\n", getpid());
got_signal = 1;
signal(SIGUSR2, sig_child);
printf("sent signal: %d\n", getpid());
kill(getppid(), SIGUSR2);
}
int main() {
pid_t child;
pid_t children[3];
int status;
int i = 0;
signal(SIGUSR1, handler);
for (; i < 3; i++) {
switch (child = fork()) {
case -1:
perror("could not create child: ");
break;
case 0:
printf("child: %d\n", getpid());
while (!got_signal);
_exit(0);
default:
children[i] = child;
/*put all children in process group of eldest child*/
setpgid(child, children[0]);
}
}
sleep(1);
/* send signal to all child by sending signal to process group of eldest child */
kill(-children[0], SIGUSR1);
int n = 0;
while (n < 3) {
waitpid(children[n], &status, 0);
n++;
}
exit(0);
}
Let's say that whenever main program receives SIGINT signal, the youngest (i.e. the lastly forked) process is forked. In other words:
p1 SIGINT
p1->p2 SIGINT
p1->p2->p3
and so on
My problem is that I don't know how to tell the grand-grand-...-children to fork.
My problem is that I don't know how to tell the
grand-grand-...-children to fork.
Parent should install SIGINT handler using SA_SIGINFO flag.
When a grandchild is created it should send signal to parent(p1).
P1 through its signal handler(si_pid field of handler's siginfo_t argument) reads pid of grandchild.
When Parent receives SIGINT then it send signal to grand child.
When grand child receives signal it should fork a new child.
Repeat from 2-5 for newly created child.
One more approach:
Let parent poll for SIGINT signal.
When SIGINT received by parent, create child.
Mask SIGINT in parents context and wait for SIGINT in child context.
repeat step 1 to 3 in childs context.
Example:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#define CHILD_NEEDED 10
static volatile sig_atomic_t got_sigint;
static volatile sig_atomic_t child_created;
void sigint_handler(int sig, siginfo_t *f, void *main_context) {
ucontext_t *uc = main_context;
// to mask SIGINT while returning from handler.
sigaddset(&uc->uc_sigmask, SIGINT);
++child_created;
got_sigint = 1;
}
void create_child(void)
{
pid_t pid = fork();
sigset_t set;
sigemptyset(&set);
if (-1 == pid) {
perror("Fork failed\n");
exit(1);
} else if (0 == pid) {
// Exit if expected child are created
if (child_created == CHILD_NEEDED) {
printf("New Child\nTotal Child: %d\n", child_created);
exit(0);
}
got_sigint = 0;
// As parent mask is copied to child so clear child mask set.
sigprocmask(SIG_SETMASK, &set, NULL);
printf("New Child\n Please send signal to create child\n");
while (!got_sigint);
create_child();
}
}
int main(int argc, const char *argv[]) {
struct sigaction act = {.sa_sigaction = sigint_handler, .sa_mask = 0, .sa_flags = SA_SIGINFO};
sigset_t mask;
int status;
parent = getpid();
sigaction(SIGINT, &act, NULL);
printf("parent\n Please send signal to create child\n");
while (!got_sigint);
// As we have returned from signal so SIGINT will be mask for parent.
create_child();
// parent will wait here.
wait(&status);
exit(0);
}
All your processes will receive the SIGINT signal, so the main process doesn't need to tell the youngest process to fork; just let the process that hasn't forked yet fork, and all other processes do nothing.
I have written C code to have understanding of how pthreads behave in face of receiving a signal. For this, I have setup a signal handler using sigaction, done fork to create child process, setup number of pthreads from child process, and sent a signal from parent process to child process. I am printing id of thread from signal handler.
I had read that when a process has number of threads, then the signal will be handled by any of the threads and the behaviour is undefined (that is not sure of which thread will handle the signal). But what I have observed in my program is that every time the signal handler is printing id of only one thread and this seems to be id of parent thread. I was expecting that random id of any of the threads will be printed every time the signal is sent, but this is not happening. Can someone please throw some light on this?
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
pthread_t tid[5];
void* doSomeThing2(void *arg)
{
int i;
printf("In thread handler.my pid is %x\n",pthread_self());
i=5;
while(i--)
{
sleep(1);
}
return NULL;
}
static void my_completion_handler( int signo, siginfo_t *info, void *context )
{
int ret;
printf("In completion handler.my pid is %x\n",pthread_self());
return;
}
int main()
{
int ret,err;
struct sigaction sig_act;
pid_t mypid;
int i,j;
/* Setup the signal handler */
sigemptyset(&sig_act.sa_mask);
sig_act.sa_flags = SA_SIGINFO;
sig_act.sa_sigaction = my_completion_handler;
/* Map the Signal to the Signal Handler */
ret = sigaction( SIGTERM, &sig_act, NULL );
mypid=fork();
switch(mypid) {
case -1:
printf("fork failed\n");
return -1;
case 0:
/* child process */
printf("In child process,my pid is %x\n",pthread_self());
for(j=0;j<5;j++) {
err = pthread_create(&(tid[j]), NULL, &doSomeThing2, NULL);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
}
for(j=0;j<5;j++)
{
pthread_join(tid[j], NULL);
}
exit(0);
default:
/* parent process */
printf("Got child pid of %d\n",mypid);
i=5;
while(i--)
{
sleep(1);
printf("Parent sending signal to child \n");
kill(mypid,SIGTERM);
}
break;
}
return 0;
}
When I executed this program, I got below results:
root#sri-ThinkCentre-M72e:/home/sri/Downloads# ./signal-fork
Got child pid of 10049
In child process,my pid is b7573700
In thread handler.my pid is b6d71b40
In thread handler.my pid is b6570b40
In thread handler.my pid is b5d6fb40
In thread handler.my pid is b7572b40
In thread handler.my pid is b556eb40
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
Parent sending signal to child
In completion handler.my pid is b7573700
In the manual for GNU libc about orphaned process groups, it mentioned :
“process groups that continue running even after the session leader
has terminated are marked as orphaned process groups.
When a process group becomes an orphan, its processes are sent a SIGHUP
signal. Ordinarily, this causes the processes to terminate. However,
if a program ignores this signal or establishes a handler for it
(see Signal Handling), it can continue running as in the orphan process
group even after its controlling process terminates; but it still
cannot access the terminal any more. ”
I write a test program, but when the process group becomes an orphan, its process didn't receive the SIGHUP signal. I am wondering why?
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static void
sig_hup(int signo) //**never get called ???**
{
printf("SIGHUP received, pid = %ld\n", (long)getpid());
}
static void
pr_ids(char *name)
{
printf("%s: pid = %ld, ppid = %ld, pgrp = %ld, tpgrp = %ld\n",
name, (long)getpid(), (long)getppid(), (long)getpgrp(),
(long)tcgetpgrp(STDIN_FILENO));
fflush(stdout);
}
int
main(void)
{
char c;
pid_t pid;
pr_ids("parent");
pid = fork();
if (pid > 0) { // parent
sleep(5);
exit(0); // parent exit;
} else {
pr_ids("child");
setsid(); //create new session, and "child" becomes the session leader
pid = fork();
if(pid>0) {
sleep(20);
exit(0); // "child" exit
// so the process group become an orphan process group
}
else{
pr_ids("grandson");
signal(SIGHUP, sig_hup); // establish signal handler
sleep(60); // now becoming orphan process group
printf("end\n");
}
}
exit(0);
}
Orphaned process groups get SIGHUP followed by SIGCONT if they're stopped when they become orphaned.
Sleep is not enough, you need:
kill(getpid(), SIGSTOP); //or raise(SIGSTOP);
In addition to that, POSIX doesn't require that SIGHUP and SIGCONT be sent if the orphaning was caused by setsid() or setprgrp() because then it wasn't caused by an exiting process innocently unaware of job control (see http://pubs.opengroup.org/onlinepubs/9699919799/functions/_exit.html ).
However, with kill(getpid(), SIGSTOP) instead of that sleep(60) in the child, you will get a stopped orphan with your program even if you don't call setsid().
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
static void
sig_hup(int signo) //**never get called ???**
{
printf("SIGHUP received, pid = %ld\n", (long)getpid());
}
static void
pr_ids(char *name)
{
printf("%s: pid = %ld, ppid = %ld, pgrp = %ld, tpgrp = %ld\n",
name, (long)getpid(), (long)getppid(), (long)getpgrp(),
(long)tcgetpgrp(STDIN_FILENO));
fflush(stdout);
}
int
main(void)
{
pid_t pid;
pr_ids("parent");
pid = fork();
if (pid > 0) { // parent
sleep(5);
_exit(0); // parent exit;
} else {
pr_ids("child");
/*setsid(); //create new session, and "child" becomes the session leader*/
pid = fork();
if(pid>0) {
sleep(2);
exit(0); // "child" exit
// so the process group become an orphan process group
}
else{
pr_ids("grandson");
signal(SIGHUP, sig_hup); // establish signal handler
kill(getpid(), SIGSTOP);
printf("end\n");
}
}
exit(0);
}
should get you a SIGHUP in the child after the parent dies (5s).
That document section is talking specifically about the loss of a controlling terminal of a process that had one—usually by a modem hangup, or the virtual equivalent (ending an ssh session, etc). (I think the phrasing in the document could be improved here). When you use setsid() here, you give up access to the controlling terminal by the time setsid() returns, so there is no controlling terminal to lose from there forward.
You could open() a tty device (such as a pty slave) to gain a controlling terminal (note that you may have to do some additional operation as well—FreeBSD requires a TIOCSCTTY ioctl), then lose it again, and then you should get the SIGHUP signal.
I'm having trouble with a process forking exercise. I want to fork a child process and have it hang after announcing it has been forked, and wait for a signal to terminate, after which the parent process must announce it is terminating and then exit.
I can get the processes forked and have the parent wait for the hanging child to be killed by the signal, but it seems to kill the parent as well. I tried killing the child process specifically by its PID, but with no success.
Thanks for any help!
Code:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
void catchInt (int signum)
{
printf("\nMy sincerest apologies, master\n");
/*kill(0, SIGINT);*/
exit(0);
}
void ignoreInt (int signum)
{
wait(NULL);
}
int main () {
pid_t pid;
/* fork process */
pid = fork();
if (pid < 0) /* error handler */
{
fprintf(stderr, "Fork Failed");
exit(-1);
}
else if (pid == 0) /* child */
{
printf("Child reporting in\n");
signal(SIGINT, catchInt);
for ( ;; )
pause();
}
else /* parent */
{
/* parent will wait for the child to complete */
signal(SIGINT, ignoreInt);
wait(NULL);
printf("You're welcome\n");
exit(0);
}
}
Even assuming you fix the code so it compiles (you've not defined tempPID), there are problems:
You set the child to go to sleep until a signal arrives.
You set the parent to wait until the child dies.
So, you have a state where neither process is going to do anything more.
You probably need the parent to send a signal to the child:
kill(pid, SIGINT);
It is not clear that you need the parent to set a signal handler.
You probably want the child to set a signal handler.
You probably don't want the infinite loop in the child.
Oh, and void main() is incorrect - int main() or int main(void) or int main(int argc, char **argv) are the approved declarations for main().
And it is tidier if you return a value (0) from main(). The C99 standard does permit you to drop off the end of main() and will treat that as returning zero, but only if the function is properly declared as returning an int.
The header for wait() and relatives in POSIX is <sys/wait.h>.
And, because I'm a sucker, here's code that compiles and might even do what you want:
#include <stdio.h>
#include <signal.h>
#include <unistd.h> /* getpid() */
#include <stdlib.h>
#include <sys/wait.h>
void catchInt(int signum)
{
printf("Child's PID is %d\n", (int)getpid());
printf("My sincerest apologies, master\n");
exit(1);
}
int main()
{
pid_t pid = fork();
if (pid < 0) /* error handler */
{
fprintf(stderr, "Fork Failed");
exit(-1);
}
else if (pid == 0) /* child */
{
printf("Child reporting in\n");
signal(SIGINT, catchInt);
pause();
}
else /* parent */
{
sleep(1);
kill(pid, SIGINT);
wait(NULL);
printf("You're welcome\n");
}
return(0);
}
Just figured out what I was doing wrong, I should have realized SIGINT is sent to every process, and so the parent was simply being sent an unhandled SIGINT, causing it to exit. Thanks for all the help (my apologies on the sloppy coding, I really shouldn't wait until the program is completed to clean that up), the code's been edited above and works as intended.
Thanks again.