[snip]
The result of this is that the acks become ambiguous in the presence
of an unreliable or antagonistically delayed transport. For instance,
if GDB sends a memory write, the stub acks it, the stub replies with
OK, and then GDB's ack is delayed. Existing implementations of the
protocol will resend the OK in this case, assuming the message was
lost - from stub side that's indistinguishable from ack lost. GDB's
long-delayed ACK arrives on the stub at the same time the OK arrives
at GDB. GDB must ack again - it doesn't know whether the first ack
ever made it through, and if it doesn't ack now then the stub might
keep resending that OK until it gets through. So now GDB sends an
ack. Simultaneously the stub sends a stop reply indicating that some
other thread has stopped. When it receives the ack, it thinks GDB saw
the stop reply and does not resend it. But GDB hasn't seen it yet,
and if it is dropped the conversation is now out of sync. GDB will
hang around waiting for an event that has already been reported.