DF-5100 / joy_crit_loop.c
/* DF-5100 trigger — exact source built on the audit guest (see build.log). * * joyread() spins inside crit_enter() until WALL-CLOCK nanotime() passes * `start + timeout` (sys/dev/misc/joy/joy.c:190-213). nanotime() adds the * stepped basetime (sys/kern/kern_clock.c:1562-1587), so a backward clock * step (settimeofday(2) / NTP step) during the loop extends the deadline in * wall time and keeps the calling CPU in a critical section (interrupts * masked, preemption blocked) for far longer than the configured timeout. * * This trigger pushes JOY_SETTIMEOUT to the 10000us maximum (joy.c:243) * and times back-to-back reads. On hardware WITH /dev/joy0 each read * measures ~timeout us of interrupt-masked spin; paired with a concurrent * backward settimeofday() the read stalls ~step-seconds longer. * On this audit guest joy(4) never attaches (no ISA gameport; kldload joy * alone creates no node), so open() returns ENOENT (see run.log). */ #include <sys/ioctl.h> #include <sys/joystick.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/time.h> #include <unistd.h> #define DEV "/dev/joy0" int main(void) { struct joystick j; struct timeval t0, t1; int fd, i, tmo = 10000; fd = open(DEV, O_RDWR); if (fd < 0) { printf("open %s: %s (errno=%d)\n", DEV, strerror(errno), errno); printf("joy(4) not attached on this machine -- cannot exercise joyread() crit loop\n"); return (2); } if (ioctl(fd, JOY_SETTIMEOUT, &tmo) < 0) { printf("JOY_SETTIMEOUT: %s\n", strerror(errno)); return (1); } for (i = 0; i < 5; i++) { gettimeofday(&t0, NULL); if (read(fd, &j, sizeof(j)) < 0) { printf("read: %s\n", strerror(errno)); return (1); } gettimeofday(&t1, NULL); printf("read %d: %ld us (x=%d y=%d b1=%d b2=%d)\n", i, (t1.tv_sec - t0.tv_sec) * 1000000L + (t1.tv_usec - t0.tv_usec), j.x, j.y, j.b1, j.b2); } return (0); } |