I am new in using signals on C programming.
I wrote two simple source codes child.c and parent.c in order to demonstrate my issue.
child.c
void errorHandler(char* message);
void sigterm_handler(int signum, siginfo_t* info, void* ptr);
int main(){
struct sigaction action1;
memset(&action1, 0, sizeof(action1));
action1.sa_sigaction = sigterm_handler;
action1.sa_flags = SA_SIGINFO;
if(sigaction(SIGTERM, &action1, NULL) != 0)
errorHandler("Signal sigterm_handler registration failed");
for(int i = 0; i < 10; i++){
printf("%d\n", i);
if(i == 5){
if(raise(SIGSTOP)!= 0)
errorHandler("Raise SIGSTOP failed");
}
}
return EXIT_SUCCESS;
}
void errorHandler(char* message){
printf("Error: %s: %s\n", message, strerror(errno));
exit(EXIT_FAILURE);
}
void sigterm_handler(int signum, siginfo_t* info, void* ptr){
printf("Child: Process %d finishes\n", getpid());
exit(EXIT_SUCCESS);
}
parent.c
int main(int argc, char* argv[]){
int status;
pid_t mem;
pid_t child = fork();
if(child == 0){
char* arr[] = {"./child", NULL};
execv(arr[0], arr);
}
else if(child > 0){
mem = child;
waitpid(mem, &status, WUNTRACED);
}
if(WSTOPSIG(status)){
printf("Sending SIGTERM to child\n");
kill(mem, SIGTERM);
waitpid(mem, &status, 0);
}
return 0;
}
When I run parent.c, the program print into stdout:
1
2
3
4
5
Sending SIGTERM to child
but then the program get stuck, probably because sigterm_handler don't invoke, instead of printing "Child: Process *** finishes".
I tried to read on the linux manual page but I still can't to figure it out.
Can anyone please explain to me what is causing this issue?
Any answer would be appreciated!
The problem is, that the child process, that calls
if(raise(SIGSTOP) != 0)
is still stopped, when the parent here
kill(mem, SIGTERM);
sends the signal SIGTERM. The signal is not lost, but is still pending at the child's process and will be delivered, as soon as the process continues to run. You can achieve that by issuing
kill(mem, SIGCONT);
directly after sending the SIGTERM. Then, the child will resume to run, the signal will be delivered and the handler will be executed, printing the diagnostic message and exiting the process.
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);
}
}
}
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.
I'm writing a Unix program where the parent process has to send signals to children and a grandson. How could I know if all processes have been already created before sending signals? Because sometimes they don't exist yet. Thanks a lot!
void t(int sig)
{
kill(SIGKILL, pidc1);
kill(SIGKILL, pidc2);
kill(SIGKILL, pidg2);
kill(SIGKILL, pidc3);
}
void handler()
{
write(1, "Signal SIGUSR1\n", 15);
}
pid_t pidc1, pidc2, pidc3, pidg2;
int main(int argc, char **argv)
{
struct sigaction action;
int status;
action.sa_flags = 0;
action.sa_handler = handler;
sigaction(SIGUSR1, &action, NULL);
pidc1 = fork();
if(pidc1 == 0)
{
printf("Child 1\n");
}
pidc2 = fork();
if(pidc2 == 0)
{
printf("Child 2\n");
pidg2 = fork();
if(pidg2 == 0)
{
printf("Grandson 2\n");
}
wait(&status);
}
pidc3 = fork();
if(pidc3 == 0)
{
printf("Child 3\n");
}
kill(pidg2, SIGUSR1);
kill(pidc3, SIGUSR1);
signal(SIGALRM, t);
alarm(10);
wait(&status);
}
Preliminary note: The child code parts in your example program fall through to their parent's code, which is certainly not intended; I'll assume something like return sleep(5); at the end of each block. Also note that the printf()s may malfunction with fork()s and buffered output.
Barmar wrote:
If you need to wait for the grandchild processes to be created, you need some kind of communication from the child to the parent, so it can send the grandchild's PID. Shared memory and a mutex would be a way to do this.
That's absolutely correct. (The direct children are no problem, since the parent knows their PIDs.) Another way to communicate the grandchild's PID is a pipe; your example main() could become:
int main(int argc, char **argv)
{
int status;
sigaction(SIGUSR1, &(struct sigaction){.sa_handler = handler}, NULL);
setbuf(stdout, NULL); // printf() may malfunction without this
pidc1 = fork();
if (pidc1 == 0)
{
printf("Child 1\n"); return sleep(5);
}
int pipefd[2];
pipe(pipefd); // for communicating the grandson's PID
pidc2 = fork();
if (pidc2 == 0)
{
printf("Child 2\n");
pidg2 = fork();
if (pidg2 == 0)
{
printf("Grandson 2\n"); return sleep(5);
}
write(pipefd[1], &pidg2, sizeof pidg2); // write pidg2 to write end
wait(&status); return sleep(5);
}
pidc3 = fork();
if(pidc3 == 0)
{
printf("Child 3\n"); return sleep(5);
}
read(pipefd[0], &pidg2, sizeof pidg2); // read pidg2 from pipe's read end
kill(pidg2, SIGUSR1);
kill(pidc3, SIGUSR1);
}
Hi currently I am collecting backtrace of child process in signal handler of child process . Then planning to send collected backtrace to parent process using message queue .
My problem is when child process get any signal. child signal handler runs but informs parent process that child exited normally instead of child get signal.
below is my code
void childProcess()
{
int h =0 ;
for(h=0;h<10;h++)
{
printf("child for loop running %d\n",h);
//sleep(1);
int q = 1/0; // generate floating point exception
}
exit(0);
}
void signalhandler(int signum, siginfo_t *si, void *arg)
{
printf("signal received %s\n",strsignal(signum));
printf("%d\n",signum);
void *array[100];
int size = 100;
int addrLen = backtrace(&array,size);
char ** sym = backtrace_symbols(&array,addrLen);
int j = 0;
printf("Test crashed due to %s\n",strsignal(signum));
for(j=0;j<addrLen;j++)
{
printf("%u : %s\n",array[j],sym[j]);
}
raise(signum);
exit(signum);
}
void registerSignals()
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = signalhandler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
}
int main()
{
//while(1)
{
pid_t pid;
pid = fork();
if(pid == 0)
{
// child
printf("child process id is %d\n",getpid());
registerSignals();
childProcess();
}
else
{
printf("parent process id is %d\n",getpid());
// parent
int iStatus;
pid_t childPID = waitpid(pid,&iStatus,0);
printf("iStatus is %d\n",WIFEXITED(iStatus));
if(childPID == -1)
{
printf("wait pid failed\n");
}
else if(WIFEXITED(iStatus)==1)
{
printf("child exited normally!\n");
}
else if (WIFSIGNALED(iStatus)==1)
{
printf("child process terminated abnormally !!\n");
int iSignalnumber = 0;
// to fetch the signal number
iSignalnumber = WTERMSIG(iStatus);
printf("child process terminated due to %s\n",strsignal(iSignalnumber));
// to check core file is generated or not
if(WCOREDUMP(iStatus)==1)
{
printf("core file is generated \n");
}
else
{
printf("core file is not generated \n");
}
}
int h ;
for(h = 0; h<10;h++)
{
printf("parent executing : %d\n",h);
}
}
printf("while loop executing with pid : %d \n", getpid());
sleep(1);
}
}
My requirement is after signal handler is served in child process the
parent should print "child process terminated abnormally !!" but I am
getting "child exited normally!" message
From wait()'s Linux docs:
WIFEXITED(wstatus)
returns true if the child terminated normally, that is, by
calling exit(3) or _exit(2), or by returning from main().
The child signal handler ends the process using exit(), so everything works a specified.
Remove the call to exit() from the signal handler to get the expected result.
The call to raise() inside the signal handler most likely leads to recursive calls, so remove is as well.
as an exercise I need to use a signal handler, and pipes to send some messages between two processes, when getting a signal. Below is my sourcecode. When I'm running it, I can get the pipes to work, both processes can talk, as long as I call the pipe in their main-method (in this case process1() and process2() ).
But I want to use the pipes inside the signalhandlers. But now the pipes don't work.
This is some output I got:
3 - 4 and 5 - 6
Segv at 8825
USR1 at 8824
898 sent to 4
130 received on 3
130
The '898' and '130' should be equal, but aren't.
I know the pipes are working correctly, so I think it has something to do with the signalstuff...
But what...?
Sourcecode:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int fd1[2], fd2[2], status;
int cpid, cpoid;
void process1() {
cpid = getpid(); /*What's my process ID?*/
cpoid = cpid + 1; /*And what's the other process ID?*/
close(fd1[0]);
close(fd2[1]);
while (1) {}
}
void process2() {
cpid = getpid();
cpoid = cpid - 1;
close(fd1[1]);
close(fd2[0]);
raise(SIGSEGV); /*Start with a SegV signal*/
while (1) {}
}
/*Method to send a message to the other process, by pipe*/
void send (int msg) {
if (cpid < cpoid) {
write(fd1[1], &msg, 1);
printf("%d sent to %d\n", msg, fd1[1]);
} else {
write(fd2[1], &msg, 1);
printf("%d sent to %d\n", msg, fd2[1]);
}
}
/*Method to receive a message from the other process*/
int receive () {
int msg = 0;
if (cpid < cpoid) {
read(fd2[0], &msg, 1);
printf("%d received on %d\n", msg, fd2[0]);
} else {
read(fd1[0], &msg, 1);
printf("%d received on %d\n", msg, fd1[0]);
}
return msg;
}
/*The SegV Signal handler*/
void segvHandler() {
int y = -1;
printf("Segv at %d\n", cpid);
kill(cpoid, SIGUSR1); /*Send an USR1 Signal to the other proces*/
while (y != 898) {
y = receive();
printf("%d\n", y);
}
}
/*The Usr1 Signal handler*/
void usr1Handler() {
int x = 898;
printf("USR1 at %d\n", cpid);
send(x);
}
int main (int argc, char *argv[]) {
if (pipe(fd1) < 0) {
fprintf (stderr, "Could not make pipe\n");
return (EXIT_FAILURE);
}
if (pipe(fd2) < 0) {
fprintf (stderr, "Could not make pipe\n");
return (EXIT_FAILURE);
}
printf("%d - %d and %d - %d\n", fd1[0], fd1[1], fd2[0], fd2[1]); /*Pipe numbers*/
signal(SIGUSR1, usr1Handler); /*Signal handlers*/
signal(SIGSEGV, segvHandler);
if (fork() != 0) {
process1();
} else {
process2();
}
waitpid(-1, &status, 0);
return EXIT_SUCCESS;
}
Some faults based on a quick look.
printf() is not async-signal-safe; don't call it in a signal handler.
You're reading and writing 1 byte, which is most likely less than sizeof(int).
You cannot assume that PID's are consecutive. In the parent, the return value of fork() gives the PID of the child. In the child, if the parent stored the return value of getpid() before fork(), there you have it; otherwise see getppid().
As mentioned in the comments, you should not
invoke printf in a signal handler, but that is probably not the problem. Unless ints are one byte on your machine, the issue is that you are not writing or reading the whole int, since you only write one byte into the pipe. (Change the code to: write( fd[ 1 ], &msg, sizeof msg ) and make the same change on the read.)