The UNIX and Linux Forums  

Go Back   The UNIX and Linux Forums > Top Forums > High Level Programming
Google UNIX.COM



View Single Post in UNIX Forums - Click on the Thread or Permalink to View Entire Thread -->
  #1 (permalink)  
Old 04-09-2008
stewartw stewartw is offline
Registered User
 

Join Date: Apr 2008
Posts: 5
Runaway SIGALRM signal handler

I have written a program to demonstrate a problem I have encountered when using BSD style asynchronous input using the O_ASYNC flag in conjunction with a real time interval timer sending regular SIGALRM signals to the program. The SIGIO handler obeys all safe practices, using only an atomic update to a volatile sig_atomic_t variable.

The program is below. The idea is that when the user enters a 'q', the program is supposed to stop. It does not. If you uncomment the printf statement in teh main program's loop you will see that the loop is exited, but the return statement is never reached because the SIGALRMS seem to keep the program alive. Be prepared to kill it with a Ctrl-C.

If I use the AIO style asynchronous I/O there is no problem. It is related to the O_ASYNC flag. (In fact if you simply call fcntl() and tell the kernel to send signals to the process, without setting the flag, the same problem will occur! )

Can anyone explain what is wrong?

Code:
#include    <stdio.h>
#include    <signal.h>
#include    <sys/time.h>
#include    <fcntl.h>


void    on_alarm(int);    /* handler for alarm    */
void    on_input(int);    /* handler for keybd    */
int     set_timer( int which, long initial, long repeat );

volatile sig_atomic_t   finished  = 0;

int main( int argc, char * argv[])
{
    int  fd_flags;
    int k = 0;
    struct sigaction newhandler;    
    sigset_t         blocked;       

    newhandler.sa_handler = on_input;  /* handler function    */
    newhandler.sa_flags   = 0;   

    sigemptyset(&blocked);             
    newhandler.sa_mask = blocked;      
    if ( sigaction(SIGIO, &newhandler, NULL) == -1 )
        perror("sigaction");

    newhandler.sa_handler = on_alarm;  /* handler function    */
    if ( sigaction(SIGALRM, &newhandler, NULL) == -1 )
        perror("sigaction");


    fcntl(0, F_SETOWN, getpid());
    fd_flags = fcntl(0, F_GETFL);
    fcntl(0, F_SETFL, (fd_flags|O_ASYNC));

    set_timer(ITIMER_REAL, 500, 500); 


    while( !finished  )    {         
       pause();
       printf("still in loop and finished = %d\n", finished);
    }
    return 0;
}
void on_input(int signum)
{
    int  c = getchar();          
    if ( c == 'q' )
        finished = 1;
}

void on_alarm(int signum)
{
    static int k = 0;
    printf("call number %d\n", k++);
}


int set_timer( int which, long initial, long repeat )
{
    struct itimerval itimer;
    long secs;

    // initialize initial delay
    secs = initial / 1000 ; 
    itimer.it_value.tv_sec     = secs;    
    itimer.it_value.tv_usec    = (initial - secs*1000 ) * 1000 ;   

    // initialize repeat inveral
    secs = repeat / 1000 ; 
    itimer.it_interval.tv_sec  = secs;     
    itimer.it_interval.tv_usec = (repeat - secs*1000 ) * 1000 ;
    
    return setitimer(which, &itimer, NULL);
}

Last edited by Perderabo; 04-10-2008 at 07:30 PM. Reason: Adding code tags... it's just 13 little keystrokes to readability.
Reply With Quote
Forum Sponsor