Search code examples
csignalsblockingsigint

How to clean up local data in SIGINT handler


I need to execute clean up functions in SIGINT handler, but I can't pass local data to it. Here an example:

int main(int argc, char *argv[]) {

    struct database *db = db_cursor();
    sockfd_t master_socket = init_server();

    signal(SIGINT, sigint_handler);

    while (1) {
        // accepting connections
    }
}

void sigint_handler(int s) {
    destroy_db(db);
    shutdown(master_socket, SHUT_RDWR);
    close(master_socket);
    exit(EXIT_SUCCESS);
}

How can I implement such behaviour? I've tried make this variables are global, but I can't invoke this functions at compile time (error: initializer element is not a compile-time constant).


Solution

  • Only a very limited number of functions is guaranteed to be async-signal-safe and therefore may be called from within a signal handler, exit() f.e. does not belong to them.

    Take a different approach:

    #include <signal.h>
    
    volatile sig_atomic_t sigint_received = 0; /* volatile might be necessary depending on 
                                                  the system/implementation in use. 
                                                  (see "C11 draft standard n1570: 5.1.2.3")*/
    
    void sigint_handler(int s) 
    {
      sigint_received = 1;
    }
    
    int main(void) 
    {
      signal(SIGINT, sigint_handler);
    
      while (!sigint_received) 
      {
        /* Do stuff. */
      }
    
      /* Clean up here. */
    }
    

    For more on this see


    Note: To be maximal portable you want to use sigaction() instead of signal().

    The code to replace signal() might look like this:

    struct sigaction sa = 
    {
      sigint_handler
      /*, SA_RESTART */ /* Set this by if blocking calls like read() or accept() 
                           should _not_ return on signal reception. */
    };
    
    if (-1 == sigaction(SIGINT, &sa, NULL))
    {
      perror("sigaction() failed");
      exit(EXIT_FAILURE);
    }
    

    Documentation on sigaction():