aboutsummaryrefslogtreecommitdiffhomepage
path: root/loader
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2020-08-28 18:54:00 +0200
committerRon Evans <[email protected]>2020-08-29 00:02:55 +0200
commitecaf9461cef875221155a997c1cf6371a5482b49 (patch)
tree1647f9e5cbf8e23e571894ee3c7b8b6172faf07d /loader
parentae01904ab08fe65c5f6a63962381cc1c5b78989a (diff)
downloadtinygo-ecaf9461cef875221155a997c1cf6371a5482b49.tar.gz
tinygo-ecaf9461cef875221155a997c1cf6371a5482b49.zip
loader: be more robust when creating the cached GOROOT
This commit fixes two issues: * Do not try to create the cached GOROOT multiple times in parallel. This may happen in tests and is a waste of resources (and thus speed). * Check for an "access denied" error when trying to rename a directory over an existing directory. On *nix systems, this results in the expected "file exists" error. Unfortunately, Windows gives an access denied. This commit fixes the Windows behavior.
Diffstat (limited to 'loader')
-rw-r--r--loader/goroot.go21
1 files changed, 21 insertions, 0 deletions
diff --git a/loader/goroot.go b/loader/goroot.go
index d1c5d1c31..c40a9f3af 100644
--- a/loader/goroot.go
+++ b/loader/goroot.go
@@ -15,11 +15,14 @@ import (
"path"
"path/filepath"
"runtime"
+ "sync"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
)
+var gorootCreateMutex sync.Mutex
+
// GetCachedGoroot creates a new GOROOT by merging both the standard GOROOT and
// the GOROOT from TinyGo using lots of symbolic links.
func GetCachedGoroot(config *compileopts.Config) (string, error) {
@@ -54,6 +57,15 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
cachedgoroot += "-syscall"
}
+ // Do not try to create the cached GOROOT in parallel, that's only a waste
+ // of I/O bandwidth and thus speed. Instead, use a mutex to make sure only
+ // one goroutine does it at a time.
+ // This is not a way to ensure atomicity (a different TinyGo invocation
+ // could be creating the same directory), but instead a way to avoid
+ // creating it many times in parallel when running tests in parallel.
+ gorootCreateMutex.Lock()
+ defer gorootCreateMutex.Unlock()
+
if _, err := os.Stat(cachedgoroot); err == nil {
return cachedgoroot, nil
}
@@ -88,6 +100,15 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
// deleted by the defer above.
return cachedgoroot, nil
}
+ if runtime.GOOS == "windows" && os.IsPermission(err) {
+ // On Windows, a rename with a destination directory that already
+ // exists does not result in an IsExist error, but rather in an
+ // access denied error. To be sure, check for this case by checking
+ // whether the target directory exists.
+ if _, err := os.Stat(cachedgoroot); err == nil {
+ return cachedgoroot, nil
+ }
+ }
return "", err
}
return cachedgoroot, nil