> It is possible to demonstrate this with some effort using
> a small C program.

For completeness this is an example of a program to reproduce
the issue: DIE("tcgetpgrp"). The failure window is small, so
many iterations and a diverse host workload is required to
demonstrate the issue. Alternatively, deliberately introducing
a short delay at maybe_give_terminal_to() should reduce the
time to detection.


    #include <errno.h>
    #include <fcntl.h>
    #include <stdarg.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <time.h>
    #include <unistd.h>

    #include <sys/wait.h>

    #define DIE(...) die(__LINE__, __VA_ARGS__)

    void die(unsigned lineno, const char *fmt, ...)
    {
        va_list argp;

        va_start(argp, fmt);
        vfprintf(stderr, fmt, argp);
        fputc('\n', stderr);
        exit(1);
    }

    int main()
    {
        const char *ttyname = ctermid(0);
        if (!ttyname) DIE("ctermid");

        int ttyfd = open(ttyname, O_RDONLY);
        if (-1 == ttyfd) DIE(ttyname);

        pid_t child = fork();

        if (-1 == child) DIE("fork");

        if (!child) {
            if (setpgid(0, 0)) DIE("setpgid");
            kill(getpid(), SIGSTOP);
            exit(0);
        }

        if (setpgid(child, child)) DIE("setpgid");
        if (tcsetpgrp(ttyfd, child)) DIE("tcsetpgrp");

        int status;
        pid_t waited;
        waited = waitpid(child, &status, WUNTRACED);
        if (waited != child || !WIFSTOPPED(status)) DIE("waitpid");

        struct timespec delay = {
            .tv_nsec = 10000000
        };

        nanosleep(&delay, 0);

        if (child != tcgetpgrp(ttyfd)) DIE("tcgetpgrp");

        return 0;
    }


Earl

Reply via email to