Skip to content

Commit 9651b02

Browse files
committed
Fix Agent close hanging
Abort started candidate i/o before waiting for the task loop to stop. this prevents close from deadblocking when a task is blocked in WriteTo
1 parent bcd6915 commit 9651b02

9 files changed

Lines changed: 904 additions & 27 deletions

File tree

agent.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ type bindingRequest struct {
4242
type Agent struct {
4343
loop *taskloop.Loop
4444

45+
startedCandidatesMu sync.Mutex
46+
startedCandidates map[*candidateBase]struct{}
47+
4548
// constructed is set to true after the agent is fully initialized.
4649
// Options can check this flag to reject updates that are only valid during construction.
4750
constructed bool
@@ -353,6 +356,7 @@ func createAgentBase(config *AgentConfig) (*Agent, error) {
353356
lite: config.Lite,
354357
gatheringState: GatheringStateNew,
355358
connectionState: ConnectionStateNew,
359+
startedCandidates: make(map[*candidateBase]struct{}),
356360
localCandidates: make(map[NetworkType][]Candidate),
357361
remoteCandidates: make(map[NetworkType][]Candidate),
358362
pairsByID: make(map[uint64]*CandidatePair),
@@ -1485,7 +1489,7 @@ func (a *Agent) GracefulClose() error {
14851489

14861490
func (a *Agent) close(graceful bool) error {
14871491
// the loop is safe to wait on no matter what
1488-
a.loop.Close()
1492+
a.loop.CloseWithPreStop(a.abortStartedCandidateIO)
14891493

14901494
// but we are in less control of the notifiers, so we will
14911495
// pass through `graceful`.
@@ -1496,6 +1500,36 @@ func (a *Agent) close(graceful bool) error {
14961500
return nil
14971501
}
14981502

1503+
func (a *Agent) registerStartedCandidate(c *candidateBase) {
1504+
a.startedCandidatesMu.Lock()
1505+
defer a.startedCandidatesMu.Unlock()
1506+
1507+
if a.startedCandidates == nil {
1508+
a.startedCandidates = make(map[*candidateBase]struct{})
1509+
}
1510+
a.startedCandidates[c] = struct{}{}
1511+
}
1512+
1513+
func (a *Agent) unregisterStartedCandidate(c *candidateBase) {
1514+
a.startedCandidatesMu.Lock()
1515+
defer a.startedCandidatesMu.Unlock()
1516+
1517+
delete(a.startedCandidates, c)
1518+
}
1519+
1520+
func (a *Agent) abortStartedCandidateIO() {
1521+
a.startedCandidatesMu.Lock()
1522+
candidates := make([]*candidateBase, 0, len(a.startedCandidates))
1523+
for c := range a.startedCandidates {
1524+
candidates = append(candidates, c)
1525+
}
1526+
a.startedCandidatesMu.Unlock()
1527+
1528+
for _, c := range candidates {
1529+
_ = c.abortIO()
1530+
}
1531+
}
1532+
14991533
// Remove all candidates. This closes any listening sockets
15001534
// and removes both the local and remote candidate lists.
15011535
//

0 commit comments

Comments
 (0)