Catching SIGTERM, and sleep preventing it working - c

I have some code written in C (working on ubuntu 17):
void sig_stop(int sig_num) {
/* Some cleanup that needs to be done */
}
void some_routine(const char *array[], const int length) {
/* Initialization */
signal(SIGTERM, sig_stop);
while (true) {
/* Some function */
/* I have this sleep to minimize the load on the CPU
as I don't need to check the conditions here
all the time. */
sleep(5);
}
}
Whenever I include the 5 minute sleep (sleep(5)), it appears sig_stop isn't called. However, when I comment out the sleep(5), the sig_stop cleanup works just fine. Have I got something wrong with my understanding of how to catch SIGTERM?
If I can't use the sleep function, is there a better way to "sleep" the program" so that it only runs the loop every x minutes or in such a way that minimizes the CPU load?

sleep() and signals
sleep() should not prevent the signal from being caught and the signal handler being executed. From the manpage for sleep() (emphasis mine):
sleep() causes the calling thread to sleep either until the number of real-time seconds specified in seconds have elapsed or until a signal arrives which is not ignored.
Take the following example ...
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
static volatile sig_atomic_t flag = 0;
static void sig_stop(int signum) { flag = 1; }
int main(void) {
int secs_remaining = 0;
signal(SIGTERM, sig_stop);
while (!flag) {
printf("Sleeping at time %d\n", time(NULL));
secs_remaining = sleep(5);
}
printf(
"Flag raised. Exiting at time %d. sleep() was interrupted %d seconds "
"early ...\n",
time(NULL), secs_remaining);
return 0;
}
Note that - in the case where it was interrupted by a signal - sleep() returns the number of seconds left to sleep. E.g., if it is interrupted 3 seconds early it will return 3. It will return 0 if it is not interrupted.
Compile as gcc -o test test.c and run. Then from another terminal run
pkill -15 test
You will see output similar to the following ...
Sleeping at time 1532273709
Flag raised. Exiting at time 1532273711. sleep() was interrupted 2 seconds early ...
By the way ... sleep(x) sleeps for x seconds - not minutes.
signal() vs sigaction()
Due to portability issues associated with signal(), it is often recommended to use sigaction() instead. The use of sigaction() would be something like the following.
int main(void) {
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = sig_stop;
if (sigaction(SIGTERM, &sa, NULL) == -1) {
perror("sigaction");
return 1;
}
// Etc.
}
As you can see the usage of sigaction() is a little more verbose than that of signal(). Perhaps that's why people still sometimes use signal().

Related

GDB, signals and SIG_IGN

Setting a signal handler as SIG_IGN ignores the signal while running the program normally but not while running it through gdb.
I'm creating a timer using timer_create and timer_settime functions. I don't want to use a signal handler (i.e a function) to handle the signals generated by this timer. I decided to use sigwait and wait for SIGALRM. I set the handler for SIGALRM as SIG_IGN and used sigwait.
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#define TRUE 1
#define ISTRUE(x) (x != 0)
#define bool int
int main() {
struct itimerspec timer_spec;
struct sigevent sig_event;
timer_t timer_id;
sigset_t sig_set;
timer_spec.it_interval.tv_sec = 1;
timer_spec.it_interval.tv_nsec = 0;
timer_spec.it_value.tv_sec = 1;
timer_spec.it_value.tv_nsec = 0;
sig_event.sigev_signo = SIGALRM;
sig_event.sigev_notify = SIGEV_SIGNAL;
signal(SIGINT, SIG_IGN);
signal(SIGALRM, SIG_IGN);
/* Create the timer */
timer_create(CLOCK_REALTIME, &sig_event, &timer_id);
timer_settime(timer_id, 0, &timer_spec, NULL);
sigemptyset(&sig_set);
sigaddset(&sig_set, SIGALRM);
int signal = 0;
bool running = TRUE;
while (ISTRUE(running)) {
sigwait(&sig_set, &signal);
switch(signal){
case SIGINT:
printf("Interrupt received.. exiting\n");
running = 0;
break;
case SIGALRM:
printf("Ticked\n");
break;
}
printf("Sleeping\n");
}
return 0;
}
While debugging the application in my IDE (CLion) as well as using gdb from the shell, the program functioned as expected. SIGALRM was not being ignored, which led me to believe that what I was doing was right. However, running the application normally, sigwait never returns.
I later realized that this was because the signal was being ignored and I needed to block the signal (using sigprocmask or similar) and set it to a pending state.
Why does, while debugging, the signal get passed through? Is this supposed to happen? What am I missing?
You should look into the handle gdb command:
(gdb) handle SIGALRM
Signal Stop Print Pass to program Description
SIGALRM No No Yes Alarm clock
(gdb) handle SIGALRM ignore
Signal Stop Print Pass to program Description
SIGALRM No No No Alarm clock
(gdb) help handle
... read it ;-) ...
As mentioned in the manpage of ptrace(2) (which gdb is using):
While being traced, the tracee will stop each time a signal is delivered, even if the signal is being ignored.

can't get alarm() to work more than twice

static void AlarmHandler(int sig) ;
int i=0;
jmp_buf mark;
int main(int argc, char * argv[]){
setjmp(mark);
signal(SIGALRM, AlarmHandler);
alarm(2);
while(1);
return 0;
}
static void AlarmHandler(int sig) {
signal(SIGALRM, SIG_IGN);
printf("I am in AlarmHandler: %d \n",i);
i++;
longjmp(mark, 0);
}
When I run this code the program goes through the AlarmHandler only once and then it just stays trapped inside the while loop. Can someone explain why?
Your program might work as you expected on some POSIXy operating systems -- in fact, it does work as you expected on the computer I'm typing this on. However, it relies on a bunch of unspecified behavior relating to signals, and I think you've tripped over one of them: I think that on your computer, a signal is "blocked" — it can't be delivered again — while its handler is executing, and also, jumping out of the handler with longjmp does not unblock the signal. So you go around the loop once and then the second SIGALRM is never delivered because it's blocked. There are several other, related problems.
You can nail down all of the unspecified behavior and make the program reliable on all POSIXy operating systems, but you have to use different functions to set things up: sigsetjmp and sigaction. You should also get rid of the busy-waiting by using sigsuspend instead. A corrected program would look something like this:
#define _XOPEN_SOURCE 700
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <unistd.h>
static jmp_buf mark;
static void
handle_SIGALRM(int sig)
{
static int signal_count;
signal_count++;
printf("SIGALRM #%u\n", signal_count);
siglongjmp(mark, signal_count);
}
int
main(void)
{
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
if (sigprocmask(SIG_BLOCK, &mask, &omask)) {
perror("sigprocmask");
return 1;
}
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0; // DO interrupt blocking system calls
sa.sa_handler = handle_SIGALRM;
if (sigaction(SIGALRM, &sa, 0)) {
perror("sigaction");
return 1;
}
if (sigsetjmp(mark, 1) >= 4)
return 0;
alarm(1);
sigsuspend(&omask);
perror("shouldn't ever get here");
return 1;
}
I should probably say a few words about signal safety: In this program, it is safe to call printf and siglongjmp from the signal handler, because I have arranged for the SIGALRM only to be deliverable while the main thread of execution is blocked on sigsuspend. (That's what the call to sigprocmask up top does.) If you had anything to do in your main thread of execution besides sleep waiting for the signal to arrive, you would have to be much more careful about what you did in the signal handler, and I would advocate for using pselect and/or the self-pipe trick instead of jumping out of the handler, if at all possible.

Interval Timer not firing signal at specified time interval

I want to call timer_handler function at every 2 seconds regardless of execution time of timer_handler function here is my code
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
void timer_handler (int signum)
{
static int count = 0;
sleep(1);
printf ("timer expired %d times %d signum \n", ++count, signum);
}
int main ()
{
struct sigaction sa;
struct itimerval timer;
/* timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timer_handler;
sigaction (SIGVTALRM, &sa, NULL);
/* Configure the timer to expire after 2000 msec... */
timer.it_value.tv_sec = 2;
timer.it_value.tv_usec = 0;
/* ... and every 2000 msec after that. */
timer.it_interval.tv_sec = 2;
timer.it_interval.tv_usec = 0;
/* Start a virtual timer. It counts down whenever this process is
executing. */
setitimer (ITIMER_VIRTUAL, &timer, NULL);
/* Do busy work. */
while (1);
}
As per above code it should print timer expired 1 times 26 signum at every two second but its prints on every 3 seconds which includes sleep time so i want to call that function on every 2 seconds.
I don't know where i am doing wrong
If any other library is able to do this please let me know
Thank you
Why not use wall-clock time?
To do so
install the signal handler for SIGALRM instead of SIGVTALRM and
specify ITIMER_REAL instead of ITIMER_VIRTUAL.
Unrelated but important: Signal handlers may only call async-signal-safe functions. printf() is not one of those. For a list of the latter click here and scroll down.
the call, in the signal handler: sleep(1) is adding an extra second to the processing of the signal. This extra second is not part of the execution time of the process.
remove from the signal handler:
sleep(1);
regarding:
setitimer (ITIMER_VIRTUAL, &timer, NULL);
since you want to see the signal handler executed every 2 seconds, the proper timer to use is: ITIMER_REAL not ITIMER_VIRTUAL. This will result in the 'clock on the wall' time being measured rather than the 'process run' time being measured.
Strongly suggest having the signal handler ONLY set a flag. Then the 'do nothing' loop in the main function be checking that flag, reset the flag, then call printf()` To properly accomplish this, with out an 'race' conditions, use a mutex/ Both the main and the signal handler would lock the mutex, modify the flag, then unlock the mutex.

Why the signal pause will cause the program to sleep forever?

The APUE book says that: If the signal occurs after the test of sig_int_flag but before the call to pause, the process could go to sleep forever.
I don't know why, can somebody tells me?
Thanks a lot.
int sig_int(); /* my signal handling function */
int sig_int_flag; /* set nonzero when signal occurs */
int main() {
signal(SIGINT, sig_int) /* establish handler */
.
.
.
while (sig_int_flag == 0)
pause(); /* go to sleep, waiting for signal */
}
int sig_int() {
signal(SIGINT, sig_int); /* reestablish handler for next time */
sig_int_flag = 1; /* set flag for main loop to examine */
}
If an interrupt signal is issued at the precise time you're describing:
the flag has been checked false: entering loop
signal resets itself, setting the flag to 1, but too late (test has been done)
since loop has already been entered, pause() is called and the program waits
That said, if CTRL+C/SIGINT is triggered another time, you can exit the loop, so it's not that critical, since that signal can be issued manually.
If you want to check that behaviour, I suggest you add a sleep statement:
while (sig_int_flag == 0)
{
printf("Hit CTRL+C in the next 10 seconds to trigger the bug\n");
sleep(10);
pause(); /* go to sleep, waiting for signal */
}
A workaround would be to remove the pause() statement and replace it by a polling loop:
while (sig_int_flag == 0)
{
sleep(1);
}
If a SIGINT occurs anywhere in the loop, including between the while and the sleep, then the worse thing that can happen is that the program waits 1 second before noticing that the flag is set, then it exits the loop, and the other, more plausible case it that the sleep call is interrupted, and the loop is exited immediately, so when the signal is set, there's little visible difference between that and a pause call if we only expect SIGINT.
The question's already answered. However, additional answer can consolidate the idea.
while (sig_int_flag == 0) {
<----- think it signal is caught here before pause btw while and pause()
pause(); /* go to sleep, waiting for signal */
}
Having caught, signal handler runs. After it finishes its task, it returns to a point at which the signal is caught, in main() in this case. So, the point is pause() and pause() is called. It waits again SIGINT to catch. To exemplify it, I add sleep(5) equivalently to catch prior pause().
So, we typically want the second situation. To achieve it always, the aforementioned code block has to be atomic. That's why sigsuspend() is better and should be used.
If you would like to experience the fallible case,
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
volatile sig_atomic_t sig_int_flag = 0; /* set nonzero when signal occurs */
char const * handlerMsg = "in handler\n";
int handlerMsgLen;
void sig_int(int s) {
signal(SIGINT, sig_int); /* reestablish handler for next time */
sig_int_flag = 1; /* set flag for main loop to examine */
write(2, handlerMsg, handlerMsgLen);
}
void mySleep() {
for (int i = 0; i < 5; ++i) {
sleep(1);
fprintf(stderr, "%d ", i + 1);
}
}
int main() {
handlerMsgLen = strlen(handlerMsg);
signal(SIGINT, sig_int); /* establish handler */
while (sig_int_flag == 0) {
mySleep();
pause(); /* go to sleep, waiting for signal */
}
}

setjmp/longjmp between threads to handle timeout

I'm porting a software from an embedded computer to a Linux machine. (Ubuntu 14.04 or Raspbian (raspberry pi))
The original program was using setjmp/longjmp to handle timeout and CTRL+C event. It was running on a Microcontroller with a single main (one thread).
I'm trying to have a similar behaviour while using threads (pthreads).
The idea is that I want either a timeout or a CTRL+C to restart an infinite loop.
The original code was doing something like the code below. I don't mind to drop the setjmp/longjmp by something else. (ex: try/catch or signal or pthread_kill, conditional variable, etc..)
Any idea how to implement similar behavior with C/C++ ?
Here is the code which seems to partially work and is probably not recommended/broken:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <setjmp.h>
// Define
#define TICK_NS_TIME (10000000) // 0.01 sec = 10 ms (100 times per second)
#define NS_PER_SEC (1000000000) // Nano sec per second.
#define TICK_PER_SEC (NS_PER_SEC/TICK_NS_TIME) // Number of tick per second (Ex:100)
#define TIMEOUT_COUNT (30*TICK_PER_SEC) // 30 seconds timeout (with 100 tick per second)
// Env set/long jmp
#define ENV_SZ (2)
#define ENV_TIMEOUT (0)
#define ENV_CTRLC (1)
static jmp_buf env[ENV_SZ];
// Variables
int timeout_val;
// sig handler.
void signal_handler(int signo)
{
pthread_t self = pthread_self();
printf("Thread %lu in signal handler\n", (long)self);
if (signo == SIGINT) {
longjmp(env[ENV_CTRLC], 1); // Q?: Is it in the same thread ? (Never, Always, Sometimes?)
}
else
{
printf("Other signal received..quitting."); // Ex: kill -9 pid
exit(0);
}
}
// thread timer function
void* timer_function(void* in_param)
{
// Loop approx 100x per second.
for (;;) {
nanosleep((const struct timespec[]){{0, TICK_NS_TIME }}, NULL); // Sleep 10 ms seconds.
if (timeout_val) {
if (!--timeout_val) {
longjmp(env[ENV_TIMEOUT], 1); // longjmp when timer reaches 0. (Q?: Is this valid with multithread?)
}
}
}
}
// main
int main(int argc, char **argv)
{
int i;
int val;
struct sigaction actions;
pthread_t thread;
setvbuf (stdout, NULL, _IONBF, 0); // Make sure stdout is not buffered (ex:printf, etc.)
printf("[Program started]\r\n");
memset(&actions, 0, sizeof(actions));
sigemptyset(&actions.sa_mask);
actions.sa_flags = 0;
actions.sa_handler = signal_handler;
val = sigaction(SIGINT, &actions, NULL);
pthread_create(&thread, NULL, timer_function, NULL); // timer thread for example
printf("[Timer thread started]\r\n");
// setting env.
val = setjmp(env[ENV_TIMEOUT]);
if (val!=0){ printf("[JMP TIMEOUT]\r\n"); }
val = setjmp(env[ENV_CTRLC]);
if (val!=0){ printf("[JMP CTRLC]\r\n"); }
// main loop
timeout_val = TIMEOUT_COUNT;
i = 0;
for (;;)
{
i++;
if (i > 10){ i = 0; printf("[%d]", timeout_val/TICK_PER_SEC); } // Number of seconds before time out.
sleep(1);
printf(".");
}
printf("Main completed\n");
return 0;
}
//Compile: g++ -pthread main.cpp -o main
Suggestion for alternative implementation would be great since I'm new to programming with threads !
setjmp() saves the information required to restore the calling environment. longjmp() can then restore this environment, but only within the same thread.
The C11 standard is explicit about the constraint of having the same thread:
7.13.2.1/2 If there has been no such invocation (i.e: of a previous setjmp), or if the invocation was from another thread of
execution, or if the function containing the invocation of the
setjmp macro has terminated execution in the interim, or if the
invocation of the setjmp macro was within the scope of an identifier
with variably modified type and execution has left that scope in the
interim, the behavior is undefined.
In fact, setjmp/longjmp are generally implemented by saving the stack pointer so that restoring it makes sense only int the same execution context.
Alternative
Unless I've missed something, you use the second thread only to act as a timer. You could instead get rid of your POSIX pthread, and use a timer signal activated with POSIX timer_create().
But be aware that using setjmp/longjmp from a signal handler (so already in your original code for CTRL+C) is tricky, as explained in this SO answer. So you'd consider sigsetjmp/siglongjmp.
For the records: C or C++ ?
Your question is tagged C. But you mention c++ try and catch. So for the sake of completeness:
in C++ setjmp should be replaced by a try/catch and the longjmp by throwing an exception. setjmp/longjmp are supported in C++ only if unwinding the stack wouldn't require invocation of any non-trivial destructor (see C++ standard, 18.10/4).
the exceptions are not propagated across the threads, unless catched and explicitely rethrown using std::rethrow_exception(). It's delicate, so refer to this SO question for for additional details. But it's possible and could solve your issue.

Resources