Commit 2ad67147 authored by Anthony Martin's avatar Anthony Martin

syscall: lazily populate the environment cache on Plan 9

This decreases the amount of system calls during the
first call to Getenv. Calling Environ will still read
in all environment variables and populate the cache.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6939048
parent 1b18a607
...@@ -12,14 +12,17 @@ import ( ...@@ -12,14 +12,17 @@ import (
) )
var ( var (
// envOnce guards initialization by copyenv, which populates env. // envOnce guards copyenv, which populates env.
envOnce sync.Once envOnce sync.Once
// envLock guards env. // envLock guards env.
envLock sync.RWMutex envLock sync.RWMutex
// env maps from an environment variable to its value. // env maps from an environment variable to its value.
env map[string]string env = make(map[string]string)
errZeroLengthKey = errors.New("zero length key")
errShortWrite = errors.New("i/o count too small")
) )
func readenv(key string) (string, error) { func readenv(key string) (string, error) {
...@@ -47,12 +50,18 @@ func writeenv(key, value string) error { ...@@ -47,12 +50,18 @@ func writeenv(key, value string) error {
return err return err
} }
defer Close(fd) defer Close(fd)
_, err = Write(fd, []byte(value)) b := []byte(value)
return err n, err := Write(fd, b)
if err != nil {
return err
}
if n != len(b) {
return errShortWrite
}
return nil
} }
func copyenv() { func copyenv() {
env = make(map[string]string)
fd, err := Open("/env", O_RDONLY) fd, err := Open("/env", O_RDONLY)
if err != nil { if err != nil {
return return
...@@ -72,7 +81,6 @@ func copyenv() { ...@@ -72,7 +81,6 @@ func copyenv() {
} }
func Getenv(key string) (value string, found bool) { func Getenv(key string) (value string, found bool) {
envOnce.Do(copyenv)
if len(key) == 0 { if len(key) == 0 {
return "", false return "", false
} }
...@@ -80,17 +88,20 @@ func Getenv(key string) (value string, found bool) { ...@@ -80,17 +88,20 @@ func Getenv(key string) (value string, found bool) {
envLock.RLock() envLock.RLock()
defer envLock.RUnlock() defer envLock.RUnlock()
v, ok := env[key] if v, ok := env[key]; ok {
if !ok { return v, true
}
v, err := readenv(key)
if err != nil {
return "", false return "", false
} }
env[key] = v
return v, true return v, true
} }
func Setenv(key, value string) error { func Setenv(key, value string) error {
envOnce.Do(copyenv)
if len(key) == 0 { if len(key) == 0 {
return errors.New("zero length key") return errZeroLengthKey
} }
envLock.Lock() envLock.Lock()
...@@ -105,8 +116,6 @@ func Setenv(key, value string) error { ...@@ -105,8 +116,6 @@ func Setenv(key, value string) error {
} }
func Clearenv() { func Clearenv() {
envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv
envLock.Lock() envLock.Lock()
defer envLock.Unlock() defer envLock.Unlock()
...@@ -115,9 +124,10 @@ func Clearenv() { ...@@ -115,9 +124,10 @@ func Clearenv() {
} }
func Environ() []string { func Environ() []string {
envOnce.Do(copyenv)
envLock.RLock() envLock.RLock()
defer envLock.RUnlock() defer envLock.RUnlock()
envOnce.Do(copyenv)
a := make([]string, len(env)) a := make([]string, len(env))
i := 0 i := 0
for k, v := range env { for k, v := range env {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment