This is an automated email from the ASF dual-hosted git repository. sjanc pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-newtmgr.git
commit 2efc393f60de36866db3d05a9bc1cccc7b08b057 Author: Szymon Janc <[email protected]> AuthorDate: Thu Oct 22 00:25:44 2026 +0200 nmxact/omp: Make Stop wait for CoAP listener removal Each OMP listener goroutine deferred RemoveCoapListener() before wg.Done(). Deferred calls run in reverse order, so wg.Done() ran first and Stop() could return while the CoAP listeners were still registered. Messages received right after Stop() were then still dispatched to listeners nobody reads anymore, contrary to the intent of Stop() waiting for the listener goroutines. Swap the defers so the CoAP listener is removed before the goroutine signals completion. Assisted-by: Claude:claude-opus-5-5 --- nmxact/omp/dispatch.go | 4 +++- nmxact/omp/dispatch_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/nmxact/omp/dispatch.go b/nmxact/omp/dispatch.go index 62d0be7..9041bd2 100644 --- a/nmxact/omp/dispatch.go +++ b/nmxact/omp/dispatch.go @@ -88,8 +88,10 @@ func (d *Dispatcher) addOmpListener(seq uint8) (*Listener, error) { d.wg.Add(1) go func() { - defer d.RemoveCoapListener(mc) + // Deferred calls run in reverse order: remove the CoAP listener + // before signalling Stop() that this goroutine is done. defer d.wg.Done() + defer d.RemoveCoapListener(mc) // Listen for events. All feedback is sent to the client via the NMP // listener channels. It is done this way so that client code can be diff --git a/nmxact/omp/dispatch_test.go b/nmxact/omp/dispatch_test.go index 85d819c..97e7e75 100644 --- a/nmxact/omp/dispatch_test.go +++ b/nmxact/omp/dispatch_test.go @@ -363,3 +363,30 @@ func TestDispatcherCoapListener(t *testing.T) { t.Errorf("RemoveCoapListener returned %p, want %p", got, l) } } + +// When Stop returns, the CoAP listeners owned by the OMP listeners must be +// gone. The window is small, so repeat a number of times. +func TestDispatcherStopRemovesCoapListeners(t *testing.T) { + for i := 0; i < 200; i++ { + d, err := NewDispatcher(nil, false, 0) + if err != nil { + t.Fatal(err) + } + + for seq := uint8(30); seq < 34; seq++ { + if _, err := d.AddNmpListener(seq); err != nil { + t.Fatal(err) + } + } + + stopWithTimeout(t, d) + + for seq := uint8(30); seq < 34; seq++ { + b := encodeTestOmpRsp(t, coap.Content, seq, "x") + if d.Dispatch(b) { + t.Fatalf("iteration %d: Dispatch for seq %d after Stop "+ + "returned true", i, seq) + } + } + } +}
