linuxdebuggingptrace

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


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?


Solution

  • 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.

    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.)