The following process does not continue after running kill -SIGCONT pid from another terminal.
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("paused\n");
pause();
printf("continue\n");
return 0;
}
I expect the program to continue after sending the signal and printing "continue". How come this doesn't work as expected?
pause() is documented to
cause the calling process (or thread) to sleep until a signal is delivered that either terminates the process or causes
the invocation of a signal-catching function.
But SIGCONT only continues a process previously stopped by SIGSTOP or SIGTSTP.
So, you might want to try:
kill(getpid(), SIGSTOP);
Instead of your pause()
Also, you might want to look at sigsuspend().
Related
Write a C program simulating alarm clock. In the main function, you fork a child process,
and the child process sleeps for 5 seconds (the number of seconds is an command line
argument, see below for a sample run) , after which the child process sends the signal
(SIGALRM) to its parent process. The parent process, after forking the child process,
pause, upon receiving the SIGALRM signal, and prints out a message “Ding!”. The
following is a sample run
$ ./alarm 5
alarm application starting
waiting for alarm to go off
<5 second pause>
Ding!
done
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>
#include <stdlib.h>
void Dingdong()
{
printf("Ding!");
exit(1);
}
int main(int argc, char *argv[])
{
if(argc!=3)
{
printf("How much seconds you want to sleep the child process\n");
}
int PauseSecond=(argv[1]);
{
if(fork()==0)
{
printf("waiting for alarm to go off\n");
printf("%d second pause",PauseSecond);
sleep(PauseSecond);
kill(getpid(),SIGALRM);
}
else {
printf("Alarm application starting\n", getpid());
signal(SIGALRM,Dingdong);
printf("done");
}
}
}
Here's what's keeping it from working at all:
int PauseSecond=(argv[1]); That puts the address of the first argument in PauseSecond, which will usually be some really big number. You probably wanted to parse the value of the first argument instead. You need to use something like atoi or strtol on it to do that.
You're calling getpid() after forking, so the child is sending the signal to itself instead of to the parent. Either call getpid() before the fork and save it to a variable, or call getppid() instead.
The parent process is finishing execution and exiting before the child process's sleep ends. You can add the pause() function to the parent process to make it wait for a signal handler to run.
If you want done to print, you can't call exit from the signal handler.
Just fixing the above will get the program sort of working, but there's other things you should consider fixing too:
Since you're not using argv[2] for anything, you should see if argc is 2 instead of 3.
If there aren't enough arguments, you should exit/return instead of continuing and trying to use one that's not there.
You should either put a \n on the end of "%d second pause" or do a manual fflush, or you won't see that until after the sleep.
printf("Alarm application starting\n", getpid()); Your format string won't actually show the result of that getpid().
If you do want to exit from the signal handler, you need to use _Exit, not exit, as the latter isn't async-signal-safe.
I run my C program on Mac OS. Part of my program is as following. This code runs well on sigint signal but can't work on sigkill signal.
void sigkill(int sig){
/*some code neglected*/
exit(0);
}
void sigint(int sig){
flag=1;
}
void alive(void) {
signal(SIGINT, sigint);
signal(SIGKILL, sigkill);
alarm(10);
while(1){
//printf("%d\n",flag);
sleep(1);
if(flag==1){
printf("no\n");
flag=0;
}
}
}
I have four questions:
At first I didn't write sleep(1), It can enter the function sigint(), and change the flag value, I can see from the printf. However, no "no" output as I expected.
After I added sleep function, it works well. I suppose the while loop would check flag every 1 second, and output "no" if flag=1. However, it seems the "no" output everytime when I press ctrl+c. Why it don't wait for one second?
The question said "You should not use 'sleep()' to wait 10 seconds. Use alarm(), coupled with a loop." I want to know how to implement this without sleep().
The kill command can't invoke sigkill function, how to fix this?
In general, signals can only be "caught" by your application when it makes a system call into the kernel. If you do a plain while(1) { if (flag==1){...} }, that will never call into the kernel. Theoretically, when you do your outer printf in the while(1) loop, that should call into the kernel and so the signal could be caught.
sleep() is interrupted by any signal. Check the man page for sleep(3).
check the man page for alarm(2).
You cannot change the signal handler for SIGKILL nor for SIGSTOP. These signal effects are hardcoded into the kernel. From sigaction(2):
signum specifies the signal and can be any valid signal except SIGKILL and SIGSTOP.
The kill command with no arguments does not generate a SIGKILL signal; it generates SIGTERM.
I want to make my program sleep upto 10 seconds even the signal is occured. So, I tried the following program.
Program:
#include<stdio.h>
#include<signal.h>
#include<errno.h>
int main()
{
printf("PID: %d\n",getpid());
int unslept=10;
while(unslept>0){
unslept=sleep(unslept);
if(errno==EINTR)
continue;
}
return 0;
}
Output:
$ ./a.out
PID: 18935
User defined signal 1
$
I expect the above program will execute 10 seconds even the signal is interrupted. I exeperiment it like, in one terminal I
executed this program. And using another terminal using kill command I sent the SIGUSR1 signal to this process. But, the same problem
occurs. Once the signal is passed, the program terminates. So, is there any way to execute my program upto 10 seconds without affecting
any signal.
You can ignore the signal. See the below example, in that example, if the SIGUSR1 signal is interrupted, it just ignore the signal using the SIG_IGN.
#include<stdio.h>
#include<signal.h>
int main(void)
{
if (signal(SIGUSR1, SIG_IGN) == SIG_ERR)
perror("SIGUSR1");
sleep(30);
}
You can use signal handling mechanism. Register your method that will handle interrupt signals and just ignore it that in your function.
// signal handler
void my_function(int sig){
//do nothing
}
// register signal
signal(SIGNAL_ID, my_function);
So I'm trying to implement a signal handler for the SIGTSTP signal in a child process.
Basically what I'm trying to achieve is this:
Start child Process
Make the parent wait on the child process
call Sleep on the Child process for x seconds.
Before the sleep finishes execution, I want to send a Ctrl+Z signal.
This signal should stop the child process, but resume the parent
process. The parent process should then know the process id of the
stopped process.
I run it using the command: ./testsig sleep 10
This is my code so far:
#include<stdlib.h>
#include<stdio.h>
#include<signal.h>
#include<string.h>
volatile sig_atomic_t last_proc_stopped;
volatile sig_atomic_t parent_proc_id;
void handle_stp(int signum)
{
if(getpid()==parent_proc_id)
{
kill(parent_proc_id,SIGCONT);
signal(SIGTSTP,handle_stp);
}
else
{
last_proc_stopped=getpid();
kill(parent_proc_id,SIGCONT);
}
}
void main(int argc, char *argv[])
{
int childid=0,status;
signal(SIGTSTP,SIG_IGN);
parent_proc_id=getpid();
childid=fork();
if(childid>=0)
{
if(childid==0)//child
{
signal(SIGTSTP,handle_stp);
strcpy(argv[0],argv[1]);
strcpy(argv[1],argv[2]);
argv[2]=NULL;
printf("Passing %s %s %s\n",argv[0],argv[1],argv[2]);
execvp(argv[0],argv);
}
else
{
wait(&status);
printf("Last Proc Stopped:%d\n",last_proc_stopped);
}
}
else
{
printf("fork failed\n");
}
}
Currently, it seems like ctrl+Z has some kind of effect (but definitely not the one I want!)
When I hit ctrl+Z in the middle of the child executing sleep, the cursor continues to blink for the remainder of the (in my case 10) seconds, but control does not reach the parent process.
Without hitting ctrl+Z, control returns to the parent as expected.
What am I doing wrong?
I have seen this answer as well, but I'm not really able to understand it:
After suspending child process with SIGTSTP, shell not responding
You have two processes:
The parent, which ignores the signal,
The child, which sets a handler, then execs another process - this will clear the code of the signal handler from the memory (the executed program will be loaded in place of the calling process), therefore will also clear the signal settings as well. So, your signal handler function will never be called. Is it possible to signal handler to survive after “exec”?
What you could do to achieve your goal?
The parent should ignore the signal,
The child should leave the default signal handling (which stops it),
The parent should use waitpid() to see if the child process exited or was stopped, and act accordingly (this involves actually killing the stopped child process).
I trying to make program reload itself after it receives signal. I have this code
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void signal_callback_handler(int signum){
printf("Caught signal %d\n",signum);
execv("./test", NULL); //reexec myself
}
int main()
{
signal(SIGINT, signal_callback_handler);
printf("Program STARTED\n");
while(1){
printf("Program processing stuff here.\n");
sleep(1);
}
return EXIT_SUCCESS;
}
The problem is that after exec program just ignore signal instead of calling signal handler.
Output:
Program STARTED
Program processing stuff here.
Program processing stuff here.
^CCaught signal 2
Program STARTED
Program processing stuff here.
^C^CProgram processing stuff here.
^C^C^C^C^CProgram processing stuff here.
^C^CProgram processing stuff here.
How to make signal handlers work after exec?
Signal masks are inherited across exec, and SIGINT is blocked during the invocation of your signal handler, which calls execve. Thus your re-exec'd image is started with SIGINT blocked.
If you strace the process, you'll see that your signal call becomes something like:
3143 rt_sigaction(SIGINT, {0xabcd, [INT], SA_RESTORER|SA_RESTART, 0xabcd}, {SIG_DFL, [], 0}, 8) = 0
^^^^^
|
+--- SIGINT is blocked during handler!
sigaction will give you finer control over the signal handler, and is recommended over signal.
Yor signal is blocked during execution of the signal handler, and the signal mask is inherited over exec. You need to reset it explicitly.
A potential problem here is that if you unblock inside the handler, and you have another signal pending, it will be delivered immediately, causing the handler to be executed again. This should be rare but it can happen.
Worse yet, if you unblock in the re-exec'd process and you have a signal pending, you may have it delivered to the re-exec'd process, potentially killing it. So set up a handler in the "child" first, then unblock.