/*
 * DF-5437 stall prober -- an unprivileged open() of the harness cdev runs
 * the production-shaped ulpt_reset chain (2 x lksleep "WXFER" without
 * PCATCH).  SIGKILL is delivered 100 ms into the open: the victim must
 * SURVIVE until the two request timeouts elapse (uninterruptible kernel
 * sleep), proving the kill-immunity of the stall.
 *
 * usage: hx5437_probe
 */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define	DEV	"/dev/hx5437ctl"

static double
now_sec(void)
{
	struct timespec ts;

	clock_gettime(CLOCK_MONOTONIC, &ts);
	return (ts.tv_sec + ts.tv_nsec / 1e9);
}

int
main(void)
{
	pid_t pid;
	int st;
	double t0, t_kill = 0.1, t_done;

	setvbuf(stdout, NULL, _IOLBF, 0);
	printf("[*] DF-5437 probe: open(%s) runs 2x ulpt_reset requests\n", DEV);

	t0 = now_sec();
	pid = fork();
	if (pid == 0) {
		int fd = open(DEV, O_RDONLY);

		printf("[child] open returned fd=%d errno=%d after %.3f s\n",
		    fd, errno, now_sec() - t0);
		_exit(fd >= 0 ? 0 : 1);
	}
	usleep((int)(t_kill * 1e6));
	kill(pid, SIGKILL);			/* unkillable? */
	waitpid(pid, &st, 0);
	t_done = now_sec() - t0;

	printf("[R] SIGKILL sent at +%.0f ms; child reaped after %.3f s "
	    "(status=0x%x)\n", t_kill * 1000, t_done, st);
	if (t_done > 1.0) {
		printf("[R] VERDICT: opener survived SIGKILL for %.1f s "
		    "-- uninterruptible stall reproduced\n", t_done);
		return (0);
	}
	printf("[R] VERDICT: opener died quickly (%.3f s) -- stall NOT "
	    "reproduced\n", t_done);
	return (1);
}
