diff --git a/src/core/state.go b/src/core/state.go index 90a0f32831..8a59255817 100644 --- a/src/core/state.go +++ b/src/core/state.go @@ -834,11 +834,25 @@ func (state *BuildState) SyncParsePackage(label BuildLabel) *Package { return p } if ch, inserted := state.progress.pendingPackages.AddOrGet(label.packageKey(), make(chan struct{})); !inserted { - <-ch + waitOnChan(ch, fmt.Sprintf("Still waiting for SyncParsePackage(%v)", label)) } return state.Graph.PackageByLabel(label) // Important to check again; it's possible to race against this whole lot. } +func waitOnChan[T any](ch chan T, message string) T { + start := time.Now() + for { + select { + case v := <-ch: + return v + case <-time.After(time.Second * 10): + { + log.Debugf("%v (after %v)", message, time.Since(start)) + } + } + } +} + // WaitForPackage is similar to WaitForBuiltTarget however it waits for the package to be parsed, queuing it for parse // if necessary func (state *BuildState) WaitForPackage(l, dependent BuildLabel, mode ParseMode) *Package { @@ -849,13 +863,13 @@ func (state *BuildState) WaitForPackage(l, dependent BuildLabel, mode ParseMode) // If something has promised to parse it, wait for them to do so if ch := state.progress.pendingPackages.Get(key); ch != nil { - <-ch + waitOnChan(ch, fmt.Sprintf("Still waiting for pending package in WaitForPackage(%v, %v, %v)", l, dependent, mode)) return state.Graph.PackageByLabel(l) } // If something has already queued the package to be parsed, wait for them if ch := state.progress.packageWaits.Get(key); ch != nil { - <-ch + waitOnChan(ch, fmt.Sprintf("Still waiting for package wait in WaitForPackage(%v, %v, %v)", l, dependent, mode)) return state.Graph.PackageByLabel(l) } @@ -876,7 +890,7 @@ func (state *BuildState) WaitForBuiltTarget(l, dependent BuildLabel, mode ParseM // okay, we need to register and wait for this guy. if ch, inserted := state.progress.pendingTargets.AddOrGet(l, make(chan struct{})); !inserted { // Something's already registered for this, get on the train - <-ch + waitOnChan(ch, fmt.Sprintf("Still waiting on WaitForBuiltTarget(%v, %v, %v)", l, dependent, mode)) return state.Graph.Target(l) } if err := state.queueTarget(l, dependent, mode.IsForSubinclude(), mode); err != nil {