Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f46a91b authored by George Burgess IV's avatar George Burgess IV
Browse files

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
parent 25777477
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -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()