tags:

views:

102

answers:

4

Hello,

I am trying to make my program ignore ctrl-c in unix which seems to work, the issue is that it keep writing "Syntax error". Here is the code

extern "C" void ignore( int sig )
{            
    fprintf( stderr, "\n"); // Print a new line
    // This function does nothing except ignore ctrl-c
}

int main()
{           
    // For ctrl-c
    sigset( SIGINT, ignore );

    while (1) {
        getUserInput();
    }      

    return 0;
}

Everytime I hit Ctrl-c it runs through getUserInput again, which is the expected behavior, but it writes "Syntax error" as well. I checked and the "ignore" function gets executed, and once it has been executed, then it prints the error message, I am not sure why.

Does anyone have any clues please?

Thank you very much,

Jary

+1  A: 

The "Syntax Error" message must be coming from the getUserInput function (or something it calls, of course) -- you could investigate by having that function print out what it is receiving and why it is complaining.

Note that the canonical way to ignore a signal is to use the pre-defined SIG_IGN as the signal handler. e.g. sigset(SIGINT, SIG_IGN)

jsegal
+1  A: 

Do not use sigset(). Although it is in POSIX 2008, it is marked obsolescent - and also unsafe in threaded programs.

You then have a choice between signal(), which is blessed by ISO C but has some undesirable characteristics, and sigaction() which is the preferred solution in POSIX systems.

One key point with signal handling is to ensure you do not trap any signals that are ignored when you enter the program - unless you know something that the caller can't (such as you need to trap SIGCHLD signals for dead children).

This leads to the standard formulations, preached since time immemorial, for signal():

if (signal(SIGINT, SIG_IGN) != SIG_IGN)
    signal(SIGINT, ignore);

Or, for sigaction():

struct sigaction new_sa;
struct sigaction old_sa;
sigfillset(&new_sa.sa_mask);
new_sa.sa_handler = SIG_IGN;
new_sa.sa_flags = 0;

if (sigaction(SIGINT, &new_sa, &old_sa) == 0 && old_sa.sa_handler != SIG_IGN)
{
    new_sa.sa_handler = ignore;
    sigaction(SIGINT, &new_sa, 0);
}

Since you do not show us the getUserInput() function, there is no way we can prognosticate on why you see 'Syntax Error'. However, if you have a grammar at work, it may well be that your read is not returning valid data, and the parser is unhappy with what is left in the buffer for it to process.

Jonathan Leffler
Thanks for the information. Indeed, getUserInput is a large grammar at work, I believe you are right. Thanks!
Jary
+3  A: 

(Note: for more portability, you should probably use signal() (C standard library) or sigaction() (POSIX) instead of sigset(), but I don't think that's the problem here.)

You're not really ignoring the signal here; you're catching it and taking your own action - but it's likely that a system call has returned an error as a result of the interruption.

e.g. maybe you've caused a read system call to fail with EINTR. I suspect the real problem is that some code inside getUserInput() is not handling this error case.

You can ignore the signal completely by setting the handler to the special value SIG_IGN, which should work with any of sigset(), signal() or sigaction().

Matthew Slattery
Thanks a lot! That solved my problem.
Jary
+1  A: 

ignore() does a lot more than nothing.

When you run this code on UNIX, SIGINT is delivered asynchronously on the same thread that is executing getUserInput(). If a SIGINT arrives while getUserInput() is accessing stderr, the behavior is undefined because fprintf() usually isn't designed to be reentrant. (However, the behavior is likely to include garbled and/or repeated output. Did your program print "Syntax Error" before the SIGINT was delivered?) CERT and GNU libc have some more info about this.

If you were running this code on Win32, SIGINT would be delivered asynchronously in a separate thread.

bk1e