/*
 * ptchurn -- hammer /dev/ptN with open+read+close while the ptsim2 bus
 * churns targets, so pt periphs are xpt_schedule()d on their device drvq
 * exactly when AC_LOST_DEVICE frees them (DF-5550 live-path repro).
 *
 * usage: ptchurn <first> <last> <seconds>
 */
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

static volatile sig_atomic_t run_flag = 1;
static int consfd = -1;

static void
on_alarm(int sig)
{
	run_flag = 0;
}

int
main(int argc, char **argv)
{
	int first, last, secs, i;
	unsigned long *opens, *errs;
	int nproc;

	if (argc != 4) {
		fprintf(stderr, "usage: %s <first> <last> <seconds>\n",
		    argv[0]);
		return (2);
	}
	first = atoi(argv[1]);
	last = atoi(argv[2]);
	secs = atoi(argv[3]);
	nproc = last - first + 1;
	if (nproc <= 0)
		return (2);

	opens = calloc(nproc, sizeof(*opens));
	errs = calloc(nproc, sizeof(*errs));

	consfd = open("/dev/console", O_WRONLY);
	signal(SIGALRM, on_alarm);

	for (i = first; i <= last; i++) {
		int pid = fork();
		if (pid == 0) {
			char path[64];
			unsigned long o = 0, e = 0;
			int idx = i - first, n = 0;

			alarm(secs);
			snprintf(path, sizeof(path), "/dev/pt%d", i);
			while (run_flag) {
				int fd = open(path, O_RDWR);
				if (fd >= 0) {
					char b[16];
					read(fd, b, sizeof(b));
					close(fd);
					o++;
				} else {
					e++;
				}
				if (++n % 64 == 0)
					opens[idx] = o, errs[idx] = e;
			}
			opens[idx] = o;
			errs[idx] = e;
			_exit(0);
		}
	}
	for (i = 0; i < nproc; i++)
		wait(NULL);
	{
		unsigned long o = 0, e = 0;
		for (i = 0; i < nproc; i++)
			o += opens[i], e += errs[i];
		printf("CHURN-DONE opens=%lu errors=%lu\n", o, e);
		if (consfd >= 0)
			dprintf(consfd, "[CHURN] done opens=%lu errors=%lu\n",
			    o, e);
	}
	return (0);
}
