I'm supposed to implement a signal handler which stops all the threads in the program the first time a certain signal is called, and resume them if they are already stopped. I implemented a demon thread running in the background using the following code:
void *handle_sig(void *arg)
{
sigset_t set;
//set set...
struct timespec to;
to.tv_sec = 1;
to.tv_nsec = 0;
while (_keepListening) {
int ret = sigtimedwait(&set, NULL, &to);
if (ret < 0)
if (errno == EAGAIN) {
continue; /* no signal sent*/
} else {
fprintf(stderr, "Failed...\n");
exit(1);
}
if (_state == PAUSE_STATE) { /* was blocked*/
//do something
} else {
` //do something else
}
}
return NULL;
}
The problem is that if a signal is sent and detected, and then another is sent before the while loop is entered again - the second signal is ignored, which can leave the program paused forever. is there a way of detecting if a signal was sent since the last call to sigtimedwait?
Thank you
You might think about making your processing asynchronous.
For example by starting a thread for "doing something" or "doing something else".
Related
I am trying to make a program that suspends its execution until a signal arrives. Then, after the signal arrives I just want my code to continue its execution from where it was. I don't want it to execute a function handler or whatsoever. Is there a simple way of doing this? I have been struggling for a week or so, reading here and there, and didn't manage to get a fully operative code.
In particular, I want the main program to create a thread that waits for some particular event to happen (e.g., a user has input some data to stdin). Meanwhile, the main program is doing something but at some point it suspends its execution until it receives a signal.
The signal may come from the thread because it has detected the event or it may be due to a timeout because I don't want it to wait for ever.
I have made some code but it does not work as expected...
/*
* This code SHOULD start a thread that gets messages from stdin.
* If the message is a "quit", the thread exits. Otherwise it raises
* a signal that should be caught by the main program.
* The main program simply waits for the message unless a timer of
* 5.5 seconds expires before receiving the signal from the thread.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include <signal.h>
#define BSIZE 100 /* Buffer size */
sigset_t mask;
pthread_t tid;
//struct itimerval timervalue;
int milisec = 5500; /* Timeout: 5,5 seconds */
int end = 0;
char buffer[BSIZE];
//Function prototypes
void init(void);
void * thread_job(void *);
void message_rcvd(void);
void wait_for_message_or_timeout(void);
int start_timer(struct itimerval, int);
int stop_timer(struct itimerval);
void on_signal(int);
// MAIN: Wait for message or timeout
int main(int argc, char ** argv) {
init();
while(!end){
wait_for_message_or_timeout();
if(!end)
printf("Message received [%s]\n", buffer);
}
return 0;
}
// INIT: Initializes the signals that the program will wait for
// and creates a thread that will eventually generate a signal
void init()
{
/* Init the signals I want to wait for with sigwait() */
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_BLOCK, &mask, NULL);
//signal(SIGUSR1, SIG_IGN);
signal(SIGUSR1, on_signal);
/* Create the thread and put it to work */
pthread_t tid;
pthread_create(&tid, NULL, thread_job, NULL);
}
void on_signal(int signum){
printf("on_signal\n");
}
// THREAD CODE -------------
// THREAD JOB: When the user inputs a message, it passes the message
// to the main thread by invoking message_rcvd()
void * thread_job(){
int end = 0;
while(!end){
printf("Input message:");
if (fgets(buffer, BSIZE, stdin) != NULL)
message_rcvd();
}
}
// MESSAGE RECEIVED: If message is not equal to "quit" raise a signal
void message_rcvd(){
if(strcmp(buffer, "quit") == 0){
exit(0);
}else{
printf("Going to raise SIGUSR1...");
if(raise(SIGUSR1) == 0)
printf("raised!\n");
}
}
// WAIT: Should wait for signal SIGUSR1 for some time
void wait_for_message_or_timeout(){
int sigid;
struct itimerval t;
/* Set a timer to prevent waiting for ever*/
printf("Setting timer...\n");
start_timer(t, milisec);
/* Put the process to wait until signal arrives */
sigwait(&mask, &sigid);
switch(sigid){
case SIGUSR1:
printf("Received SIGUSR1: Message avaible!\n");
break;
case SIGALRM:
printf("Received SIGALRM: Timeout\n");
end = 1;
break;
default:
printf("Unknown signal received\n");
break;
}
printf("Stopping timer...\n");
/* Stop timer */
stop_timer(t);
}
// START TIMER: I don't want the timer to cause the execution
// of a handler function
int start_timer(struct itimerval timervalue, int msec)
//int start_timer(int msec)
{
timervalue.it_interval.tv_sec = msec / 1000;
timervalue.it_interval.tv_usec = (msec % 1000) * 1000;
timervalue.it_value.tv_sec = msec / 1000;
timervalue.it_value.tv_usec = (msec % 1000) * 1000;
if(setitimer(ITIMER_REAL, &timervalue, NULL))
{
printf("\nsetitimer() error\n");
return(-1);
}
return(0);
}
// STOP TIMER:
int stop_timer(struct itimerval timervalue)
//int stop_timer()
{
timervalue.it_interval.tv_sec = 0;
timervalue.it_interval.tv_usec = 0;
timervalue.it_value.tv_sec = 0;
timervalue.it_value.tv_usec = 0;
if(setitimer(ITIMER_REAL, &timervalue, NULL))
{
printf("\nsetitimer() error\n");
return(-1);
}
return(0);
}
Here is a typical execution of this code.
./signaltest
Setting timer...
Input message:hello
Going to raise SIGUSR1...raised!
Input message:friend
Going to raise SIGUSR1...raised!
Input message:Received SIGALRM: Timeout
Stopping timer...
As you can see, the signal SIGUSR1 is being raised and sigwait is being unblocked. However, the code seems does not continue after the signal has been raised. (Note that I don't need a signal handler but I just added for the debugging purposes. I have blocked its execution with sigprocmask)
Why is SIGUSR1 unblocking sigwait but the execution does not continue from there? Is there a way to make it continue after unblocking? This seems to work for SIGALRM but why not for SIGUSR1?
As I said, I have been looking at tons of stackoverflow questions, online howto's, tried with different system calls (e.g., pause, sigsuspend), ... but couldn't find a way to solve this :-(
If you are wondering why I am not doing this code much simpler by not using a thread is because this is not actually the code I am implementing but just a simpler example to make my question more clear. I am actually trying to implement a network protocol API, similar to the sockets API for my own protocol.
Thanks in advance
The SIGUSR1 signal isn't going where you think it is.
In a multithreaded program, the raise function sends a signal to the current thread, which is the thread_job thread in this case. So the main thread never sees the signal.
You need to save off thread ID of the main thread, then use pthread_kill to send a signal to that thread.
Add a new global:
pthread_t main_tid;
Then populate it in your init function before starting the new thread:
void init()
{
main_tid = pthread_self();
...
Then in message_rcvd, use pthread_kill:
if(pthread_kill(main_tid, SIGUSR1) == 0)
printf("raised!\n");
Also, remove the definition of end in thread_job, and remove the definition of tid in init. These definitions mask the global variables of the same name.
Sample output:
Setting timer...
Input message:hello
Going to raise SIGUSR1...raised!
Input message:Received SIGUSR1: Message avaible!
Stopping timer...
Message received [hello
]
Setting timer...
test
Going to raise SIGUSR1...raised!
Input message:Received SIGUSR1: Message avaible!
Stopping timer...
Message received [test
]
Setting timer...
Received SIGALRM: Timeout
Stopping timer...
I'm reading http://250bpm.com/blog:12 to understand how EINTR should/could be handled and I have trouble reconciling the second and third source code snippet with description.
Second listing:
volatile int stop = 0;
void handler (int)
{
stop = 1;
}
void event_loop (int sock)
{
signal (SIGINT, handler);
while (1) {
if (stop) {
printf ("do cleanup\n");
return;
}
char buf [1];
recv (sock, buf, 1, 0);
printf ("perform an action\n");
}
}
Third listing:
volatile int stop = 0;
void handler (int)
{
stop = 1;
}
void event_loop (int sock)
{
signal (SIGINT, handler);
while (1) {
if (stop) {
printf ("do cleanup\n");
return;
}
char buf [1];
int rc = recv (sock, buf, 1, 0);
if (rc == -1 && errno == EINTR)
continue;
printf ("perform an action\n");
}
}
Specifically:
POSIX specification defines that when signal (such as Ctrl+C) is caught, recv returns EINTR error. That allows the event loop to wrap over and check the 'stop' variable:
But the explanation given for supposed blocking in 2nd listing is that:
The problem is that recv is a blocking function. If Ctrl+C is pressed
while the event loop is blocked in recv, you'll get a kind of
deadlock: Signal handler is executed as expected, it sets 'stop' to 1,
but then the execution blocks. The event loop is stuck in recv and has
no opportunity to check whether 'stop' was set to 1.
Well, signal handler is defined in both cases and so the SIGINT is caught, therefore it seems like recv should unblock in both cases, no?
I really didn't get how signal handlers work especially with forks. So i need to do this exercise but i couldn't get it work properly.
My main program makes 5 forks, each fork prints simply 10 messages with its pid. So the purpose of the program, when i send a SIGINT signal via keyboard(Ctrl-c) it should print, "a single SIGINT arrived", if two SIGINT arrives between one second, it should print "double SIGINT arrived" and should terminate the whole program. So when i launch my program, it handles first two SIGINT(that i send the second more than 1 second after the first one) but then it doesn't handle single SIGINT and neither double SIGINT.
So i'm very confused about signals. Forks continue to stamp messages. I load same handler both to main and to forks but what should i do to terminate all forks when arrives double SIGINT? Should i call killl or some other function in handler to terminate them?
the main function
/* libraries... */
volatile sig_atomic_t double_sigint = 0;
int64_t time_diff = 0;
int main()
{
int i;
int pid;
sigset_t set;
struct sigaction sa;
/* mask all signals */
/*H*/ if(sigfillset(&set) == -1 )
/*A*/ {perror("sigfillset"); exit(errno);}
/*N*/
/*D*/ if(sigprocmask(SIG_SETMASK,&set,NULL) == -1)
/*L*/ {perror("sigfillset"); exit(errno);}
/*E*/
/*R*/ memset(&sa,0,sizeof(sa));
/*B*/
/*L*/ sa.sa_handler = handler;
/*O*/
/*C*/ if(sigaction(SIGINT, &sa, NULL) == -1)
/*K*/ {perror("sigaction"); exit(errno);}
/**/
/**/ /* unmask all signals */
/**/ if( sigemptyset(&set) == -1 )
/**/ {perror("sigepmtyset"); exit(errno);}
/**/
/**/ if(sigprocmask(SIG_SETMASK,&set,NULL) == -1 )
/**/ {perror("sigprocmask"); exit(errno);}
for(i=0;i<5;++i)
{
if((pid = fork()) == -1)
{ perror("rec:fork"); exit(errno); }
if(pid == 0)/* figlio */
{
/* SAME HANDLER BLOCK IS HERE */
foo(i);
return;
}
sleep(1);
}
return 0;
}
foo function
void foo(int i)
{
int k;
for(k=0; k<10; ++k)
{
printf("%d. fork %d. print\n", i, k);
sleep(1);
}
}
signal handler
void handler (int signum) {
struct timespec sig1;
struct timespec sig2;
if(double_sigint == 0)
{
if(clock_gettime(CLOCK_REALTIME, &sig1))
{ perror("failed to get sig1 time"); exit(errno); }
write(1,"Received single SIGINT\n",18);
double_sigint = 1;
}
else if(double_sigint == 1)
{
if(clock_gettime(CLOCK_REALTIME, &sig2))
{ perror("failed to get sig2 time"); exit(errno); }
time_diff = (sig2.tv_sec - sig1.tv_sec) + (sig2.tv_nsec - sig1.tv_nsec)/1000000000;
if(time_diff < 1)
{
double_sigint = 2;
write(1,"Received double SIGINT\n",18);
_exit(EXIT_FAILURE);
}
else
{
sig1.tv_sec = sig2.tv_sec;
sig1.tv_nsec = sig2.tv_nsec;
write(1,"Received single SIGINT\n",18);
}
}
}
When you receive a double-SIGINT, you only kill the parent process, with the line _exit(EXIT_FAILURE);. The forks you have created before are not killed and keep running, their parent now being the init process.
If you want all the children to terminate, you have to kill them manually. Maybe this post would be helpful : How to make child process die after parent exits
Edit: That was not the problem since Ctrl+C sends a SIGINT to all the children (see comments).
What worked for me was :
As said in William Pursell's comment, make sig1 and sig2 global variables.
Make the parent process always run (just added a while (1); before the return statement), because some signals were not taken into account once the parent process was terminated.
In the handler, in the else clause (double_sigint == 1) you are comparing sig2 and sig1, but sig1 is uninitialized. The value that you gave it the first time the handler was called went away when that handler returned. You could simply give those variables file scope.
By using the uninitialized value of the local variable, you are getting undefined behavior. If the signal handler is called and the signal handling stack happens to be in the same state it was on the previous call, then things may work fine. This can happen if you send the signal twice with no intervening signals, for example. Since sleep is likely implemented with a signal, it is quite likely that the stack has been modified since the previous call and sig1 is not what you expect. However, speculation about undefined behavior is somewhat pointless.
i want to try to program a small shell on my own, because it is a nice way to learn signals.
But somehow i have some problems to suspend a process and also continue it later.
execute_command() should be the interesting part, because before i'm only splitting the inputted information.
void execute_command(){
int status = 0;
pid_t childprocess= fork();
int wait_state=0;
if(arg_list[0] == NULL){
exit(0);
}
if(childprocess <0 ){
printf(" Could not create childprocess");
}else if (childprocess == 0){
int end_state =execvp(*arg_list,arg_list);
if(end_state < 0){
printf("Some kind of Error happens here \n");
}else if(end_state == 0){
// printf("Program exited with %d\n",end_state);
}
exit(0);
}else{
current_process_id = childprocess;
register_signals();
last_pid = getpid();
/*When i have found a '&' */
if(!background_process){
do{
waitpid(childprocess,&status,WUNTRACED);
if( WIFSTOPPED(status) ) {
// later for conitinuing the suspended process
last_pid = childprocess;
kill(last_pid,SIGSTOP); // edited line of code !
}
}while( !WIFEXITED(status) && !WIFSIGNALED(status));
}
}
}
void register_signals(){
signal(SIGINT,signal_int_handler);
signal(SIGTSTP,signal_stop_handler);
}
mysignal.c:
void signal_int_handler(int signum){
printf("[caught SIGINT]\n");
}
void signal_kill_handler(int signum){
}
void signal_stop_handler(int signum){
printf("[caught SIGTSTP]\n");
}
When i press "Ctrl+z" the signal_action execute and print the message from the command signal_stop_handler.
But the program is still running in the do-while-loop.
Maybe i have misunderstood something.
My test input is : sleep 50
I only want to suspend a process and also continue it later.
Can someone give me a hint?
Edit: i have edit the code, depend on the answer, but it doesn't works
If you catch SIGTSTP in your program, it won't be suspended. Suspend is its default behavior and it goes away once a custom handler is installed. There is also SIGTSTOP which can't be diverted and suspends the process in all cases.
So I have the following code segment as part of my program. Handler is the handler for the SIGALRM.
static void handler(void)
{
//DISABLE SIGALRM
sigset_t oldset;
disable_sigalrm(&oldset);
if(queue_length(&queue) == 0)
{
ucontext_t context;
getcontext(&context);
swapcontext(&context,&uctxt_main);
}
else
{
//...
//enable sigalarm
}
}
The program disable_sigalrm looks as follows:
void disable_sigalrm(sigset_t* oldset)
{
sigset_t sset;
//Empty sset
if(sigemptyset(&sset) == -1)
{
printf("Error in emptying the signal set.\n");
}
//Add SIGALRM to sset
if(sigaddset(&sset,SIGALRM) == -1)
{
printf("Error in adding SIGALRM to the specified signal set.\n");
}
//Block any occurence of SIGALRM
if(sigprocmask(SIG_BLOCK,&sset,oldset) == -1)
{
printf("Error in adding the specified signal; set to the signal mask.\n ");
}
}
Now when I run in the debugger even after the queue length reaches zero it keeps coming back to handler.
Since the SIGALRM is disabled, the only explanation that makes sense is if there are multiple signals waiting to reach the handler. Is it possible that multiple signals can wait to run to the handler? If so how would you disable them running the handler?