]> Cypherpunks repositories - gostls13.git/commitdiff
os: make Setenv update C environment variables
authorBrad Fitzpatrick <bradfitz@golang.org>
Mon, 2 May 2011 19:38:13 +0000 (12:38 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 2 May 2011 19:38:13 +0000 (12:38 -0700)
Fixes #1569

R=rsc, bradfitzwork
CC=golang-dev
https://golang.org/cl/4456045

misc/cgo/test/Makefile
misc/cgo/test/cgo_test.go
misc/cgo/test/env.go [new file with mode: 0644]
src/pkg/os/env.go
src/pkg/os/env_unix.go
src/pkg/runtime/cgo/util.c
src/pkg/runtime/proc.c

index 893540d9798782d510e010469966da2f92b57d1a..43c45f416e22821c8d98ff18279dd4e8c0f9254e 100644 (file)
@@ -10,6 +10,7 @@ CGOFILES=\
        align.go\
        basic.go\
        callback.go\
+       env.go\
        issue1222.go\
        issue1328.go\
        issue1560.go\
index e23da15770b178f2223fd9161065a4719bb1452d..94fba15dbf8257ce017fb0a166306382cb131c04 100644 (file)
@@ -25,3 +25,4 @@ func TestZeroArgCallback(t *testing.T)     { testZeroArgCallback(t) }
 func TestBlocking(t *testing.T)            { testBlocking(t) }
 func Test1328(t *testing.T)                { test1328(t) }
 func TestParallelSleep(t *testing.T)       { testParallelSleep(t) }
+func TestSetEnv(t *testing.T)              { testSetEnv(t) }
diff --git a/misc/cgo/test/env.go b/misc/cgo/test/env.go
new file mode 100644 (file)
index 0000000..53e80c7
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+#include <stdlib.h>
+*/
+import "C"
+import (
+       "os"
+       "testing"
+       "unsafe"
+)
+
+// This is really an os package test but here for convenience.
+func testSetEnv(t *testing.T) {
+       const key = "CGO_OS_TEST_KEY" 
+       const val = "CGO_OS_TEST_VALUE" 
+       os.Setenv(key, val) 
+       keyc := C.CString(key)
+       defer C.free(unsafe.Pointer(keyc))
+       v := C.getenv(keyc)
+       if v == (*C.char)(unsafe.Pointer(uintptr(0))) {
+               t.Fatal("getenv returned NULL")
+       }
+       vs := C.GoString(v)
+       if vs != val {
+               t.Fatalf("getenv() = %q; want %q", vs, val)
+       }
+}
+
+
index 3a6d79dd09589223aa92d9c8103933ad8191ce09..3772c090b8ffb64c3470311bd6d4e60157cf0293 100644 (file)
@@ -6,6 +6,8 @@
 
 package os
 
+func setenv_c(k, v string)
+
 // Expand replaces ${var} or $var in the string based on the mapping function.
 // Invocations of undefined variables are replaced with the empty string.
 func Expand(s string, mapping func(string) string) string {
index e7e1c3b90f1dc954bc0bbad38315f474b41e9a15..6a8a0b17fe19b8a8064b09494e5b31a81eb3b06b 100644 (file)
@@ -29,6 +29,8 @@ func copyenv() {
        }
 }
 
+var envLock sync.RWMutex
+
 // Getenverror retrieves the value of the environment variable named by the key.
 // It returns the value and an error, if any.
 func Getenverror(key string) (value string, err Error) {
@@ -37,6 +39,10 @@ func Getenverror(key string) (value string, err Error) {
        if len(key) == 0 {
                return "", EINVAL
        }
+
+       envLock.RLock()
+       defer envLock.RUnlock()
+
        v, ok := env[key]
        if !ok {
                return "", ENOENV
@@ -55,24 +61,36 @@ func Getenv(key string) string {
 // It returns an Error, if any.
 func Setenv(key, value string) Error {
        once.Do(copyenv)
-
        if len(key) == 0 {
                return EINVAL
        }
+
+       envLock.Lock()
+       defer envLock.Unlock()
+
        env[key] = value
+       setenv_c(key, value) // is a no-op if cgo isn't loaded
        return nil
 }
 
 // Clearenv deletes all environment variables.
 func Clearenv() {
        once.Do(copyenv) // prevent copyenv in Getenv/Setenv
+
+       envLock.Lock()
+       defer envLock.Unlock()
+
        env = make(map[string]string)
+
+       // TODO(bradfitz): pass through to C
 }
 
 // Environ returns an array of strings representing the environment,
 // in the form "key=value".
 func Environ() []string {
        once.Do(copyenv)
+       envLock.RLock()
+       defer envLock.RUnlock()
        a := make([]string, len(env))
        i := 0
        for k, v := range env {
index 0eff19aa6d5e99023a7013cc662d8065dc1870f2..ba6e0ca9c38824fa988f062857bb10be617e7ee8 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "libcgo.h"
 
+#include <stdlib.h>
+
 /* Stub for calling malloc from Go */
 static void
 x_cgo_malloc(void *p)
@@ -49,3 +51,12 @@ xlibcgo_thread_start(ThreadStart *arg)
 }
 
 void (*libcgo_thread_start)(ThreadStart*) = xlibcgo_thread_start;
+
+/* Stub for calling setenv */
+static void
+xlibcgo_setenv(char **arg)
+{
+       setenv(arg[0], arg[1], 1);
+}
+
+void (*libcgo_setenv)(char**) = xlibcgo_setenv;
index 52784854fd0fffc7788dd35600da5abb746112c9..61faa15594bea3dc05c3bd8a9b16757e969b5d20 100644 (file)
@@ -1343,3 +1343,26 @@ runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz)
        if(hz != 0)
                runtime·resetcpuprofiler(hz);
 }
+
+void (*libcgo_setenv)(byte**);
+
+void
+os·setenv_c(String k, String v)
+{
+       byte *arg[2];
+
+       if(libcgo_setenv == nil)
+               return;
+
+       arg[0] = runtime·malloc(k.len + 1);
+       runtime·mcpy(arg[0], k.str, k.len);
+       arg[0][k.len] = 0;
+
+       arg[1] = runtime·malloc(v.len + 1);
+       runtime·mcpy(arg[1], v.str, v.len);
+       arg[1][v.len] = 0;
+
+       runtime·asmcgocall(libcgo_setenv, arg);
+       runtime·free(arg[0]);
+       runtime·free(arg[1]);
+}