diff options
| author | 2024-11-14 09:53:50 -0700 | |
|---|---|---|
| committer | 2024-11-14 09:55:35 -0700 | |
| commit | 1f46a91b5a9978b5d624082de44f189ad6d22a6f (patch) | |
| tree | 708266a5cebd636983647002c73bd8538b1fde9d | |
| parent | 25777477593f60273be433e44ee9e49897bdab23 (diff) | |
build: limit concurrency of updateSymlinks
In rare cases, the unbounded concurrency here may lead to Go runtime
panics, due to the runtime spawning >10K threads.
Bug: 376466642
Test: `m` generates build files properly
Change-Id: Ib2e812b2fd56ebcee16154c69927821a4f379a87
| -rw-r--r-- | ui/build/soong.go | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/ui/build/soong.go b/ui/build/soong.go index e6d01dd1d..0963f76b7 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -433,13 +433,13 @@ func checkEnvironmentFile(ctx Context, currentEnv *Environment, envFile string) } } -func updateSymlinks(ctx Context, dir, prevCWD, cwd string) error { +func updateSymlinks(ctx Context, dir, prevCWD, cwd string, updateSemaphore chan struct{}) error { defer symlinkWg.Done() visit := func(path string, d fs.DirEntry, err error) error { if d.IsDir() && path != dir { symlinkWg.Add(1) - go updateSymlinks(ctx, path, prevCWD, cwd) + go updateSymlinks(ctx, path, prevCWD, cwd, updateSemaphore) return filepath.SkipDir } f, err := d.Info() @@ -470,12 +470,27 @@ func updateSymlinks(ctx Context, dir, prevCWD, cwd string) error { return nil } + <-updateSemaphore + defer func() { updateSemaphore <- struct{}{} }() if err := filepath.WalkDir(dir, visit); err != nil { return err } return nil } +// b/376466642: If the concurrency of updateSymlinks is unbounded, Go's runtime spawns a +// theoretically unbounded number of threads to handle blocking syscalls. This causes the runtime to +// panic due to hitting thread limits in rare cases. Limiting to GOMAXPROCS concurrent symlink +// updates should make this a non-issue. +func newUpdateSemaphore() chan struct{} { + numPermits := runtime.GOMAXPROCS(0) + c := make(chan struct{}, numPermits) + for i := 0; i < numPermits; i++ { + c <- struct{}{} + } + return c +} + func fixOutDirSymlinks(ctx Context, config Config, outDir string) error { cwd, err := os.Getwd() if err != nil { @@ -508,7 +523,7 @@ func fixOutDirSymlinks(ctx Context, config Config, outDir string) error { } symlinkWg.Add(1) - if err := updateSymlinks(ctx, outDir, prevCWD, cwd); err != nil { + if err := updateSymlinks(ctx, outDir, prevCWD, cwd, newUpdateSemaphore()); err != nil { return err } symlinkWg.Wait() |