Thread: When to re-enable signal handlers

  1. #1
    Registered User
    Join Date
    Aug 2011
    Posts
    13

    When to re-enable signal handlers

    I'm reading the GNU libc manual, the part about signals.

    In this page it shows some code. I report it here:
    Code:
         #include <signal.h>
         #include <stdio.h>
         #include <stdlib.h>
         
         /* This flag controls termination of the main loop. */
         volatile sig_atomic_t keep_going = 1;
         
         /* The signal handler just clears the flag and re-enables itself. */
         void
         catch_alarm (int sig)
         {
           keep_going = 0;
           signal (sig, catch_alarm);
         }
         
         void
         do_stuff (void)
         {
           puts ("Doing stuff while waiting for alarm....");
         }
         
         int
         main (void)
         {
           /* Establish a handler for SIGALRM signals. */
           signal (SIGALRM, catch_alarm);
         
           /* Set an alarm to go off in a little while. */
           alarm (2);
         
           /* Check the flag once in a while to see when to quit. */
           while (keep_going)
             do_stuff ();
         
           return EXIT_SUCCESS;
         }
    I was curious about the signal handler function. Why does it have to re-enable itself? Is it always necessary? If not, when is it? I'd like to know when I have to re-enable signal handlers.
    I'm in a situation where I can't use sigaction() function (exam rule).

    PS: a user in IRC told me "It's necessary on some platforms (implementation-defined when) with signal(). But sigaction() should avoid that issue." Is this true?

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    The "user in IRC" is mistaken.

    The signal() function defines the handling of the next received signal only, after which the default handling is reinstated. So it is necessary for the signal handler to call signal() if the program needs to continue handling signals using a non-default handler.

    signal() is specified in the C standard. sigaction() is not (albeit, it is considered a better approach by some). So, yes, sigaction() will avoid the need for calling signal(). sigaction() also handles situations where a second signal comes in while handling a signal. The potential catch is that sigaction() is also not available on all target systems.

    There are some signals that cannot be handled. There are also some signals that leave the process in an unpredictable state if the signal handler does not terminate (i.e. if the handler is used to effectively ignore the signal).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    Registered User
    Join Date
    Aug 2011
    Posts
    13
    Thanks for your support, grumpy.

    I was reading 'man signal' to learn more about this behaviour, and it seems to change according to libc version and macros defined.

    In the original Unix systems, when a handler that was established using signal() was invoked by the delivery of a
    signal, the disposition of the signal would be reset to SIG_DFL, and the system did not block delivery of further
    instances of the signal. System V also provides these semantics for signal(). This was bad because the signal
    might be delivered again before the handler had a chance to reestablish itself. Furthermore, rapid deliveries of
    the same signal could result in recursive invocations of the handler.

    BSD improved on this situation by changing the semantics of signal handling (but, unfortunately, silently changed
    the semantics when establishing a handler with signal()). On BSD, when a signal handler is invoked, the signal
    disposition is not reset, and further instances of the signal are blocked from being delivered while the handler is
    executing.

    The situation on Linux is as follows:

    * The kernel's signal() system call provides System V semantics.

    * By default, in glibc 2 and later, the signal() wrapper function does not invoke the kernel system call. Instead,
    it calls sigaction(2) using flags that supply BSD semantics. This default behavior is provided as long as the
    _BSD_SOURCE feature test macro is defined. By default, _BSD_SOURCE is defined; it is also implicitly defined if
    one defines _GNU_SOURCE, and can of course be explicitly defined.

    On glibc 2 and later, if the _BSD_SOURCE feature test macro is not defined, then signal() provides System V
    semantics. (The default implicit definition of _BSD_SOURCE is not provided if one invokes gcc(1) in one of its
    standard modes (-std=xxx or -ansi) or defines various other feature test macros such as _POSIX_SOURCE,
    _XOPEN_SOURCE, or _SVID_SOURCE; see feature_test_macros(7).)

    * The signal() function in Linux libc4 and libc5 provide System V semantics. If one on a libc5 system includes
    <bsd/signal.h> instead of <signal.h>, then signal() provides BSD semantics.
    In my Ubuntu 10.04 system, I got libc6 installed, but it says version 2.11.1-0ubuntu7.10.
    When the 'man' page talks about "libc 2 or later", what does it mean? Does it mean "libcX 2 or later" or "libc version 2.anything or later"? The man also says that _BSD_SOURCE macro is defined by default... even if I don't include any header? Probably I can check it with a #ifdef, right?
    My concern is that I will arrive at the exam place, different computers, and I will not know how that computer behave. How can I check it fast? Check for _BSD_SOURCE and libc version? (still not sure if libcX or libc v2.blabla)

    Thanks

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    glibc 2 refers to any version of the GNU C library created after 1997.

    libc6 is just a name of a package for ubuntu that delivers glibc. Libc 4 and 5 are older packages (that deliver older versions of glibc - although the versioning of a packaged library is not required to exactly match versioning of glibc). That version 2.11.1 refers to a version of glibc version 2.11.1. The -0ubuntu7.10 means the installed version was built for ubuntu7.10 - that might mean the library has simply been built from source, or it might have been tweaked for ubuntu (that sort of thing depends on the package maintainers, as well as whether the glibc folks specifically support ubuntu).

    The thing to remember is that the content of man pages will be specific to your host system. That comes down to versions of the operating system, and versions of many packages that may not be on all systems (and may be in different versions between systems).

    The way to check it fast would be to check the man pages on a system when you login, but that doesn't offer a 100% guarantee. Or you can avoid the version number madness and simply stick to things which are guaranteed on all versions. The more things you learn that are specific to your particular system, the more things you need to check when going to another system. And the more chance of your code breaking on that other system if you forget to do one check. Unfortunately, the way code breaks can be obvious (eg code that doesn't compile because of header file mismatch with your code, or a program that won't run because of mismatched libraries) or subtle (the program runs, but problems only occur in specific and possibly rare usage scenarios).

    That's life. There is not enough consistency in the unix world, as yet, for more certainty.
    Last edited by grumpy; 08-18-2012 at 03:22 PM.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  5. #5
    Registered User
    Join Date
    Aug 2011
    Posts
    13
    Ok

    Anyway, I was curious and I checked about that macro with this source code:
    Code:
    #include <stdio.h>
    
    int main(void){
    #ifdef _BSD_SOURCE
    	printf("_BSD_SOURCE is defined\n");
    #endif
    	return 0;
    }
    I compiled it with gcc filename.c -Wall and it printed the text. So, yes, even without including any particular header file, on my system that macro is defined by default, so it means I got BSD-like behaviours. Which means:
    On BSD, when a signal handler is invoked, the
    signal disposition is not reset, and further instances of the signal are
    blocked from being delivered while the handler is executing.
    and
    By default, in glibc 2 and later, the signal() wrapper function does not
    invoke the kernel system call. Instead, it calls sigaction(2) using
    flags that supply BSD semantics. This default behavior is provided as
    long as the _BSD_SOURCE feature test macro is defined.
    Sorry me for the repetition of informations, I did it to make it clear if anyone would find this topic later by search.

    Thanks

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. GTK+ C++ compiler and signal handlers
    By nickstyle in forum C++ Programming
    Replies: 6
    Last Post: 03-19-2012, 06:45 AM
  2. Return Handlers
    By Laks in forum C Programming
    Replies: 0
    Last Post: 11-22-2009, 07:18 AM
  3. Return Handlers
    By Laks in forum C Programming
    Replies: 0
    Last Post: 11-22-2009, 07:17 AM
  4. uncaught exception handlers
    By George2 in forum C# Programming
    Replies: 0
    Last Post: 04-26-2008, 08:50 AM
  5. Signal Handlers
    By MethodMan in forum Linux Programming
    Replies: 1
    Last Post: 03-05-2003, 12:20 AM

Tags for this Thread