• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 334
  • Last Modified:

Odd Results Using timer & signals


First I need to say that is has been 10+ years since I wrote any serious C code, mainly because I have been doing sysadmin stuff and Java since then but trying to dig back in now. I am playing around with some code that will incorporate a timer that will be used to run various tasks at various intervals. Here is the code:

#include "sa_watchdog.h"

int count   = 0;
long millis  = 0;
char timestr[40];
struct itimerval   timer;
struct timeval currtime;
struct timeval *currtimeptr = &currtime;
struct tm *disptime;

void a_handler(int signo)
{
        gettimeofday(&currtime, NULL);
        disptime = localtime(&currtime.tv_sec);
        strftime(timestr, sizeof(timestr), "%H:%M:%S", disptime);
        millis = currtime.tv_usec / 1000;
        printf("\nSignal %d received at %s.%03ld\n", count, timestr, millis);
        count++;
}

int main()
{
          int keep_running = 1;
          int index = 0;
          timer.it_interval.tv_sec = 0;
          timer.it_interval.tv_usec = 1000000;
          timer.it_value.tv_sec = 0;
          timer.it_value.tv_usec = 1000000;

          task = task1;
          setitimer(ITIMER_REAL, &timer, NULL);
          signal(SIGALRM, a_handler);

          while(keep_running){
              index++;
              printf(".");
              if (index >= 100000000) // just wanna spin to waste time
                keep_running = 0;
          }
         
          printf("Received a total of %d signals during execution.\n", count);
          return 0;
}

However, I get some out output when I run this:
delta:/projects/SAWatchDog #./sa_watchdog  | grep -i signal
Signal 0 received at 14:44:04.069
Signal 0 received at 14:44:04.069
Signal 2 received at 14:44:07.072
Signal 2 received at 14:44:07.072
Signal 5 received at 14:44:10.074
Signal 5 received at 14:44:10.074
Signal 7 received at 14:44:13.077
Signal 8 received at 14:44:14.078
Signal 8 received at 14:44:14.078
Signal 10 received at 14:44:16.079
Signal 10 received at 14:44:16.079

2 things: 1) Why is it printing 2 lines for each signal and 2) why are the intervals only 3 seconds apart.

If I change my main while loop to this:
          int max_count = 20;
          while(keep_running){
              if (count >= max_count)
                keep_running = 0;
          }

I get this for my output:
delta:/SAWatchDog #./sa_watchdog
Signal 0 received at 14:50:38.609
Signal 1 received at 14:50:39.610
Signal 2 received at 14:50:40.611
Signal 3 received at 14:50:41.612
Signal 4 received at 14:50:42.612
Signal 5 received at 14:50:43.613
Signal 6 received at 14:50:44.614
Signal 7 received at 14:50:45.615
Signal 8 received at 14:50:46.616
Signal 9 received at 14:50:47.617
Signal 10 received at 14:50:48.618

This is what I would expect from the code above. I'm sure it is something obvious and dumb on my part but just can't seem to track it down. The platform is Fedora Core 2 using gcc 3.3.3.

Also, if anyone knows any good resources I can use for something like this please let me know.

Thanks for any help!
rhugga
0
rhugga
Asked:
rhugga
4 Solutions
 
ssnkumarCommented:
Hi rhugga,

I tried the same code on Linux box.
It is not giving 2 displays!
And I have commented out  the line:
>task = task1;
What is this one doing?

-ssnkumar
0
 
ssnkumarCommented:
I tried your code on my system again.
I am not getting 2 displays.
Also, the time gap is 1 second.

This is what man page has to say regarding this: Timers  will  never  expire before the requested time, instead expiring some short, constant time afterwards, dependent  on  the  system  timer resolution  (currently 10ms).

So, your system timer resolution should be different.

>Also, if anyone knows any good resources
Tell me what is the resource you are looking for? Is it for timer or signals?

-ssnkumar
0
 
grg99Commented:
Please print out the "signo" inside the handler.

Also check the man pages for setitimer and signal, make sure your function prototypes are exactly as required.

Also try setting the sec field to "1" and the usec field to "0".

Not to mention check the function return values.



0
The Lifecycle Approach to Managing Security Policy

Managing application connectivity and security policies can be achieved more effectively when following a framework that automates repeatable processes and ensures that the right activities are performed in the right order.

 
van_dyCommented:
first off all, stdio functions are not async-signal-safe.
this is so because various implementations
of stdio use global data structures in non-reentrant
way. so it is reccommended not to use printf() inside
a signal handler. having said that, we can still implement what
you are trying to do by using setjmp/longjmp (both of which are
signal safe).

consider the following:
#include <setjmp.h>
#include "sa_watchdog.h"

jmp_buf     jbuf;

void a_handler(signo)
                  int signo;
{
           count++;
            longjmp(jbuf, 1);
}

...

int main()
{
        .....
              while(keep_running){
                          index++;
//                          printf(".");                dont need this
                           if(setjmp(jbuf)){
                                      gettimeofday(&currtime, NULL);
                                      disptime = localtime(&currtime.tv_sec);
                                      strftime(timestr, sizeof(timestr), "%H:%M:%S", disptime);
                                       millis = currtime.tv_usec / 1000;
                                       printf("\nSignal %d received at %s.%03ld\n", count, timestr, millis);
                           }
                            if (index >= 100000000) // just wanna spin to waste time
                                  keep_running = 0;
              }
....


hope this helps,
van_dy

0
 
rhuggaAuthor Commented:

The task = task1 is just leftover code from earlier testing. This code is just a simple test of the timer capabilities to see if it can even perform as I need it to. The actual end-product will be nothing like this. I have never played with timers before in C so I just wanted to get an idea of how accurate they were, also how accurate they were on a heavily loaded system. I just need a timer that can be accurate to 100ms.

About the printf in the handler, this handler will eventually only contain 1 or 2 function calls but these functions will be communicating with databases and other nodes via TCP, as well as logging various things. Is printf safe to use in a function called from a handler?

Also, in refernce to the resources I was asking about, I am looking for anything that can assist me in writing a timer driven event system. This code will also be heavily threaded. I have found a lot on the web but mostly just rudimentary examples.

One last thing. Suppose I have a real-time timer that will expire every 10 secs, however the process loses its time slice on the cpu in 5 secs and doesnt regain another slice for 30 seconds (hypothetically). Thus it will be sleeping when the timer expires (it will be sleeping during the next 3 time expirations), so what happens when the process regains execution time? Are the signals queued up and sent at that time, or are they lost, or what?

Thanks for all the help, I will increase points if this is a larger problem.

Thanks,
rhugga
0
 
ssnkumarCommented:
You are trying to set a real-time clock on a non-realtime system!
Because of scheduling and context-switching, you may never get a very accurate timer on these systems.

-ssnkumar
0
 
van_dyCommented:
>>Is printf safe to use in a function called from a handler?

No it is not safe, signal handlers are supposed to do only trivial things, like setting
a flag, or doing somethng to a global variable.

 >>Are the signals queued up and sent at that time, or are they lost, or what?
usually, the implementation of signals is roughly like this: if the kernel has to send  a signal to
a process it sets a flag for a particullar signal in some internal data structure for the process(struct proc).
once set, this flag remains set unless the signal is handled, if the signal is not handled and there is another
occurrence of the signal, it is lost, (the signal flag is already set, you cant set it more than once).
You might consider reading about posix real time signals for what are you trying.
0
 
PaulCaswellCommented:
>>No it is not safe, signal handlers are supposed to do only trivial things, like setting
>>a flag, or doing somethng to a global variable.
This is VERY good advice.

The approach I've used many times is to use signals to state switch a state machine. Then add a tight loop that just watches for a state change and semaphores the timer. Remember to protect the state machine from being switched too fast.

E.G.

// On Signal.
...
if ( State->handled )
{
  State = State->next;
  State->handled = false;
}
...

// Your state loop.
while ( true )
{
  if ( !State->handled )
  {
    (*State->Handle)();
    State->Handled = true;
  }
}

This makes:

1. Signal handling extremely trivial.
2. Versatile timer-driven coding.
3. Thread-safe if you code it right.

Paul
0

Featured Post

Has Powershell sent you back into the Stone Age?

If managing Active Directory using Windows Powershell® is making you feel like you stepped back in time, you are not alone.  For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now