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.
Related
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);
}
}
}
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;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
GOAL: Make parent process counters correct, counter1 = 5, counter2 =8.
Program is supposed to create 2 subprocesses. Each one of them will send set number of respectively SIGUSR1 and SIGUSR2 to parent. 5 and 8 times respectively.
To simplify, after many crashes causing my system to log out, closing all programs and forcing me to log in, i'm printing information about parent process instead. The goal is to replace those prints by
kill(getppid(),SIGUSR1) // and SIGUSR2 for second child process.
Current child work function:
void childWork(int loopCounter, int sigNum)
{
for(; loopCounter>0; loopCounter--)
{
if(SIGUSR1==sigNum) //kill(getppid(),SIGUSR1);
printf("[%d] sending SIGUSR1 to %d\n", getpid(),getppid());
else if(SIGUSR2 == sigNum) //kill(getppid(), SIGUSR2);
printf("[%d] sending SIGUSR2 to %d\n", getpid(),getppid());
}
}
Here is the zombie handling function for cleanup:
void handleZombie(int sig) {
while (1) {
pid_t pid = waitpid(0, NULL, WNOHANG);
if (pid < 0) {
if (errno == ECHILD)
return;
printf("Error, cleaning\n");
}
if (pid == 0)
return;
}
And finally main:
int main(int argc, char** argv)
{
printf("[%d] PARENT started! My parent: %d\n", getpid(), getppid());
childrenLeft=2;
setHandler(handleZombie,SIGCHLD);
setHandler(sigHandler1, SIGUSR1);
setHandler(sigHandler2, SIGUSR2);
int i;
for(i=1;i<=childrenLeft;i++)
{
pid_t pid = fork();
if(pid < 0)
printf("Error - fork\n");
if(pid==0)
if(i==1)
{
printf("[%d] child created!\n", getpid());
childWork(5,SIGUSR1);
}
if(i==2)
{
childWork(8, SIGUSR2);
printf("[%d] child created!\n", getpid());
}
exit(EXIT_SUCCESS);
}
printf("Work finished, final numbers:\nSIGUSR1 received: %d\nSIGUSR2 received: %d\n",sig1Count,sig2Count);
while (wait(NULL) > 0)
continue;
printf("[PARENT=%d] terminates\n", getpid());
return EXIT_SUCCESS;
}
Current issue is actually handling the parent process. For reason i do not understand, my second child isn't created. What more, the parent being printed is out of the blue.
[6025] PARENT started! My parent: 1300
[6026] child created!
[6026] sending SIGUSR1 to 6025
[6026] sending SIGUSR1 to 6025
[6026] sending SIGUSR1 to 6025
[6026] sending SIGUSR1 to 30404
[6026] sending SIGUSR1 to 30404
This is the complete output. Please help me understand what is going on here...
Note that you don't report that child 2 is created until after childWork() returns.
However, your fundamental problem is the lack of statement grouping braces after if (pid == 0) which means that the exit(EXIT_SUCCESS): after the two tests if (i == 1) and if (i == 2); causes the parent to exit immediately after launching the first child.
int main(int argc, char** argv)
{
printf("[%d] PARENT started! My parent: %d\n", getpid(), getppid());
childrenLeft=2;
setHandler(handleZombie,SIGCHLD);
setHandler(sigHandler1, SIGUSR1);
setHandler(sigHandler2, SIGUSR2);
int i;
for(i=1;i<=childrenLeft;i++)
{
pid_t pid = fork();
if(pid < 0)
printf("Error - fork\n");
if(pid==0)
{ // Primary bug: braces missing
if(i==1)
{
printf("[%d] child created!\n", getpid());
childWork(5,SIGUSR1);
}
if(i==2)
{
printf("[%d] child created!\n", getpid()); // Moved before childWork()
childWork(8, SIGUSR2);
}
exit(EXIT_SUCCESS); // Only executed by children
} // Primary bug: missing braces
}
printf("Work finished, final numbers:\nSIGUSR1 received: %d\nSIGUSR2 received: %d\n",sig1Count,sig2Count);
while (wait(NULL) > 0)
continue;
printf("[PARENT=%d] terminates\n", getpid());
return EXIT_SUCCESS;
}
This is the bare minimum fixing needed; there are many other changes that could and perhaps should be made.
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.
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.