0

I want to suspend the thread and resume it. There are few methods listed here. But I thought of using pause() library function from unistd.h.

What are the pitfalls of using pausing in signal handler?

One I noticed is, when I send 0 to pause thread and send 0 again then my signal is queued. I need to send 1 twice to resume the thread.

I guess there may be many more cases like this. How to handle such conditions if I want to use pause() or sleep() in signal handler.

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

static bool thread_ready = false;

static void cb_sig(int signal)
{
        if (signal == SIGUSR1)
                pause();
        else if (signal == SIGUSR2)
                ;
}

static void *thread_job(void *ignore)
{
        int i = 0;
        struct sigaction act;

        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        act.sa_handler = cb_sig;

        if (sigaction(SIGUSR1, &act, NULL) == -1)
                printf("unable to handle siguser1\n");
        if (sigaction(SIGUSR2, &act, NULL) == -1)
                printf("unable to handle siguser2\n");

        thread_ready = true;
        while (1) {
                printf("thread counter: %d\n", i++);
                sleep(1);
        }

        return NULL;
}

int main()
{
        bool running;
        int user_input;
        pthread_t thread;

        if (pthread_create(&thread, NULL, thread_job, NULL))
                return -1;

        while (!thread_ready);

        for (running = true; running; ) {
                printf("0: pause thread, 1: resume thread, -1: exit\n");
                scanf("%d", &user_input);

                switch(user_input) {
                case -1:
                        running = false;
                        break;
                case 0:
                        pthread_kill(thread, SIGUSR1);
                        break;
                case 1:
                        pthread_kill(thread, SIGUSR2);
                        break;
                }
        }

        pthread_kill(thread, SIGKILL);
        return 0;
}
Shubham
  • 628
  • 1
  • 9
  • 19
  • 1
    Why do you want to use `pause()` or `sleep()` in a signal handler? Instead of using signals, why doesn't your `main()` function simply suspend or pause the thread directly? Generally, speaking, terminating a thread is problematical - it is usually better to get information to the thread that causes it to end cleanly, rather than trying to kill it directly. – Peter Jun 20 '19 at 12:02
  • Sorry I forgot to mention my use case, consider a thread pool, so a job will be passed to a thread. Now, thread is executing a job, and I want my thread pool to have pause/resume functionality. So thread should suspend even if it is in the middle of the job. There will be a monitor thread which will take care of suspending and resuming other thread in pool. – Shubham Jun 20 '19 at 12:23
  • if one thread in a program suspends another, it will be suspended even in the "middle of the job". When it is resumed, it will continue from where it was suspended. No need for signals. – Peter Jun 20 '19 at 12:26
  • Yes It should resume its job, i.e. resume where it is suspended – Shubham Jun 20 '19 at 12:27

1 Answers1

6

A signal handler should not sleep(), and probably should not pause(), even though technically, both of these functions are async-signal-safe. Signal handlers should run quickly and minimize or (preferrably) completely avoid blocking.

As for specific pitfalls, you already noted one: by default, a signal is automatically blocked while its handler is running. It is possible to install the handler in a way that avoids that, but here that wouldn't help you: if you kept sending signals that get handled by your particular handler, then you would always have at least one thread blocked in that handler. If you kept sending them to the same thread then that thread would never unblock.

More generally, there are any number of poor interactions that might happen between signal masks, signaling, and signal handlers blocking on signal receipt.

Moreover, pause() is rather non-specific unless you combine it with setting a rather restrictive signal mask (in which case sigsuspend() is probably a better choice). But if you set a restrictive signal mask then you potentially interfere with other uses of signaling.

Do not "handle" such issues other than by avoiding use of pause() and sleep() in your signal handlers.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • If I may relate signal handlers with interrupts, signal handlers should be short and return immediately, am I right? So, I need to defer the processing. – Shubham Jun 20 '19 at 12:30
  • 1
    @Shubham an Interrupt Service Routine should definitely be as short and quick as possible. Typically, they are used to simply set a flag and return; another part of your program will act on that set flag. – stevieb Jun 20 '19 at 15:22