/*
 * fxp_callout_replica_fixed.c - protocol-level validation of the fix.diff
 * shape for if_fxp.c (DF-4064): fxp_tick() becomes non-blocking via
 * lwkt_serialize_try() + 1-tick callout_reset retry (same shape as the
 * DF-3738-validated emx fix).
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/serialize.h>
#include <sys/callout.h>
#include <sys/sysctl.h>
#include <sys/systm.h>

static struct lwkt_serialize ser;
static struct callout blk_c;
static volatile int blk_fired, blk_ran;

static void
blk_timer(void *arg)
{
	blk_fired++;
	/* FIXED shape: non-blocking try + 1-tick retry */
	if (lwkt_serialize_try(&ser) == 0) {
		callout_reset(&blk_c, 1, blk_timer, NULL);
		return;
	}
	blk_ran++;
	callout_reset(&blk_c, hz, blk_timer, NULL);
	lwkt_serialize_exit(&ser);
}

static int
arm_sysctl(SYSCTL_HANDLER_ARGS)
{
	int error, v = 0;

	error = sysctl_handle_int(oidp, &v, 0, req);
	if (error || req->newptr == NULL)
		return error;
	if (v == 1) {
		blk_fired = blk_ran = 0;
		callout_reset(&blk_c, 1, blk_timer, NULL);
		kprintf("fxrf: armed (FIXED fxp_tick shape)\n");
	}
	return 0;
}

static int
stop_blk_sysctl(SYSCTL_HANDLER_ARGS)
{
	int error, v = 0;

	error = sysctl_handle_int(oidp, &v, 0, req);
	if (error || req->newptr == NULL)
		return error;
	if (v != 1)
		return 0;

	lwkt_serialize_enter(&ser);
	/* hold it long enough for the handler to hit the try + retry path */
	tsleep(&blk_ran, 0, "blkw", 3 * hz);
	kprintf("fxrf: holding serializer, callout_stop() [fxp_stop shape]...\n");
	callout_stop(&blk_c);
	kprintf("fxrf: callout_stop RETURNED cleanly, pending=%d\n",
	    callout_pending(&blk_c));
	lwkt_serialize_exit(&ser);
	return 0;
}

static SYSCTL_NODE(_kern, OID_AUTO, fxrf, CTLFLAG_RW, 0,
    "fxp callout replica fixed");
SYSCTL_PROC(_kern_fxrf, OID_AUTO, arm, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
    arm_sysctl, "I", "arm FIXED fxp_stat_timer replica");
SYSCTL_PROC(_kern_fxrf, OID_AUTO, stop_blk, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
    stop_blk_sysctl, "I", "fxp_stop vs FIXED (try+retry) fxp_tick");

static int
fxp_callout_replica_fixed_load(struct module *m, int what, void *arg)
{
	switch (what) {
	case MOD_LOAD:
		lwkt_serialize_init(&ser);
		callout_init(&blk_c);	/* NON-MP, exactly if_fxp.c:399 */
		kprintf("fxp_callout_replica_fixed: loaded (hz=%d)\n", hz);
		return 0;
	case MOD_UNLOAD:
		callout_stop(&blk_c);
		return 0;
	}
	return 0;
}

static moduledata_t fxp_callout_replica_fixed_mod = {
	"fxp_callout_replica_fixed",
	fxp_callout_replica_fixed_load,
	NULL
};
DECLARE_MODULE(fxp_callout_replica_fixed, fxp_callout_replica_fixed_mod,
    SI_SUB_DRIVERS, SI_ORDER_ANY);
