Solved

Odd Results Using timer & signals

Posted on 2004-10-24
327 Views
Last Modified: 2010-04-15

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
Question by:rhugga
    8 Comments
     
    LVL 8

    Assisted Solution

    by:ssnkumar
    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
     
    LVL 8

    Assisted Solution

    by:ssnkumar
    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
     
    LVL 22

    Assisted Solution

    by:grg99
    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
     
    LVL 5

    Accepted Solution

    by:
    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
     
    LVL 1

    Author Comment

    by:rhugga

    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
     
    LVL 8

    Expert Comment

    by:ssnkumar
    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
     
    LVL 5

    Expert Comment

    by:van_dy
    >>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
     
    LVL 16

    Expert Comment

    by:PaulCaswell
    >>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

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    IT, Stop Being Called Into Every Meeting

    Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

    Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
    This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
    The goal of this video is to provide viewers with basic examples to understand and use structures in the C programming language.
    Video by: Grant
    The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.

    845 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    7 Experts available now in Live!

    Get 1:1 Help Now