# DF-3738 — emx(4) callout_stop(&sc->timer) AB-BA deadlock (DF-3715 em(4) twin)

## What
`emx_timer()` is an MP callout whose callback **blocks** on the driver
serializer; `emx_stop()` (and two other paths) call `callout_stop()` on it
**while holding that same serializer**.  DragonFly's `callout_stop()` is
synchronous — it sleeps (`"costp"`, sys/kern/kern_timeout.c:920) until the
in-progress callback finishes — and `lwkt_serialize_enter()` sleeps
(`"slize"`, sys/kern/lwkt_serialize.c:234) until the serializer is free.
Callback parked on the serializer + stopper parked in `callout_stop()`
holding the serializer = **permanent AB-BA deadlock**: the stopping thread
AND the softclock thread of that CPU wedge forever.

Driver sites:
- `emx_timer()` — sys/dev/netif/emx/if_emx.c:1908-1931
  (`lwkt_serialize_enter(&sc->main_serialize)` at :1914, self re-arm at
  :1928 inside the serializer).
- `callout_stop(&sc->timer)` under `ASSERT_IFNET_SERIALIZED_ALL`:
  - `emx_stop()` — :2030 (callers: SIOCSIFFLAGS :1227, `emx_init` :1354,
    `emx_detach` :989, `emx_suspend` :1059 — every ifconfig down/up,
    MTU/media/cap change, detach, kldunload, suspend, watchdog reinit);
  - `emx_intr_body()` LSC path — :1534 (ISR holds `main_serialize`; then
    `emx_serialize_skipmain` adds tx+rx serializers);
  - `emx_npoll_status()` — :4196 (polling status, main serializer).

The try-based `emx_txgc_timer()` (:426-449) is **not** affected (it never
blocks); this is exactly the em(4) DF-3715 structure.

## Build / run (guest)
```
# tarball Makefile + emx_callout_replica.c into /root/emxkmod
cd /root/emxkmod && make
kldload /root/emxkmod/emx_callout_replica.ko
sysctl kern.emxreplica.arm=1; sleep 2
sysctl kern.emxreplica.stop_gc=1            # negative control: returns
(sysctl kern.emxreplica.stop_blk=1 &)       # AB-BA: NEVER returns
sleep 6; dmesg | grep emxreplica | tail
ps -o pid,stat,wchan,command -ax | grep stop_blk    # D4 costp
# then reset the guest
```

## Expected (and observed) output
Console ends with:
```
emxreplica[blk]: handler BLOCKED on our serializer (fired=14 ran=13) - entering callout_stop() [emx_stop shape]
emxreplica[blk]: IF THIS IS THE LAST emxreplica LINE, AB-BA DEADLOCK IS PROVEN
```
— and the "callout_stop returned" line NEVER appears.  `ps` shows the
stopper in `D4 costp`; `ps -ax` shows `softclock 0` in `B0 slize` (parked
inside the callback's `lwkt_serialize_enter`).  Negative control
(`stop_gc`): `callout_stop returned, pending=0`.

Fixed-shape validation (`emx_callout_replica_fixed.c`, replicating the
fix.diff protocol): `sysctl kern.emxreplica.stop_fixed=1` →
`callout_stop returned, pending=0`, `STOP_FIXED_RC=0`, clean `kldunload`.
