sleep, SIGINT, ctrl c, etc.

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

icorey
Posts: 12
Joined: Thu Nov 20, 2008 8:07 am UTC
Contact:

sleep, SIGINT, ctrl c, etc.

Postby icorey » Sat Mar 07, 2009 6:16 am UTC

so i expect the snippet below to print "hello" every second and print "ouch: 2" (I think it's 2...the number doesn't really matter) when i hit Ctrl-C. I also expect Ctrl-\ to kill the process. The only part of that that works is the "hello" part and to end the program, I have to run kill -9 pid (using linux, btw). What the hell is going on?

Code: Select all

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void ouch(int sig) {
        printf("ouch: %d\n", sig);
}

int main() {
        struct sigaction act;
        act.sa_handler = ouch;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGINT, &act, 0);

        while (1) {
                printf("hello\n");
                sleep(1);
        }
}

User avatar
Link
Posts: 1407
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: sleep, SIGINT, ctrl c, etc.

Postby Link » Sat Mar 07, 2009 12:04 pm UTC

Confirming those results. Apparently despite its name, SIGQUIT does not actually cause the application to quit.

A modified version that does what you want:

Code: Select all

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

void ouch(int sig) {
        printf("ouch: %d\n", sig);
        if (sig == SIGQUIT) exit(0);
}

int main() {
        struct sigaction act;
        act.sa_handler = ouch;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGINT, &act, 0);
        sigaction(SIGQUIT, &act, 0);

        while (1) {
                printf("hello\n");
                sleep(1);
        }
}

icorey
Posts: 12
Joined: Thu Nov 20, 2008 8:07 am UTC
Contact:

Re: sleep, SIGINT, ctrl c, etc.

Postby icorey » Sat Mar 07, 2009 3:53 pm UTC

Thanks. There must be something wrong on my system because neither of those work at all. They both just print "hello" until i send SIGSTP.

Rysto
Posts: 1460
Joined: Wed Mar 21, 2007 4:07 am UTC

Re: sleep, SIGINT, ctrl c, etc.

Postby Rysto » Sat Mar 07, 2009 4:03 pm UTC

Is a signal handler allowed to printf? There's quite a limited list of functions that a signal handler can call.

User avatar
Link
Posts: 1407
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: sleep, SIGINT, ctrl c, etc.

Postby Link » Sat Mar 07, 2009 6:50 pm UTC

I've looked into it a bit more, and according to Wikipedia, using printf in a signal handler is indeed unsafe.

Since the rules say I shouldn't post links yet, I suggest you look up "DA's signal hints". It has some tips on writing safe signal handlers.

Regardless of whether it's safe or not, I don't know why it works on my system but not on yours.

Random832
Posts: 2525
Joined: Wed Oct 10, 2007 4:38 pm UTC

Re: sleep, SIGINT, ctrl c, etc.

Postby Random832 » Sat Mar 07, 2009 9:13 pm UTC

Link wrote:I've looked into it a bit more, and according to Wikipedia, using printf in a signal handler is indeed unsafe.

Since the rules say I shouldn't post links yet, I suggest you look up "DA's signal hints". It has some tips on writing safe signal handlers.

Regardless of whether it's safe or not, I don't know why it works on my system but not on yours.


"not safe" doesn't mean "always breaks predictably"

I believe write() and sprintf() are both safe, so:

Code: Select all

char b[8+(CHAR_BIT*sizeof(int)+2)/3+1];
int n = sprintf(b,"ouch: %d\n",sig);
write(2,b,n);


Explanation of array thing: 8 is the number of chars needed for "ouch: \n".
(CHAR_BIT*sizeof(int)+2)/3+1 : CHAR_BIT*sizeof(int) is at least number of bits in an int: 3 is floor(log2(10)), +2 makes it round up, and +1 allows an extra space for a minus sign if needed. Result is 12, one more than needed for -2147483648.

DISREGARD EVERYTHING ABOVE - sprintf() is not guaranteed safe. write() is, though, so you can

Code: Select all

char b[11] = "ouch: ___\n"
b[8] = '0'+sig % 10;
b[7] = '0'+(sig/10)%10;
b[6] = (sig>999)?'?':'0'+(sig/100)%10;
if(b[6]='0'){b[6]=' ';if(b[7]='0')b[7]=' ';}
write(2,b,10);


Also, you cannot call exit(), you have to call _exit() which does not call atexit handlers.

Karrion
Posts: 92
Joined: Fri Jun 22, 2007 12:14 am UTC
Location: Melbourne, AU

Re: sleep, SIGINT, ctrl c, etc.

Postby Karrion » Sun Mar 08, 2009 11:48 am UTC

Link wrote:Apparently despite its name, SIGQUIT does not actually cause the application to quit.

The default behaviour on SIGQUIT is to terminate the process. However, you've associated your own signal handler with it, thus replacing the default behaviour. So if you still want the process to terminate, your handler will have to do it.

Usually you don't exit within the handler though. You generally have your main loop testing some boolean "running" flag, and when you receive SIGQUIT, just set the flag to false, so your main loop will exit and any cleanup code will be run.

User avatar
eta oin shrdlu
Posts: 451
Joined: Sat Jan 19, 2008 4:25 am UTC

Re: sleep, SIGINT, ctrl c, etc.

Postby eta oin shrdlu » Mon Mar 09, 2009 12:06 am UTC

The reason that printf(), sprintf(), etc., are not allowed in signal handlers, as far as I know, is just that they are not reentrant functions; they use some function-static internal variables and so are not safe for use in situations (like multithreaded applications, signal handlers, etc.) where several instances could be called at the same time. You probably have reentrant-safe versions printf_r(), sprintf_r() available; these get passed an extra struct reent which is used for the required temporary storage.

User avatar
'; DROP DATABASE;--
Posts: 3284
Joined: Thu Nov 22, 2007 9:38 am UTC
Location: Midwest Alberta, where it's STILL snowy
Contact:

Re: sleep, SIGINT, ctrl c, etc.

Postby '; DROP DATABASE;-- » Mon Mar 09, 2009 12:46 am UTC

There's not much you can safely do in a signal handler. Typically you set a flag to be checked either after doing the thing that might raise a signal (e.g. for SIGPIPE) or by the main loop.
poxic wrote:You suck. And simultaneously rock. I think you've invented a new state of being.

Random832
Posts: 2525
Joined: Wed Oct 10, 2007 4:38 pm UTC

Re: sleep, SIGINT, ctrl c, etc.

Postby Random832 » Mon Mar 09, 2009 2:23 am UTC

eta oin shrdlu wrote:The reason that printf(), sprintf(), etc., are not allowed in signal handlers, as far as I know, is just that they are not reentrant functions; they use some function-static internal variables and so are not safe for use in situations (like multithreaded applications, signal handlers, etc.) where several instances could be called at the same time. You probably have reentrant-safe versions printf_r(), sprintf_r() available; these get passed an extra struct reent which is used for the required temporary storage.


Uh, what? No, you're thinking of strtok - printf has no way around it because it's using the output stream, and there's only one of that. sprintf could be made safe in theory, but it's considered unsafe specifically because it doesn't appear on the list of safe functions, not because there's anything actually unsafe about any given implementation. And there's no printf_r/sprintf_r in the standard (or AFAIK in any implementation)

User avatar
eta oin shrdlu
Posts: 451
Joined: Sat Jan 19, 2008 4:25 am UTC

Re: sleep, SIGINT, ctrl c, etc.

Postby eta oin shrdlu » Mon Mar 09, 2009 3:07 am UTC

Random832 wrote:Uh, what? No, you're thinking of strtok - printf has no way around it because it's using the output stream, and there's only one of that. sprintf could be made safe in theory, but it's considered unsafe specifically because it doesn't appear on the list of safe functions, not because there's anything actually unsafe about any given implementation. And there's no printf_r/sprintf_r in the standard (or AFAIK in any implementation)
I wasn't actually thinking of strtok, so I'm probably just wrong. printf_r and sprintf_r appear to exist in the Cygwin version of stdio.h, though, although I've never used them.

Random832
Posts: 2525
Joined: Wed Oct 10, 2007 4:38 pm UTC

Re: sleep, SIGINT, ctrl c, etc.

Postby Random832 » Mon Mar 09, 2009 4:36 am UTC

eta oin shrdlu wrote:
Random832 wrote:Uh, what? No, you're thinking of strtok - printf has no way around it because it's using the output stream, and there's only one of that. sprintf could be made safe in theory, but it's considered unsafe specifically because it doesn't appear on the list of safe functions, not because there's anything actually unsafe about any given implementation. And there's no printf_r/sprintf_r in the standard (or AFAIK in any implementation)
I wasn't actually thinking of strtok, so I'm probably just wrong. printf_r and sprintf_r appear to exist in the Cygwin version of stdio.h, though, although I've never used them.

I looked into this, and found what _appears_ to be it - cygwin apparently uses something called "newlib" now (i thought it used glibc at one point).

http://sourceware.org/cgi-bin/cvsweb.cg ... vsroot=src

glibc provides a function (similar to this thing's dynamic reentrancy) for errno, but it looks like newlib does stuff like making a lot of things thread-safe (the messy details are here)

But anyway, this all has very little to do with the POSIX concept of async-signal-safety. sprintf is unsafe because the standard says it is, not because of what specifically it does.

User avatar
eta oin shrdlu
Posts: 451
Joined: Sat Jan 19, 2008 4:25 am UTC

Re: sleep, SIGINT, ctrl c, etc.

Postby eta oin shrdlu » Tue Mar 10, 2009 12:56 am UTC

Random832 wrote:I looked into this, and found what _appears_ to be it - cygwin apparently uses something called "newlib" now (i thought it used glibc at one point).

http://sourceware.org/cgi-bin/cvsweb.cg ... vsroot=src

glibc provides a function (similar to this thing's dynamic reentrancy) for errno, but it looks like newlib does stuff like making a lot of things thread-safe (the messy details are here)

But anyway, this all has very little to do with the POSIX concept of async-signal-safety. sprintf is unsafe because the standard says it is, not because of what specifically it does.
Thanks for the correction and explanation.

User avatar
Link
Posts: 1407
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: sleep, SIGINT, ctrl c, etc.

Postby Link » Tue Mar 10, 2009 6:10 pm UTC

Karrion wrote:
Link wrote:Apparently despite its name, SIGQUIT does not actually cause the application to quit.

The default behaviour on SIGQUIT is to terminate the process. However, you've associated your own signal handler with it, thus replacing the default behaviour. So if you still want the process to terminate, your handler will have to do it.

To clarify, I was referring to the original example. For some reason, on my system, even programs with no explicit signal handling code whatsoever do not respond to SIGQUIT by default. No core dumps, no program termination; nothing - and that's even the case when I explicitly kill the process with SIGQUIT.


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 11 guests