type wantConn struct {
cm connectMethod
key connectMethodKey // cm.key()
- ctx context.Context // context for dial
ready chan struct{} // closed when pc, err pair is delivered
// hooks for testing to know when dials are done
beforeDial func()
afterDial func()
- mu sync.Mutex // protects pc, err, close(ready)
+ mu sync.Mutex // protects ctx, pc, err, close(ready)
+ ctx context.Context // context for dial, cleared after delivered or canceled
pc *persistConn
err error
}
}
}
+// getCtxForDial returns context for dial or nil if connection was delivered or canceled.
+func (w *wantConn) getCtxForDial() context.Context {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ return w.ctx
+}
+
// tryDeliver attempts to deliver pc, err to w and reports whether it succeeded.
func (w *wantConn) tryDeliver(pc *persistConn, err error) bool {
w.mu.Lock()
return false
}
+ w.ctx = nil
w.pc = pc
w.err = err
if w.pc == nil && w.err == nil {
close(w.ready) // catch misbehavior in future delivery
}
pc := w.pc
+ w.ctx = nil
w.pc = nil
w.err = err
w.mu.Unlock()
// If the dial is canceled or unsuccessful, dialConnFor decrements t.connCount[w.cm.key()].
func (t *Transport) dialConnFor(w *wantConn) {
defer w.afterDial()
+ ctx := w.getCtxForDial()
+ if ctx == nil {
+ return
+ }
- pc, err := t.dialConn(w.ctx, w.cm)
+ pc, err := t.dialConn(ctx, w.cm)
delivered := w.tryDeliver(pc, err)
if err == nil && (!delivered || pc.alt != nil) {
// pconn was not passed to w,