Skip to content

Commit

Permalink
go/packages: correctly handle context canceled
Browse files Browse the repository at this point in the history
If the context is canceled for packages.Load, the following log message is
written numerous times to stderr and returned as a load error per-package:

internal error: error "context canceled" (*errors.errorString) without
position

packages.Load now checks if the context was canceled while parsing files and
returns nil, ctx.Err() if so.

parseFiles now will not create unnecessary goroutines when ctx is canceled.

ld.Config.Context is equivalent to ld.Context as Config is an embedded struct
within loader. Use ld.Context to refer to ld.Config.Context for consistency.
  • Loading branch information
paralin committed Apr 4, 2024
1 parent 11c692e commit 0d90ebb
Showing 1 changed file with 21 additions and 4 deletions.
25 changes: 21 additions & 4 deletions go/packages/packages.go
Expand Up @@ -852,6 +852,11 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
}(lpkg)
}
wg.Wait()

// Check if the context was canceled and return nil, context.Canceled if so.
if err := ld.Context.Err(); err != nil {
return nil, err
}
}

result := make([]*Package, len(initial))
Expand Down Expand Up @@ -910,6 +915,7 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
// loadRecursive loads the specified package and its dependencies,
// recursively, in parallel, in topological order.
// It is atomic and idempotent.
// May return early if ld.Context is canceled.
// Precondition: ld.Mode&NeedTypes.
func (ld *loader) loadRecursive(lpkg *loaderPackage) {
lpkg.loadOnce.Do(func() {
Expand All @@ -931,6 +937,7 @@ func (ld *loader) loadRecursive(lpkg *loaderPackage) {
// loadPackage loads the specified package.
// It must be called only once per Package,
// after immediate dependencies are loaded.
// May return early if ld.Context is canceled.
// Precondition: ld.Mode & NeedTypes.
func (ld *loader) loadPackage(lpkg *loaderPackage) {
if lpkg.PkgPath == "unsafe" {
Expand Down Expand Up @@ -1059,6 +1066,12 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
}

files, errs := ld.parseFiles(lpkg.CompiledGoFiles)
// parseFiles may return nil, nil if ld.Context.Err() != nil
// check if the context was canceled and return early if so.
// ld.Context will be checked again after loadPackage returns.
if err := ld.Context.Err(); err != nil {
return
}
for _, err := range errs {
appendError(err)
}
Expand Down Expand Up @@ -1239,16 +1252,20 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) {
//
// Because files are scanned in parallel, the token.Pos
// positions of the resulting ast.Files are not ordered.
//
// May return nil, nil if ld.Context is canceled.
func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) {
var wg sync.WaitGroup
n := len(filenames)
parsed := make([]*ast.File, n)
errors := make([]error, n)
for i, file := range filenames {
if ld.Config.Context.Err() != nil {
parsed[i] = nil
errors[i] = ld.Config.Context.Err()
continue
if err := ld.Context.Err(); err != nil {
// If the context was canceled: return nil, nil
// The context will be checked just after the call to parseFiles.
// Wait for all parseFile calls to be interrupted
wg.Wait()
return nil, nil
}
wg.Add(1)
go func(i int, filename string) {
Expand Down

0 comments on commit 0d90ebb

Please sign in to comment.