I need to measure the time it takes to handle an exception and invoke a signal handler 100,000 times. I need to use signal()system call to register a handler function for SIGFPE then i need to cause a divide by 0 error.
I only have a skeleton right now and am not sure how I should handle the signal. So far I plan on calling gettimeofday() then entering in a for loop 100k times to invoke the signal() then another gettimeofday() in order to end the time and then take the total elapsed time and average it out over those 100k invocations.
#include <signal.h>
#include <sys/time.h>
void handle_sigfe(int signum)
{
//unsure how to handle the signal to keep the loop running for 100k times
}
double time_in_milli (struct timeval t){ //for time conversion
return (((t.tv_sec*1000000+t.tv_usec)*1000)/1000000);
}
int main(int argv, char ** argv)
{
int x =5;
int y = 0;
int z = 0;
signal(SIGFPE, handle_sigfpe);
z = x/y;
return 0;
}
Anyone have any clue on how I need to handle this signal? I am completely lost on this
A divide-by-zero exception invokes the handler that you installed. When the handler returns, the processor goes back to the division instruction and tries again. The result is an infinite loop. To prevent that, you can use the sigsetjmp and siglongjmp routines.
When you call sigsetjmp it returns 0. However, when siglongjmp is called, the program behaves as if sigsetjmp returns the value supplied by siglongjmp. So you can use an if statement to execute the division or skip the division based on the return value from sigsetjmp.
If that's too confusing, hopefully the following example will clear things up.
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
static sig_atomic_t caught = 33;
static sigjmp_buf env;
void action( int unused )
{
caught = 42;
siglongjmp( env, 1 );
}
int main( void )
{
if ( signal( SIGFPE, action ) == SIG_ERR ) {
perror( "signal failed" );
return 1;
}
int x = 1;
int y = 0;
int z;
if ( sigsetjmp( env, 1 ) == 0 )
z = x / y;
printf( "%d\n", caught );
}
The global variable caught is used to indicate that the exception was caught. The initial value is 33. The signal handler sets it to 42. The printf at the end of the program displays the final value. It should print 42 to indicate the that signal was caught.
The global variable env is used by the sigsetjmp and siglongjmp functions to save a copy of the registers and stack.
The if (sigsetjmp(env,1) == 0) will initially be true, and the division will be attempted. But when the handler is invoked, siglongjmp will make the program behave as if sigsetjmp returned 1, and the division will be skipped.
This allows the program to move past the division, and execute the printf at the end.
Related
I am trying to implement a code which continuously switched between functions fun() and main() which do nothing but to print on screen infinitely. I am trying to switch by setjmp and longjmp and using SIGALRM signal in C.
But when I run it, it just works once and then doesn't switch.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
jmp_buf b1, b2;
int cur = 0;
void handlesig(int sig) {
if(!cur) {
cur = 1;
setjmp(b2);
longjmp(b1, 1);
}
else {
cur = 0;
setjmp(b1);
longjmp(b2, 1);
}
}
void fun() {
while(1) {
printf("I am in function fun()\n");
for(int x = 0; x < 100000000; x++);
}
}
int main() {
signal(SIGALRM, handlesig);
ualarm(900000, 900000); //send SIGALRM after each 900000 microseconds
if(!setjmp(b1))
fun(); //will be run when setjmp returns 0
while(1) {
printf("I am in function main()\n"); //will be run when setjmp returns 1
for(int x = 0; x < 100000000; x++);
}
return 0;
}
I am not getting what is the problem with this code.
Your program has undefined behavior because the lifetime of the block where setjmp was called on b1 or b2 in the signal handler ends as soon as longjmp is called (in the very next line). The next time you call longjmp trying to return to a jmp_buf that is no longer valid, the behavior is undefined, and this manifests as the state being utterly corrupted.
You can write a hack to work around this by using sigaltstack and SA_ONSTACK flag for the signal handler to have multiple stacks, so that even though the jmp_buf is formally invalid, it's in practice not clobbered. But this is not a valid program, just one which happens to work in practice on some systems (not all). Ultimately, there is no (valid/reliable) way to do what you're asking for with setjmp and longjmp; context switching requires a strictly stronger primitive than what they provide.
I have a simple program using signal with the user's handlers.
#include <signal.h>
#include <stdio.h>
#include <zconf.h>
int x = 0;
int i = 3;
void catcher3(int signum) {
i = 1;
}
void catcher2(int signum) {
// Stuck in infinity loop here.
// Happens even with i == 0
if (i != 0) {
x = 5;
}
}
void catcher1(int signum) {
printf("i = %d\n", i);
i--;
if (i == 0) {
signal(SIGFPE, catcher2);
signal(SIGTERM, catcher3);
}
}
int main() {
signal(SIGFPE, catcher1);
x = 10 / x;
printf("Goodbye");
}
While I expect it to print:
3
2
1
Goodbye
It actually prints:
3
2
1
# Infinity loop within catcher2
My questions are:
On running a user handler like catcher1, to which point the code returns after the handler's execution? I would expect it continue the execution but it re-runs the signal handler.
What causes the infinity loop?
How to fix it?
Why sending SIGTERM won't print "Goodbye"? (kill -s TERM <pid>)
As pointed out by AProgrammer, the program doesn't necessarily read x after returning from the handler, even if x is marked volatile (which it should be anyway). This is because the execution continues to the offending instruction. The read from memory and the actual division could be separate instructions.
To get around this you will have to continue the execution to a point before x was read from memory.
You can modify your program as follows -
#include <csetjmp>
jmp_buf fpe;
volatile int x = 0; // Notice the volatile
volatile int i = 3;
void catcher2(int signum) {
if (i != 0) {
x = 5;
longjump(fpe, 1);
}
}
int main() {
signal(SIGFPE, catcher1);
setjump(fpe);
x = 10 / x;
printf("Goodbye");
}
Rest of the functions can remain the same.
You should also not be using printf from the signal handler. Instead use write directly to print debug messages as -
write(1, "SIGNAL\n", sizeof("SIGNAL\n"));
The handling of signals is complex and full of implementation defined, unspecified and undefined behavior. If you want to be portable, there is in fact very few things that you can do. Mostly reading and writing volatile sig_atomic_t and calling _Exit. Depending on the signal number, it is often undefined if you leave the signal handler in another way than calling _Exit.
In your case, I think FPE is one of those signals for which leaving normally the signal handler is UB. The best I can see is restarting the machine instruction which triggered the signal. Few architectures, and last I looked x86 was not one of them, provide a way to do 10/x without loading x in a register; that means that restarting the instruction will always restart the signal, even if you modify x and x us a volatile sig_atomtic_t.
Usually longjmp is also able to leave signal handler. #Bodo confirmed that using setjmp and longjmp to restart the division, you can get the behavior you want.
Note: on Unix there is another set of functions, sigaction, siglongjump and others, which is better to use. In fact I don't recommend using something else in any serious program.
I am trying to handle a SIGFPE signal but my program just crashes or runs forever. I HAVE to use signal() and not the other ones like sigaction().
So in my code I have:
#include <stdio.h>
#include <signal.h>
void handler(int signum)
{
// Do stuff here then return to execution below
}
int main()
{
signal(SIGFPE, handler);
int i, j;
for(i = 0; i < 10; i++)
{
// Call signal handler for SIGFPE
j = i / 0;
}
printf("After for loop");
return 0;
}
Basically, I want to go into the handler every time there is a division by 0. It should do whatever it needs to inside the handler() function then continue the next iteration of the loop.
This should also work for other signals that need to be handled. Any help would be appreciated.
If you have to use signal to handle FPE or any other signal that you cause directly by invoking the CPU nonsense that causes it, it is only defined what happens if you either exit the program from the signal handler or use longjmp to get out.
Also note the exact placement of the restore functions, at the end of the computation branch but at the start of the handle branch.
Unfortunately, you can't use signal() like this at all; the second invocation causes the code to fall down. You must use sigaction if you intend to handle the signal more than once.
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <string.h>
jmp_buf fpe;
void handler(int signum)
{
// Do stuff here then return to execution below
longjmp(fpe, 1);
}
int main()
{
volatile int i, j;
for(i = 0; i < 10; i++)
{
// Call signal handler for SIGFPE
struct sigaction act;
struct sigaction oldact;
memset(&act, 0, sizeof(act));
act.sa_handler = handler;
act.sa_flags = SA_NODEFER | SA_NOMASK;
sigaction(SIGFPE, &act, &oldact);
if (0 == setjmp(fpe))
{
j = i / 0;
sigaction(SIGFPE, &oldact, &act);
} else {
sigaction(SIGFPE, &oldact, &act);
/* handle SIGFPE */
}
}
printf("After for loop");
return 0;
}
Caveat: Sorry to rain on the parade, but you really don't want to do this.
It is perfectly valid to trap [externally generated] signals like SIGINT, SIGTERM, SIGHUP etc. to allow graceful cleanup and termination of a program that may have files open that are partially written to.
However, internally generated signals, such as SIGILL, SIGBUS, SIGSEGV and SIGFPE are very hard to recover from meaningfully. The first three are bugs--pure and simple. And, IMO, the SIGFPE is also a hard bug as well.
After such a signal, your program is in an unsafe and indeterminate state. Even trapping the signal and doing longjmp/siglongjmp doesn't fix this.
And, there is no way to tell exactly how bad the damage is. Or, how bad the damage will become if the program tries to proceed.
If you get SIGFPE, was it for a floating point calculation [which you might be able to smooth over]. Or, was it for integer divide-by-zero? What calculation was being done? And, where? You don't know.
Trying to continue can sometimes cause 10x the damage because now the program is out of control. After recovery, the program may be okay, but it may not be. So, the reliability of the program after the event, can not be determined with any degree of certainty.
What were the events (i.e.) calculations that led up to the SIGFPE? Maybe, it's not merely a single divide, but the chain of calculations that led up to the value being zero. Where did these values go? Will these now suspect values be used by code after the recovery operation has taken place?
For example, the program might overwrite the wrong file because the failed calculation was somehow involved in selecting the file descriptor that a caller is going to use.
Or, you leak memory. Or, corrupt the heap. Or, was the error within the heap allocation code itself?
Consider the following function:
void
myfunc(char *file)
{
int fd;
fd = open(file,O_WRONLY);
while (1) {
// do stuff ...
// write to the file
write(fd,buf,len);
// do more stuff ...
// generate SIGFPE ...
x = y / z;
}
close(fd);
}
Even with a signal handler that does siglongjmp, the file that myfunc was writing to is now corrupted/truncated. And, the file descriptor won't be closed.
Or, what if myfunc was reading from the file and saving the data to some array. That array is only partially filled. Now, you get SIGFPE. This is intercepted by the signal handler which does siglongjmp.
One of the callers of myfunc does the sigsetjmp to "catch" this. But, what can it do? The caller has no idea how bad things are. It might assume that the buffer myfunc was reading into is fully formed and write it out to a different file. That other file has now become corrupted.
UPDATE:
Oops, forgot to mention undefined behavior ...
Normally, we associate UB, such as writing past the end of an array, with a segfault [SIGSEGV]. But, what if it causes SIGFPE instead?
It's no longer just a "bad calculation" -- we're trapping [and ignoring] UB at the earliest detection point. If we do recovery, the next usage could be worse.
Here's an example:
// assume these are ordered in memory as if they were part of the same struct:
int x[10];
int y;
int z;
void
myfunc(void)
{
// initialize
y = 23;
z = 37;
// do stuff ...
// generate UB -- we run one past the end of x and zero out y
for (int i = 0; i <= 10; ++i)
x[i] = 0;
// do more stuff ...
// generate SIGFPE ...
z /= y;
// do stuff ...
// do something _really_ bad with y that causes a segfault or _worse_
// sends a space rocket off-course ...
}
I have written the following code to get the understanding of event ordering using pthreads and mutex. main function creates two threads which are associated to functions func1 and func2. Function func1 checks for the value of count and conditionally wait for func2 to signal it. Function func2 increments the count and when count reaches 50000, it signals func1.
Then func1 prints the value of count which is(or should be) at that time 50000.
But in actual output, along with 50000 some other values are also being printed. I am not getting any reason why is it so. What I think is, when func2 signals, func1 wakes up and execute from after the pthread_cond_wait statement, and so it should print only 50000. Please point out where I am wrong and what should be changed to get correct output?
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pthread_mutex_t evmutex;
pthread_cond_t evcond;
char a;
int count;
int N = 50000;
void *func1()
{
while(1)
{
pthread_mutex_lock(&evmutex);
if(count < N)
{
pthread_cond_wait(&evcond,&evmutex);
printf("%d\n",count);
count = 0;
}
pthread_mutex_unlock(&evmutex);
}
}
void *func2()
{
while(1)
{
pthread_mutex_lock(&evmutex);
count++;
if(count == N)
{
pthread_cond_signal(&evcond);
}
pthread_mutex_unlock(&evmutex);
}
}
int main ()
{
pthread_t ptd1,ptd2;
pthread_mutex_init(&evmutex,NULL);
pthread_cond_init(&evcond,NULL);
count = 0;
pthread_create(&ptd1,NULL,func1,NULL);
pthread_create(&ptd2,NULL,func2,NULL);
pthread_exit(NULL);
pthread_mutex_destroy(&evmutex);
pthread_cond_destroy(&evcond);
return 0;
}
You've not synchronized with the producer, func2(), and telling it to wait until the consumer, func1(), has processed the condition.
Nothing stops the producer from signalling the condition, re-acquiring the mutex, and incrementing the counter again. pthread_cond_signal doesn't mean your producer will halt and wait for the consumer to process.
This means the producer might increment the counter many times before your consumer gets scheduled and wakes up to print the current number.
You'd need to add another condition variable which the producer waits for after it's incremented the counter to N, and have the consumer signal that when it has processed the counter.
In addition to that, you need to handle spurious wakeups as other answers mentions.
Some implementations of pthread_cond_wait() suffer from spurious wake-ups, and because of this, it's common practice to use a while (cond) { pthread_cond_wait(...); } loop to work around this.
I found a good explanation of the problem and causes here: Why does pthread_cond_wait have spurious wakeups?
In the following program, pause is interrupted once, but then pause never returns. I have set alarm to interrupt pause, so i am confused why pause never returns?
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static void sig_alrm(int);
static jmp_buf env_alrm;
int main(int arc, char **argv)
{
int x;
x = setjmp(env_alrm);
printf("setjmp was created with return value: %d\n", x);
if(signal(SIGALRM, sig_alrm) == SIG_ERR)
{
printf("Error settting SIGALRM\n");
exit(1);
}
if((x!= 0) && (x!=1))
{
printf("Error setting setjmp\n");
exit(1);
}
printf("Line next to setjmp\n");
x = alarm(2);
printf("Alarm set for 2 seconds, remaning secs from previous alarm: %d\n");
pause();
printf("Line next to pause()\n");
alarm(0);
return 0;
}
static void sig_alrm(int signo)
{
longjmp(env_alrm, 1);
}
Here is the output and the last line shows where the application pauses
setjmp was created with return value: 0
Line next to setjmp
Alarm set for 2 seconds, remaining secs from previous alarm: 0
setjmp was created with return value: 1
Line next to setjmp
Alarm set for 2 seconds, remaining secs from previous alarm: 0
use sigsetjmp() and siglongjmp() instead, to save and restore the signal masks, which are not saved by default in Linux, to clear any pending signals, from man setjmp():
POSIX does not specify whether setjmp() will save the signal mask. In System V it will not.By default, Linux/glibc follows the System V behavior. If you want to portably save and restore signal masks, use sigsetjmp()
and siglongjmp().
Note: I'm not sure what you're trying to accomplish, but your code looks like it's supposed to run in an infinite loop, calling longjmp() restores execution as if it had just returned from setjmp() and it goes on forever.
According to http://linux.die.net/man/2/pause :
pause() only returns when a signal was caught and the signal-catching
function returned.
In your case it never returns, it does the longjmp out.