The UNIX and Linux Forums  

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


High Level Programming Post questions about C, C++, Java, SQL, and other programming languages here.

More UNIX and Linux Forum Topics You Might Find Helpful
Thread Thread Starter Forum Replies Last Post
signal handler problems blowtorch High Level Programming 4 08-26-2007 05:14 AM
signal handler for SIGCHLD jens High Level Programming 3 07-02-2005 09:05 AM
Runaway processes killed (Really need help) Micz UNIX for Dummies Questions & Answers 2 10-28-2003 10:45 AM
shell script signal handler jalburger Shell Programming and Scripting 2 12-04-2002 01:10 PM
SIGALRM Help skannan High Level Programming 1 06-16-2002 07:17 AM

Reply
 
Submit Tools LinkBack Thread Tools Display Modes
  #1 (permalink)  
Old 04-09-2008
Registered User
 

Join Date: Apr 2008
Posts: 5
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Reddit! Stumble this Post!Spurl this Post!
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
  #2 (permalink)  
Old 04-09-2008
...@...
 

Join Date: Feb 2004
Location: NM
Posts: 3,289
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Reddit! Stumble this Post!Spurl this Post!
You are using 500 when you do integer division of 500 /1000 you get zero. That's what I see right off.
Reply With Quote
  #3 (permalink)  
Old 04-09-2008
Registered User
 

Join Date: Apr 2008
Posts: 5
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Reddit! Stumble this Post!Spurl this Post!
Not that simple

The lines:

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

set the seconds to 0 and the microseconds to 500,000. That is intentional integer division. It si the standard way to convert milliseconds to (secs,microsecs).

Stewart
Reply With Quote
  #4 (permalink)  
Old 04-10-2008
Registered User
 

Join Date: Dec 2007
Location: Virginia, USA.
Posts: 211
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Reddit! Stumble this Post!Spurl this Post!
Works for me on both linux 2.6.x and FreeBSD 6.0-RELEASE.
Reply With Quote
  #5 (permalink)  
Old 04-10-2008
Registered User
 

Join Date: Apr 2008
Posts: 5
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Reddit! Stumble this Post!Spurl this Post!
When you run it, the 'q' causes the program to quit? I have run this program on Linux 2.6..x (from 9 to 24) and on Solaris 9, and it does not terminate on 'q'. And I have run it on at least 6 different machines. You used the exact code?

Stewartw
Reply With Quote
  #6 (permalink)  
Old 04-10-2008
Registered User
 

Join Date: Dec 2007
Location: Virginia, USA.
Posts: 211
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Reddit! Stumble this Post!Spurl this Post!
Yep. I did the intuitive interactive thing. I fear your problem is pretty standard for stdio buffered programs looking for a newline.
Code:
@skbsd::~/src>./progname
call number 0
still in loop and finished = 0
call number 1
still in loop and finished = 0
call number 2
still in loop and finished = 0
call number 3
still in loop and finished = 0
call number 4
still in loop and finished = 0
call number 5
still in loop and finished = 0
qcall number 6
qcall number 7
qcall number 8
qcall number 9
qcall number 10
<\r here>
still in loop and finished = 1
Reply With Quote
  #7 (permalink)  
Old 04-10-2008
Perderabo's Avatar
Unix Daemon
 

Join Date: Aug 2001
Location: Washington DC Area
Posts: 8,253
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Reddit! Stumble this Post!Spurl this Post!
You are doing something extremely non-standard and you aren't bothering to test the return codes. Solaris does not support O_ASYNC. Here is the Solaris 9 fcntl man page. I don't see any O_ASYNC flag mentioned. You actually got this to compile on Solaris??? I got to try that tomorrow.... I would expect it to run on FreeBSD. I'm not sure about Linux.... I'm don't have time right now to look up the man pages. Anyway this BSD async stuff is pretty much BSD only and not part of Posix.

Please test those return codes. If not all the time, at least break down and test them when you don't understand the behavior of the system calls.
Reply With Quote
  #8 (permalink)  
Old 04-10-2008
Registered User
 

Join Date: Apr 2008
Posts: 5
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Reddit! Stumble this Post!Spurl this Post!
Ramen Noodle,

You are correct. When I supply the return it terminates. But this is the real story. Below is the original program that had this problem. It uses the NCurses library. I simplified it for the post. This program puts the terminal into cbreak mode and does not require the newline character -- it is using non-blocking I/O. And you will discover that typign newline after the 'q' does not solve it.

But I would be grateful to know what does. Here it is:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <curses.h>
#include <signal.h>
#include <sys/time.h>
#include <fcntl.h>
#include <time.h>
#include "timers.h"

/*****************************************************************************/
/* Global Constants */
/*****************************************************************************/

#define INITIAL_SPEED 30
#define RIGHT 1
#define LEFT -1
#define ROW 12
#define MESSAGE "ooooooo=>"
#define REVMSSGE "<=ooooooo"
#define BLANK " "

int row; // current row
int col; // current column
int dir; // Global variable to store direction of movement
int speed; // Current speed in chars/second
volatile sig_atomic_t finished;

/*****************************************************************************/
/* Signal Handler Prototypes */
/*****************************************************************************/
void on_alarm(int); /* handler for alarm */
void on_input(int); /* handler for keybd */

/*****************************************************************************/
/* Utility Function Prototype */
/*****************************************************************************/

void enable_kbd_signals();

/*****************************************************************************/
/* Main */
/*****************************************************************************/
int main( int argc, char * argv[])
{
struct sigaction newhandler; // for installing handlers
sigset_t blocked; // to set mask for handler


// Set up signal handling
newhandler.sa_handler = on_input; // name of handler
newhandler.sa_flags = SA_RESTART; // flag is just RESTART
sigemptyset(&blocked); // clear all bits of blocked set
//sigaddset(&blocked, SIGALRM);
newhandler.sa_mask = blocked; // set this empty set to be the mask
if ( sigaction(SIGIO, &newhandler, NULL) == -1 ) {
perror("sigaction");
return (1);
}

sigemptyset(&blocked); // clear all bits of blocked set
//sigaddset(&blocked, SIGIO);
newhandler.sa_mask = blocked; // set this empty set to be the mask
newhandler.sa_handler = on_alarm; // SIGALRM handler function
if ( sigaction(SIGALRM, &newhandler, NULL) == -1 ){ // try to install
perror("sigaction");
return (1);
}

// Prepare the terminal for the animation
initscr(); // initialize the library and screen
cbreak(); // put terminal into non-blocking input mode
noecho(); // turn off echo
clear(); // clear the screen
curs_set(0); // hide the cursor

// Initialize the parameters of the program
row = ROW;
col = 0;
dir = RIGHT;
finished = 0;
speed = INITIAL_SPEED ;

// Turn on keyboard signals
enable_kbd_signals();

// Start the real time interval timer with delay interval size
set_timer( ITIMER_REAL, 1000/speed, 1000/speed );


// mvaddstr(LINES-1, 0, "Current speed:");
//refresh();

// Put the message into the first position and start
mvaddstr(row, col, MESSAGE);


while( !finished ) {
pause();
}
endwin();
return 0;
}

/*****************************************************************************/

void on_input(int signum)
{
int c;

c = getch();

switch (c) {

case 'Q':

case 'q':

finished = 1;
}
}



/*****************************************************************************/

void on_alarm(int signum)
{

mvaddstr( row, col, BLANK ); // erase old string
col += dir; // advance one column
move( row, col ); // move to new locataion
if ( RIGHT == dir ) {
addstr( MESSAGE ); // add forward string
if ( col+strlen(MESSAGE) >= COLS-1 )
dir = LEFT; // reverse if hitting edge
}
else {
addstr( REVMSSGE ); // add reverse string
if ( col <= 0 )
dir = RIGHT; // reverse if hitting edge
}
refresh();
}

/*****************************************************************************/
/*
* install a handler, tell kernel who to notify on input, enable signals
*/
void enable_kbd_signals()
{
int fd_flags;

fcntl(0, F_SETOWN, getpid());
fd_flags = fcntl(0, F_GETFL);
fcntl(0, F_SETFL, (fd_flags|O_ASYNC));
}
Reply With Quote
  #9 (permalink)  
Old 04-10-2008
Registered User
 

Join Date: Dec 2007
Location: Virginia, USA.
Posts: 211
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Reddit! Stumble this Post!Spurl this Post!
My ncurses is rusty. Like 2003 rusty
Don't think you want me for this. Sounds debuggable and you seem proficient.
Reply With Quote
Google UNIX.COM
Reply

Tags
linux, solaris

Thread Tools
Display Modes


The 50 most popular UNIX and Linux searches.
Google Search Cloud for The UNIX and Linux Forums
421 service not available, remote server has closed connection ^m automate ftp autosys awk trim bash eval bash exec bash for loop command copy/move folder in unix couldn't set locale correctly curses.h cut command in unix daemon process export command in unix find grep find mtime find null character in a unix file grep multiple lines grep or grep recursive hp-ux ifconfig inaddr_any inappropriate ioctl for device lynx javascript mailx attachment mget mtime ping port remove first character from string in k shell replace space by comma , perl script scp recursive segmentation fault(coredump) sftp script snoop unix stale nfs file handle syn_sent tar exclude tar extract to folder test: argument expected unix unix .profile unix forum unix forums unix interview questions unix simulator unix.com vi select all vi substitute vi+substitute+end+of+line+character while loop within while loop shell script


All times are GMT -7. The time now is 04:56 AM.


Powered by: vBulletin, Copyright ©2000 - 2006, Jelsoft Enterprises Limited.
The UNIX and Linux Forums Content Copyright ©1993-2008 The CEP Blog All Rights Reserved -Ad Management by RedTyger Visit The Global Fact Book

Content Relevant URLs by vBSEO 3.2.0

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101