DF-3173 / pending_stat.c
/* * pending_stat.c — DF-3173 creator process. * * Blocks SIGTERM (both the main thread and the helper thread inherit * the mask), spawns a thread that sends the process SIGTERM after * <delay_ms>, then issues stat(2) on <path>. The SIGTERM pends * undeliverable while every thread blocks it; when the stat is blocked * inside autofs_trigger()'s cv_mtx_wait_sig, autofs_set_sigmask() * temporarily unmasks exactly {INT,TERM,HUP,KILL,QUIT} * (sys/vfs/autofs/autofs.c:267-291), so the pending SIGTERM interrupts * the wait immediately -> the creator exits the trigger via the EINTR * path (autofs.c:373-377) at a precise, fork-latency-independent * moment, dropping its request reference early — exactly like a user * Ctrl-C'ing a hung automount lookup. * * Build: cc -O2 -pthread -o pending_stat pending_stat.c * Run: ./pending_stat <path> <delay_ms> */ #include <sys/types.h> #include <sys/stat.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> static void * timer_thread(void *arg) { long delay_ms = (long)(intptr_t)arg; usleep(delay_ms * 1000); kill(getpid(), SIGTERM); return (NULL); } int main(int argc, char **argv) { struct stat st; sigset_t set; pthread_t t; if (argc != 3) { fprintf(stderr, "usage: %s <path> <delay_ms>\n", argv[0]); return (1); } sigemptyset(&set); sigaddset(&set, SIGTERM); if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { perror("sigprocmask"); return (1); } if (pthread_create(&t, NULL, timer_thread, (void *)(intptr_t)atoi(argv[2])) != 0) { fprintf(stderr, "pthread_create failed\n"); return (1); } if (stat(argv[1], &st) == -1) { /* EINTR from the interrupted trigger is the expected end */ } return (0); } |