Sending signal from child to parent - c

Here I want to send SIGINT signal to parent while it is sleeping. I have tried it by writing following the program. In this program, I am not getting why the signal handler for SIGINT from the parent is not executing at all?
here is the code:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
void sig_usr(int signo){
if(signo == SIGINT)
printf("Signal caught!");
return;
}
int main(void){
pid_t pid, ppid;
ppid = getpid();
printf("ppid = %d\n", ppid);
if((pid = fork()) == 0){
printf("killing parent...\n");
kill(ppid, SIGINT);
printf("After killing parent...\n");
}
else{
sleep(5);
printf("%d %d ",ppid, pid);
if(signal(SIGINT,sig_usr) == SIG_ERR)
printf("Signal processed ");
}
return 0;
}
Output:
The output is printing only this much content. I think parent is not executing at all.

You need to set the signal handler before SIGINT is sent to the parent process, otherwise, the handler will not be executed. Also, the parent process is being killed before it executes anything. The easy way to fix this would be to move the sleep call after the code for the parent process, and add a delay to the child process.
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
void sig_usr(int signo){
if(signo == SIGINT)
printf("Signal caught!");
return;
}
int main(void){
pid_t pid, ppid;
ppid = getpid();
printf("ppid = %d\n", ppid);
if((pid = fork()) == 0){
sleep(1); // Wait for parent to finish setting up
printf("killing parent...\n");
kill(ppid, SIGINT);
printf("After killing parent...\n");
}
else{
printf("%d %d ",ppid, pid);
if(signal(SIGINT,sig_usr) == SIG_ERR)
printf("Signal processed ");
sleep(5); // Wait to be killed
}
return 0;
}

When you send SIGINT signal has not been called yet.
I think you want to set signal handler before sending SIGINT:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
void sig_usr(int signo){
if(signo == SIGINT)
printf("Signal caught!");
return;
}
int main(void){
pid_t pid, ppid;
ppid = getpid();
printf("ppid = %d\n", ppid);
if((pid = fork()) == 0){
sleep(1);
printf("killing parent...\n");
kill(ppid, SIGINT);
printf("After killing parent...\n");
}
else{
printf("%d %d ",ppid, pid);
if(signal(SIGINT,sig_usr) == SIG_ERR)
printf("Signal processed ");
sleep(5);
}
return 0;
}

Related

Why will signal TSTP received by sigchld_handler instead of sigtstp_handler?

This is my own shell program.
The TSTP signal is sent by this part of main function, this c file will be ran as a program in the shell.
When the c program runs, it's in a forked child process, when it sends TSTP to itself, the expectation is that the signal should be received by tstp-handler (the printf should be showing up) and then the child process stopped.
However, it's the child-handler that received a signal(17), i.e the printf in sigchld_handler was called without printf in sigtstp_handler being called first. It's the parent process that gets received the sigchld signal, how can I make the child process itself receive the TSTP signal?
All handlers registered correctly as CTRL+Z will invoke the tstp-handler correctly.
Can anyone please help me with this part? Very much appreciate it.
If you need all the source code, please find it here
// the program sending the signal
int main(int argc, char **argv)
{
int i, secs;
pid_t pid;
if (argc != 2) {
fprintf(stderr, "Usage: %s <n>\n", argv[0]);
exit(0);
}
secs = atoi(argv[1]);
for (i=0; i < secs; i++)
sleep(1);
pid = getpid();
// printf("main process id: %d\n", pid);
if (kill(-pid, SIGTSTP) < 0)
fprintf(stderr, "kill (tstp) error");
exit(0);
}
void eval(char *cmdline){
char *argv[MAXARGS];
char buf[MAXLINE];
strcpy(buf, cmdline);
int bg = parseline(buf, argv);
if(argv[0] == NULL) return;
if(builtin_cmd(argv)){
return;
}
/* not built-in commands */
pid_t cpid;
sigset_t mask, prev_mask;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, &prev_mask);
cpid = fork();
if(cpid == 0){ // child
setpgid(0, 0);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
Execve(argv[0], argv, environ);
}else{
addjob(jobs, cpid, (bg? BG: FG), cmdline);
sigprocmask(SIG_SETMASK, &prev_mask, NULL);
if(bg){
printf("[%d] (%d) %s", pid2jid(cpid), cpid, cmdline);
/* when bg job is done, how is the child process reaped? => sigchld_handler will be triggered */
}else{
/* fg job, parent process blocked;
delete fg job after it's complete(in sigchld_handler)
*/
waitfg(cpid);
}
}
}
void sigtstp_handler(int sig){
//printf("=== in sigtstp_handler, sig: %d, from %d\n", sig, getpid());
pid_t foreground_pid = fgpid(jobs);
if(foreground_pid == 0) return;
struct job_t *fg_job = getjobpid(jobs, foreground_pid);
if(fg_job != NULL && fg_job->state == FG){
pid_t pgid = getpgid(fg_job->pid);
printf("Job [%d] (%d) stopped by signal %d\n", fg_job->jid, fg_job->pid, sig);
Kill(-pgid, SIGTSTP);
}
}
void sigchld_handler(int sig){
// printf("=== in sigchld_handler: %d\n", sig);
pid_t cpid;
int status;
if((cpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0){
if(WIFEXITED(status)){
// printf("in sigchld_handler, terminated cpid: %d\n", cpid);
deletejob(jobs, cpid);
}
if(WIFSTOPPED(status)){
struct job_t *stopped_job = getjobpid(jobs, cpid);
stopped_job->state = ST;
}
if(WIFSIGNALED(status)){
deletejob(jobs, cpid);
}
}
}

How to fix signal handler functions are never invoked in c?

In the following code, I try to send SIGINT, SIGHUP, SIGQUIT signal to child process.
void sighup(int sig);
void sigint(int sig);
void sigquit(int sig);
These are my signal handler.
the issue is signal handler never invoked.
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
void sighup(int sig);
void sigint(int sig);
void sigquit(int sig);
int main()
{
int pid, i, j, k;
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
if(pid == 0)
{
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
}
else
{
j = 0;
for (i = 1; i <= 5; i++)
{
j++;
if (i % 2 == 0)
{
printf("PARENT: sending SIGHUP Signal : %d\n", j);
kill(pid, SIGHUP);
sleep(3);
}
else
{
printf("PARENT: sending SIGINT signal : %d\n", j);
kill(pid, SIGINT);
sleep(3);
}
}
printf("Parent sending SIGQUIT\n");
kill(pid, SIGQUIT);
}
}
void sighup(int sig)
{
signal(SIGHUP, sighup);
printf("Child: I have received sighup\n");
}
void sigint(int sig)
{
signal(SIGINT, sigint);
printf("Child: I have received sighINT\n");
}
void sigquit(int sig)
{
printf("My daddy has killed me\n");
exit(0);
}
Below lines never printed on screen
Child: I have received sighup
Child: I have received sighINT
My daddy has killed me
Output
PARENT: sending SIGINT signal : 1
PARENT: sending SIGHUP Signal : 2
PARENT: sending SIGINT signal : 3
PARENT: sending SIGHUP Signal : 4
PARENT: sending SIGINT signal : 5
Parent sending SIGQUIT
You have two problems here.
First, after the child process sets up its signal handlers, it exits right away. So the parent might get to send the first signal depending on timing, but not any others.
Put the child in a pause loop to have it wait for signals.
The other problem is that it's possible that the parent might send the first signal to the child before it can set up its signal handlers. So put a short delay in the parent to allow that to happen.
if(pid == 0)
{
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
while (1) pause();
}
else
{
sleep(1);
...
Also, calling printf and exit from a signal handler are not considered safe. It's better to have the signal handlers set a global variable and have the main part of the code check for that.
int gotsig = 0;
void sighup(int sig)
{
signal(SIGHUP, sighup);
gotsig = sig;
}
void sigint(int sig)
{
signal(SIGINT, sigint);
gotsig = sig;
}
void sigquit(int sig)
{
gotsig = sig;
}
...
while (1) {
pause();
if (gotsig == SIGHUP) {
printf("Child: I have received sighup\n");
} else if (gotsig == SIGINT) {
printf("Child: I have received sighINT\n");
} else if (gotsig == SIGQUIT) {
printf("My daddy has killed me\n");
exit(0);
}
gotsig = 0;
}
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
void signint(int sig);
void sighup(int sig);
void sigquit(int sig);
int gotsig;
int main()
{
int pid,i;
pid = fork();
if(pid < 0)
{
perror("fork");
exit(0);
}
if(pid == 0)
{
signal(SIGHUP,sighup);
signal(SIGINT,signint);
signal(SIGQUIT,sigquit);
pause();
while(1)
{
if(gotsig == SIGINT)
{
printf("Child : Child process recieved SIGINT signal\n");
gotsig = -1;
}else if(gotsig == SIGHUP)
{
printf("Child : Child process recieved SIGHUP signal\n");
gotsig = -1;
}else if(gotsig == SIGQUIT)
{
printf("Dady killed me....!\n");
exit(0);
}
}
}else
{
sleep(1);
for(i = 1; i <=5 ; i++)
{
if(i % 2 == 0)
{
printf("Parent : sending SIGINT signal\n");
kill(pid,SIGINT);
sleep(3);
}else
{
printf("Parent : sending SIGHUP signal\n");
kill(pid,SIGHUP);
sleep(3);
}
}
printf("Parent : sending SIGQUIT signal\n");
kill(pid,SIGQUIT);
}
}
void signint(int sig)
{
gotsig = sig;
}
void sighup(int sig)
{
gotsig = sig;
}
void sigquit(int sig)
{
gotsig = sig;
}
Above code work fine for me.
Output :
Parent : sending SIGHUP signal
Child : Child process recieved SIGHUP signal
Parent : sending SIGINT signal
Child : Child process recieved SIGINT signal
Parent : sending SIGHUP signal
Child : Child process recieved SIGHUP signal
Parent : sending SIGINT signal
Child : Child process recieved SIGINT signal
Parent : sending SIGHUP signal
Child : Child process recieved SIGHUP signal
Parent : sending SIGQUIT signal
Dady killed me....!

Kill() error: no such process?

I have to insert an odd number by terminal. After this, it generates two processes, A and B.
Then it sends SIGUSR2 signal to B, and his handler prints the reciprocal of the argv[1]. Then, B sleeps for argv[1] seconds and sends SIGUSR1 signal to A process before terminating. The SIGUSR1 handler for process A prints something and then terminates.
The problem is that SIGUSR1 handler for process A doesnt' work because the signal couldn't be sent by SIGUSR2 handler for process B. In fact, the kill(A,SIGUSR1) tells that there is no such process (for process A). After setting the signal handler in process A, it is in pause().
Can anyone help me to solve? Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int arg;
int pid1 = 11, pid2 = 12;
void sigusr2Handler1(int);
void sigusr1Handler2(int);
int main(int argc, char* argv[])
{
if(argc != 2){
printf("Usage: %s num(int)\n", argv[0]);
exit(1);
}
arg = atoi(argv[1]);
pid1 = fork();
if (pid1 != 0)
pid2 = fork();
if (arg%2 != 0) {
if (pid1 == 0) {
if (signal(SIGUSR1, sigusr1Handler2) == SIG_ERR) {
printf("PID %d can't catch SIGUSR1\n", getpid());
exit(1);
}
printf("PID1 %d sigusr1 handler2 installation\n", getpid());
pause();
}
if (pid2 == 0) {
signal(SIGUSR2, sigusr2Handler1);
printf("PID2 %d sigusr2 handler installation\n", getpid());
kill(0, SIGUSR2);
}
}
return 0;
}
void sigusr2Handler1(int sig)
{
printf("PID %d Received SIGUSR2. 1/%d = %f.\n", getpid(), arg, (float)1 / arg);
sleep(arg);
if (kill(pid1, SIGUSR1) < 0) {
perror("Kill error");
exit(1);
}
printf("PID %d. Sent SIGUSR1 to %d. Closing\n", getpid(), pid1);
exit(0);
}
void sigusr1Handler2(int sig)
{
printf("PID %d Received SIGUSR1. Closing.\n", getpid());
exit(0);
}
pid1 has been killed by the time pid2 attempts to send a it a SIGUSR1. pid2 is the killer.
When pid2 issues a kill(0, SIGUSR2), this sends SIGUSR2 to the entire process group, including pid1. This kills pid1, which is unprepared to receive a SIGUSR2.

Trouble sending and handling signals with children processes in C

The parent process forks two children, each replace SIGUSR1 and SIGUSR2 signal respectively.
The parent process replace SIGINT signal, on catching it, send SIGUSR1 and SIGUSR2 to its children respectively.
The expected output when Ctrl-C is pressed should be:
Ctrl+C is pressed。
received SIGUSR1 signal
received SIGUSR2 signal
But on Ctrl-C I've got
Ctrl+C is pressed。
I have no idea why sig_handler_1 and sig_handler_2 are not excuted.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
void fun_ctrl_c(int);
void sig_handler_1(int);
void sig_handler_2(int);
pid_t pid1;
pid_t pid2;
int status;
int main() {
pid1 = fork();
if (pid1 == 0) { // child 1
// avoid to be killed
(void) signal(SIGINT, SIG_IGN);
// replace SIGUSR1
(void) signal(SIGUSR1, sig_handler_1);
raise(SIGSTOP);
} else {
pid2 = fork();
if (pid2 == 0) { // child 2
// avoid to be killed
(void) signal(SIGINT, SIG_IGN);
// replace SIGUSR2
(void) signal(SIGUSR2, sig_handler_2);
raise(SIGSTOP);
} else { // parent
(void) signal(SIGINT, fun_ctrl_c);
waitpid(-1, &status, 0);
}
}
return 0;
}
void fun_ctrl_c(int)
{
printf("Ctrl+C is pressed。\n");
kill(pid1 ,SIGUSR1);
kill(pid2 ,SIGUSR2);
(void) signal(SIGINT, SIG_DFL);
}
void sig_handler_1(int)
{
printf("received SIGUSR1 signal\n");
}
void sig_handler_2(int)
{
printf("received SIGUSR2 signal\n");
}
Your problem is that you do raise(SIGSTOP); in the child processes, so they're stopped and cannot respond to signals at all.
Replace that with pause(); — the code then works.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
void fun_ctrl_c(int);
void sig_handler_1(int);
void sig_handler_2(int);
pid_t pid1;
pid_t pid2;
int main(void)
{
pid1 = fork();
if (pid1 == 0)
{
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGUSR1, sig_handler_1);
pause();
printf("PID %d exiting\n", (int)getpid());
}
else if ((pid2 = fork()) == 0)
{
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGUSR2, sig_handler_2);
pause();
printf("PID %d exiting\n", (int)getpid());
}
else
{
(void) signal(SIGINT, fun_ctrl_c);
int status;
int pid;
printf("Interrupt me!\n");
while ((pid = waitpid(-1, &status, 0)) != -1)
printf("Child %d exited with status 0x%.4X\n", pid, status);
printf("Parent %d exiting\n", (int)getpid());
}
return 0;
}
void fun_ctrl_c(int signum)
{
printf("Ctrl+C is pressed。Received SIGINT (%d) signal\n", signum);
kill(pid1, SIGUSR1);
kill(pid2, SIGUSR2);
(void) signal(SIGINT, SIG_DFL);
}
void sig_handler_1(int signum)
{
printf("received SIGUSR1 (%d) signal\n", signum);
}
void sig_handler_2(int signum)
{
printf("received SIGUSR2 (%d) signal\n", signum);
}
Sample run (I called the program sigintusr12):
$ ./sigintusr12
Interrupt me!
^CCtrl+C is pressed。Received SIGINT (2) signal
received SIGUSR2 (31) signal
received SIGUSR1 (30) signal
PID 31184 exiting
PID 31183 exiting
Child 31184 exited with status 0x0000
Child 31183 exited with status 0x0000
Parent 31182 exiting
$
Note that you're not strictly supposed to use printf() (and many other functions, especially those that might need to allocate memory) inside a signal handler. It'll work OK here, but it is not good practice. See How to avoid using printf() in a signal handler? for more information.

order of SIGCONT and SIGHUP sent to orphaned linux process group

APUE says
Since the process group is orphaned when the parentterminates, POSIX.1 requires that every process in
the newly orphaned process group that is stopped (as our child is) be sent the hang-up signal (SIGHUP)
followed by the continue signal (SIGCONT)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#define errexit(msg) do{ perror(msg); exit(EXIT_FAILURE); } while(0)
static void sig_hup(int signo)
{
printf("SIGHUP received, pid = %d\n", getpid());
}
static void sig_cont(int signo)
{
printf("SIGCONT received, pid = %d\n", getpid());
}
static void sig_ttin(int signo)
{
printf("SIGTTIN received, pid = %d\n", getpid());
}
static void pr_ids(char *name)
{
printf("%s: pid = %d, ppid = %d, pgrp = %d, tpgrp = %d\n",
name, getpid(), getppid(), getpgrp(), tcgetpgrp(STDIN_FILENO));
}
int main(int argc, char *argv[])
{
char c;
pid_t pid;
setbuf(stdout, NULL);
pr_ids("parent");
if ((pid = fork()) < 0) {
errexit("fork error");
} else if (pid > 0) { /* parent */
sleep(5);
printf("parent exit\n");
exit(0);
} else { /* child */
pr_ids("child...1");
signal(SIGCONT, sig_cont);
signal(SIGHUP, sig_hup);
signal(SIGTTIN, sig_ttin);
kill(getpid(), SIGTSTP);
//sleep(10);
pr_ids("child...2");
if (read(STDIN_FILENO, &c, 1) != 1) {
printf("read error from controlling TTY, errno = %d\n",
errno);
}
printf("child exit\n");
}
exit(0);
}
program output:
parent: pid = 2036, ppid = 1959, pgrp = 2036, tpgrp = 2036
child...1: pid = 2037, ppid = 2036, pgrp = 2036, tpgrp = 2036
parent exit
xiejingfeng#xiejingfeng-desktop:/codes/apue$ SIGCONT received, pid = 2037
SIGHUP received, pid = 2037
child...2: pid = 2037, ppid = 1, pgrp = 2036, tpgrp = 1959
read error from controlling TTY, errno = 5
child exit
output is not expected as what the book says because the program receive SIGCONT firstly then SIGHUP, which is very confusing for me, can you guys help me out?
thanks in advance.
The SIGHUP cannot be delivered until the child's execution is resumed. When a process is stopped, all signal delivery is suspended except for SIGCONT and SIGKILL.
So, the SIGHUP does arrive first, but it cannot be processed until the SIGCONT awakens the process execution.

Resources