DF-4365 / pcn_callout_replica_fixed.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | /* * pcn_callout_replica_fixed.c - replica of if_pcn.c's callout protocol WITH * the proposed fix.diff shape applied to pcn_tick(): * * pcn_tick() never blocks the softclock thread on the serializer; on * contention it retries on the next tick (lwkt_serialize_try + 1-tick * callout_reset retry). pcn_stop() keeps its synchronous callout_stop() * under the serializer - but now the callback can never be parked inside * lwkt_serialize_enter() holding the stopper's lock, so callout_stop() * always returns (no AB-BA). * * Sysctls (root): * kern.pcnrepfix_arm = 1 arm the fixed-shape timer (fast, 1 tick) * kern.pcnrepfix_stop = 1 hold the serializer ~3s (worst pcn_stop * duration), then callout_stop() - must RETURN. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/sysctl.h> #include <sys/serialize.h> #include <sys/callout.h> static struct lwkt_serialize ser; static struct callout tick_c; static volatile int tick_fired; static volatile int tick_ran; static volatile int tick_retries; static void pcn_tick_fixed(void *arg) { tick_fired++; /* FIX SHAPE: never block - try, else retry next tick */ if (!lwkt_serialize_try(&ser)) { tick_retries++; callout_reset(&tick_c, 1, pcn_tick_fixed, NULL); return; } tick_ran++; callout_reset(&tick_c, hz, pcn_tick_fixed, 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 || v == 0) return (error); callout_reset(&tick_c, 1, pcn_tick_fixed, NULL); kprintf("pcnrepfix[arm]: fixed-shape pcn_stat_timer armed\n"); return (0); } static int stop_sysctl(SYSCTL_HANDLER_ARGS) { int error, v = 0; int i; error = sysctl_handle_int(oidp, &v, 0, req); if (error || req->newptr == NULL || v == 0) return (error); lwkt_serialize_enter(&ser); /* pcn_stop context */ for (i = 0; i < 3000; i++) /* hold it ~3s: worst case */ DELAY(1000); kprintf("pcnrepfix[stop]: fires=%d ran=%d retries=%d - " "calling callout_stop\n", tick_fired, tick_ran, tick_retries); callout_stop(&tick_c); /* must RETURN now */ kprintf("pcnrepfix[stop]: callout_stop RETURNED, pending=%d\n", callout_pending(&tick_c)); lwkt_serialize_exit(&ser); return (0); } static int stat_sysctl(SYSCTL_HANDLER_ARGS) { int error, v = 0; if (req->newptr != NULL) { /* write: report counters */ kprintf("pcnrepfix[stat]: fires=%d ran=%d retries=%d " "pending=%d\n", tick_fired, tick_ran, tick_retries, callout_pending(&tick_c)); return (0); } error = sysctl_handle_int(oidp, &v, 0, req); return (error); } static int pcnrepfix_load(module_t mod, int what, void *arg) { switch (what) { case MOD_LOAD: lwkt_serialize_init(&ser); callout_init(&tick_c); /* plain, like if_pcn.c:577 */ tick_fired = tick_ran = tick_retries = 0; sysctl_add_oid(NULL, SYSCTL_STATIC_CHILDREN(_kern), OID_AUTO, "pcnrepfix_arm", CTLTYPE_INT|CTLFLAG_RW, NULL, 0, arm_sysctl, "I", "arm fixed-shape pcn tick"); sysctl_add_oid(NULL, SYSCTL_STATIC_CHILDREN(_kern), OID_AUTO, "pcnrepfix_stop", CTLTYPE_INT|CTLFLAG_RW, NULL, 0, stop_sysctl, "I", "pcn_stop shape with fix"); sysctl_add_oid(NULL, SYSCTL_STATIC_CHILDREN(_kern), OID_AUTO, "pcnrepfix_stat", CTLTYPE_INT|CTLFLAG_RW, NULL, 0, stat_sysctl, "I", "report tick counters"); kprintf("pcnrepfix: loaded (fixed-shape replica)\n"); return (0); case MOD_UNLOAD: /* stop the armed timer first (NOT under the serializer) */ callout_stop(&tick_c); return (0); } return (EOPNOTSUPP); } static moduledata_t pcnrepfix_mod = { "pcnrepfix", pcnrepfix_load, NULL }; DECLARE_MODULE(pcnrepfix, pcnrepfix_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |