Does tgkill interrupt tasks currently executing a system call, effectively aborting it like ptrace does?

40 Views Asked by At

Reading the manual, PTRACE_INTERRUPT will interrupt a task that's executing a system call (which will be restarted once the task is restarted).

However, tgkill mentions nothing about this; what is the effects of tgkill sending a signal to a task currently executing a system call. Will it also abort the system call?

1

There are 1 best solutions below

1
chris_se On BEST ANSWER

Short answer: yes.

Longer answer: it depends on a few factors. Some system calls can't be interrupted, and signal dispatch will wait until they have completed (just like with every other program). When the thread is currently in a system call that can be interrupted, then the behavior depends on what signal handler / mask the process has installed.

  • If the signal leads to process termination (e.g. SIGTERM by default), that takes precedent, and your process is gone.
  • If the signal is ignored, then the system call will not be interrupted.
  • If a signal handler is installed for that signal, then the system call will be interrupted.

To demonstrate this, take the following simple example code (pthread_kill uses tgkill internally):

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/signal.h>

static void handle_signal(int)
{
    // Don't use stdio in signal handler, so
    // write this to stdout manually
    write(1, "signal\n", 7);
}

static void* thread_main(void*)
{
    unsigned int rc = sleep(10);
    printf("Sleep result: %u\n", rc);
    fflush(stdout);
    return NULL;
}

int main()
{
    int rc = 0;
    pthread_t thread;
    void* retval;

    // decide per comment which variant to use
    //signal(SIGUSR1, handle_signal);
    signal(SIGUSR1, SIG_IGN);

    rc = pthread_create(&thread, NULL, &thread_main, NULL);
    if (rc) {
        fprintf(stderr, "pthread_create() failed with code %d\n", rc);
        return 1;
    }
    sleep(1);
    rc = pthread_kill(thread, SIGUSR1);
    if (rc) {
        fprintf(stderr, "pthread_kill() failed with code %d\n", rc);
        return 1;
    }
    pthread_join(thread, &retval);
    printf("Done\n");
    return 0;
}

(sleep returns the amount of seconds it didn't sleep if it was interrupted, otherwise 0.)