From 6ad59aa8c5627fd0e730406d6111066eadcdd15d Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 3 Nov 2016 09:43:26 -0700 Subject: Fix race condition writing soong.config soong_build is run twice simultaneously now, once for manifest generation and once for docs generation. If one starts writing the default soong.config file, and the other starts reading it, the reader can see an empty file and fail. Write the soong.config file to a temporary file and the atomically rename it into place. Bug: 32628314 Test: rm out/soong/soong.config && m -j blah && cat out/soong/soong.config Change-Id: I8119b11d45093284b24cbc926d81eb9ea4bf2e27 (cherry picked from commit d8f2014d3bba76a928c0aaa933d85c8ddd43a6da) --- android/config.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/android/config.go b/android/config.go index 74cb56e8..1088c888 100644 --- a/android/config.go +++ b/android/config.go @@ -17,6 +17,7 @@ package android import ( "encoding/json" "fmt" + "io/ioutil" "os" "path/filepath" "runtime" @@ -127,28 +128,34 @@ func loadFromConfigFile(configurable jsonConfigurable, filename string) error { return nil } +// atomically writes the config file in case two copies of soong_build are running simultaneously +// (for example, docs generation and ninja manifest generation) func saveToConfigFile(config jsonConfigurable, filename string) error { data, err := json.MarshalIndent(&config, "", " ") if err != nil { return fmt.Errorf("cannot marshal config data: %s", err.Error()) } - configFileWriter, err := os.Create(filename) + f, err := ioutil.TempFile(filepath.Dir(filename), "config") if err != nil { return fmt.Errorf("cannot create empty config file %s: %s\n", filename, err.Error()) } - defer configFileWriter.Close() + defer os.Remove(f.Name()) + defer f.Close() - _, err = configFileWriter.Write(data) + _, err = f.Write(data) if err != nil { return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error()) } - _, err = configFileWriter.WriteString("\n") + _, err = f.WriteString("\n") if err != nil { return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error()) } + f.Close() + os.Rename(f.Name(), filename) + return nil } -- cgit v1.2.3