// teardown moves the connection from the dying to the dead state. func (c *Conn) teardown(abort rpccapnp.Message) { c.workers.Wait() c.mu.Lock() for _, q := range c.questions { if q != nil { q.cancel(ErrConnClosed) } } c.questions = nil exps := c.exports c.exports = nil c.embargoes = nil for _, a := range c.answers { a.cancel() } c.answers = nil c.imports = nil c.mainFunc = nil c.mu.Unlock() if c.mainCloser != nil { if err := c.mainCloser.Close(); err != nil { c.errorf("closing main interface: %v", err) } c.mainCloser = nil } // Closing an export may try to lock the Conn, so run it outside // critical section. for id, e := range exps { if e == nil { continue } if err := e.client.Close(); err != nil { c.errorf("export %v close: %v", id, err) } } exps = nil var werr error if abort.IsValid() { werr = c.transport.SendMessage(context.Background(), abort) } cerr := c.transport.Close() c.stateMu.Lock() if c.closeErr == ErrConnClosed { if cerr != nil { c.closeErr = cerr } else if werr != nil { c.closeErr = werr } } c.state = connDead c.stateCond.Broadcast() c.stateMu.Unlock() }