user8495585
user8495585

Reputation:

How to leave endless loop by signal?

If I have something like this.

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

void signalquit(int sig)
{
   printf("\nQuitting..\n");
   (void)signal(SIGINT, SIG_DFL);
   //How to return?
}

int main(void)
{
   (void)signal(SIGINT, signalquit);
   while (1)
   {
      //Something...
   }
   //Continue here after quit with "Control + C"
   return 0;
}

How can I return to my main function after the while loop and after quitting with Control + C? Thanks for your answers!

Upvotes: 2

Views: 177

Answers (1)

alk
alk

Reputation: 70981

How to leave endless loop by signal?

By flagging that your are done.

#include <stdlib.h> /* for EXIT_XXX macros */
#include <signal.h>

volatile sig_atomic_t flag = 0;

void signalquit(int sig)
{
  flag = 1;

  signal(sig, SIG_DFL);

  return; /* Optional for void-functions */
}

int main(void)
{
  signal(SIGINT, signalquit);

  while (!flag)
  {
    //Something...
  }

  return EXIT_SUCCESS;
}

Please note that not every function may be called from a signal handler. printf() for example is not guaranteed to by async-signal-safe.

To find a list of functions to be guaranteed by POSIX to be async-signal-safe scroll down here.


Your code uses the signal() function, which for historical reason is highly unportable.

A portable approach would use the function sigaction() like for example below:

#include <stdlib.h> /* for EXIT_XXX macros */
#include <stdio.h> /* for perror() */
#include <signal.h>

volatile sig_atomic_t flag = 0;

int set_sig_handler(int sig, void(*handler)(int))
{
  struct sigaction sa = {0};
  sa.sa_handler = handler;
  return sigaction(sig, sa, NULL);
}

void signalquit(int sig)
{
  flag = 1;

  if (-1 == set_sig_handler(sig, SIG_DFL))
  {
    flag = 2;
  }
}

int main(void)
{
  if (-1 == set_sig_handler(SIGINT, signalquit))
  {
    perror("set_sig_handler() failed");
    return EXIT_FAILURE;
  }

  while (!flag)
  {
    //Something...
  }

  if (2 == flag)
  {
    perror("set_sig_handler() in signal handler failed");
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

As pointed out by pilcrow an even simpler approach is to explicitly install the handler for single use only by specifying the SA_RESETHAND flag.

#include <stdlib.h> /* for EXIT_XXX macros */
#include <stdio.h> /* for perror() */
#include <signal.h>

volatile sig_atomic_t flag = 0;

void signalquit(int sig)
{
  flag = 1;
}

int main(void)
{
  {
    struct sigaction sa = {0};

    sa.sa_handler = signalquit;
    sa.sa_flags = SA_RESETHAND;

    if (-1 == sigaction(SIGINT, sa, NULL))
    {
      perror("sigaction() failed");
      return EXIT_FAILURE;
    }
  }

  while (!flag)
  {
    //Something...
  }

  return EXIT_SUCCESS;
}

Upvotes: 5

Related Questions