aboutsummaryrefslogtreecommitdiff
path: root/libgo/misc/cgo/testcshared
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2017-06-27 04:21:40 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-06-27 04:21:40 +0000
commit936615752a29ab245708d40782427c25e60a2114 (patch)
treef43366b59cae9e51da40272eefd1ea71bb3ea055 /libgo/misc/cgo/testcshared
parent9913ef5866a64176bac5749080487b0c7d637d4b (diff)
downloadgcc-936615752a29ab245708d40782427c25e60a2114.zip
gcc-936615752a29ab245708d40782427c25e60a2114.tar.gz
gcc-936615752a29ab245708d40782427c25e60a2114.tar.bz2
libgo: add misc/cgo files
Copy all the misc/cgo files from the gc toolchain into libgo/misc. These will be used for testing purposes by later changes to the gotools directory. Reviewed-on: https://go-review.googlesource.com/46721 From-SVN: r249674
Diffstat (limited to 'libgo/misc/cgo/testcshared')
-rw-r--r--libgo/misc/cgo/testcshared/main0.c36
-rw-r--r--libgo/misc/cgo/testcshared/main1.c69
-rw-r--r--libgo/misc/cgo/testcshared/main2.c56
-rw-r--r--libgo/misc/cgo/testcshared/main3.c29
-rw-r--r--libgo/misc/cgo/testcshared/main4.c215
-rw-r--r--libgo/misc/cgo/testcshared/main5.c199
-rw-r--r--libgo/misc/cgo/testcshared/src/libgo/libgo.go46
-rw-r--r--libgo/misc/cgo/testcshared/src/libgo2/dup2.go13
-rw-r--r--libgo/misc/cgo/testcshared/src/libgo2/dup3.go13
-rw-r--r--libgo/misc/cgo/testcshared/src/libgo2/libgo2.go52
-rw-r--r--libgo/misc/cgo/testcshared/src/libgo4/libgo4.go45
-rw-r--r--libgo/misc/cgo/testcshared/src/libgo5/libgo5.go44
-rw-r--r--libgo/misc/cgo/testcshared/src/p/p.go10
-rw-r--r--libgo/misc/cgo/testcshared/test.bash193
14 files changed, 1020 insertions, 0 deletions
diff --git a/libgo/misc/cgo/testcshared/main0.c b/libgo/misc/cgo/testcshared/main0.c
new file mode 100644
index 0000000..1274b89
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/main0.c
@@ -0,0 +1,36 @@
+// Copyright 2015 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.
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "p.h"
+#include "libgo.h"
+
+// Tests libgo.so to export the following functions.
+// int8_t DidInitRun();
+// int8_t DidMainRun();
+// int32_t FromPkg();
+int main(void) {
+ int8_t ran_init = DidInitRun();
+ if (!ran_init) {
+ fprintf(stderr, "ERROR: DidInitRun returned unexpected results: %d\n",
+ ran_init);
+ return 1;
+ }
+ int8_t ran_main = DidMainRun();
+ if (ran_main) {
+ fprintf(stderr, "ERROR: DidMainRun returned unexpected results: %d\n",
+ ran_main);
+ return 1;
+ }
+ int32_t from_pkg = FromPkg();
+ if (from_pkg != 1024) {
+ fprintf(stderr, "ERROR: FromPkg=%d, want %d\n", from_pkg, 1024);
+ return 1;
+ }
+ // test.bash looks for "PASS" to ensure this program has reached the end.
+ printf("PASS\n");
+ return 0;
+}
diff --git a/libgo/misc/cgo/testcshared/main1.c b/libgo/misc/cgo/testcshared/main1.c
new file mode 100644
index 0000000..420dd1e
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/main1.c
@@ -0,0 +1,69 @@
+// Copyright 2015 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.
+
+#include <stdint.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+int check_int8(void* handle, const char* fname, int8_t want) {
+ int8_t (*fn)();
+ fn = (int8_t (*)())dlsym(handle, fname);
+ if (!fn) {
+ fprintf(stderr, "ERROR: missing %s: %s\n", fname, dlerror());
+ return 1;
+ }
+ signed char ret = fn();
+ if (ret != want) {
+ fprintf(stderr, "ERROR: %s=%d, want %d\n", fname, ret, want);
+ return 1;
+ }
+ return 0;
+}
+
+int check_int32(void* handle, const char* fname, int32_t want) {
+ int32_t (*fn)();
+ fn = (int32_t (*)())dlsym(handle, fname);
+ if (!fn) {
+ fprintf(stderr, "ERROR: missing %s: %s\n", fname, dlerror());
+ return 1;
+ }
+ int32_t ret = fn();
+ if (ret != want) {
+ fprintf(stderr, "ERROR: %s=%d, want %d\n", fname, ret, want);
+ return 1;
+ }
+ return 0;
+}
+
+// Tests libgo.so to export the following functions.
+// int8_t DidInitRun() // returns true
+// int8_t DidMainRun() // returns true
+// int32_t FromPkg() // returns 1024
+int main(int argc, char** argv) {
+ void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL);
+ if (!handle) {
+ fprintf(stderr, "ERROR: failed to open the shared library: %s\n",
+ dlerror());
+ return 2;
+ }
+
+ int ret = 0;
+ ret = check_int8(handle, "DidInitRun", 1);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = check_int8(handle, "DidMainRun", 0);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = check_int32(handle, "FromPkg", 1024);
+ if (ret != 0) {
+ return ret;
+ }
+ // test.bash looks for "PASS" to ensure this program has reached the end.
+ printf("PASS\n");
+ return 0;
+}
diff --git a/libgo/misc/cgo/testcshared/main2.c b/libgo/misc/cgo/testcshared/main2.c
new file mode 100644
index 0000000..6e8bf14
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/main2.c
@@ -0,0 +1,56 @@
+// Copyright 2015 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.
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define fd (100)
+
+// Tests libgo2.so, which does not export any functions.
+// Read a string from the file descriptor and print it.
+int main(void) {
+ int i;
+ ssize_t n;
+ char buf[20];
+ struct timespec ts;
+
+ // The descriptor will be initialized in a thread, so we have to
+ // give a chance to get opened.
+ for (i = 0; i < 1000; i++) {
+ n = read(fd, buf, sizeof buf);
+ if (n >= 0)
+ break;
+ if (errno != EBADF && errno != EINVAL) {
+ fprintf(stderr, "BUG: read: %s\n", strerror(errno));
+ return 2;
+ }
+
+ // An EBADF error means that the shared library has not opened the
+ // descriptor yet.
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ }
+
+ if (n < 0) {
+ fprintf(stderr, "BUG: failed to read any data from pipe\n");
+ return 2;
+ }
+
+ if (n == 0) {
+ fprintf(stderr, "BUG: unexpected EOF\n");
+ return 2;
+ }
+
+ if (n == sizeof buf) {
+ n--;
+ }
+ buf[n] = '\0';
+ printf("%s\n", buf);
+ return 0;
+}
diff --git a/libgo/misc/cgo/testcshared/main3.c b/libgo/misc/cgo/testcshared/main3.c
new file mode 100644
index 0000000..49cc055
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/main3.c
@@ -0,0 +1,29 @@
+// Copyright 2015 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.
+
+#include <stdint.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+// Tests "main.main" is exported on android/arm,
+// which golang.org/x/mobile/app depends on.
+int main(int argc, char** argv) {
+ void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL);
+ if (!handle) {
+ fprintf(stderr, "ERROR: failed to open the shared library: %s\n",
+ dlerror());
+ return 2;
+ }
+
+ uintptr_t main_fn = (uintptr_t)dlsym(handle, "main.main");
+ if (!main_fn) {
+ fprintf(stderr, "ERROR: missing main.main: %s\n", dlerror());
+ return 2;
+ }
+
+ // TODO(hyangah): check that main.main can run.
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/libgo/misc/cgo/testcshared/main4.c b/libgo/misc/cgo/testcshared/main4.c
new file mode 100644
index 0000000..355cdef
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/main4.c
@@ -0,0 +1,215 @@
+// Copyright 2015 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.
+
+// Test that a signal handler that uses up stack space does not crash
+// if the signal is delivered to a thread running a goroutine.
+// This is a lot like misc/cgo/testcarchive/main2.c.
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sched.h>
+#include <time.h>
+#include <dlfcn.h>
+
+static void die(const char* msg) {
+ perror(msg);
+ exit(EXIT_FAILURE);
+}
+
+static volatile sig_atomic_t sigioSeen;
+
+// Use up some stack space.
+static void recur(int i, char *p) {
+ char a[1024];
+
+ *p = '\0';
+ if (i > 0) {
+ recur(i - 1, a);
+ }
+}
+
+// Signal handler that uses up more stack space than a goroutine will have.
+static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
+ char a[1024];
+
+ recur(4, a);
+ sigioSeen = 1;
+}
+
+static jmp_buf jmp;
+static char* nullPointer;
+
+// Signal handler for SIGSEGV on a C thread.
+static void segvHandler(int signo, siginfo_t* info, void* ctxt) {
+ sigset_t mask;
+ int i;
+
+ if (sigemptyset(&mask) < 0) {
+ die("sigemptyset");
+ }
+ if (sigaddset(&mask, SIGSEGV) < 0) {
+ die("sigaddset");
+ }
+ i = sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ if (i != 0) {
+ fprintf(stderr, "sigprocmask: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ // Don't try this at home.
+ longjmp(jmp, signo);
+
+ // We should never get here.
+ abort();
+}
+
+int main(int argc, char** argv) {
+ int verbose;
+ struct sigaction sa;
+ void* handle;
+ void (*fn)(void);
+ sigset_t mask;
+ int i;
+ struct timespec ts;
+
+ verbose = argc > 2;
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ // Call setsid so that we can use kill(0, SIGIO) below.
+ // Don't check the return value so that this works both from
+ // a job control shell and from a shell script.
+ setsid();
+
+ if (verbose) {
+ printf("calling sigaction\n");
+ }
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_sigaction = ioHandler;
+ if (sigemptyset(&sa.sa_mask) < 0) {
+ die("sigemptyset");
+ }
+ sa.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGIO, &sa, NULL) < 0) {
+ die("sigaction");
+ }
+
+ sa.sa_sigaction = segvHandler;
+ if (sigaction(SIGSEGV, &sa, NULL) < 0 || sigaction(SIGBUS, &sa, NULL) < 0) {
+ die("sigaction");
+ }
+
+ if (verbose) {
+ printf("calling dlopen\n");
+ }
+
+ handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
+ if (handle == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling dlsym\n");
+ }
+
+ // Start some goroutines.
+ fn = (void(*)(void))dlsym(handle, "RunGoroutines");
+ if (fn == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling RunGoroutines\n");
+ }
+
+ fn();
+
+ // Block SIGIO in this thread to make it more likely that it
+ // will be delivered to a goroutine.
+
+ if (verbose) {
+ printf("calling pthread_sigmask\n");
+ }
+
+ if (sigemptyset(&mask) < 0) {
+ die("sigemptyset");
+ }
+ if (sigaddset(&mask, SIGIO) < 0) {
+ die("sigaddset");
+ }
+ i = pthread_sigmask(SIG_BLOCK, &mask, NULL);
+ if (i != 0) {
+ fprintf(stderr, "pthread_sigmask: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling kill\n");
+ }
+
+ if (kill(0, SIGIO) < 0) {
+ die("kill");
+ }
+
+ if (verbose) {
+ printf("waiting for sigioSeen\n");
+ }
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (!sigioSeen) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ i++;
+ if (i > 5000) {
+ fprintf(stderr, "looping too long waiting for signal\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (verbose) {
+ printf("calling setjmp\n");
+ }
+
+ // Test that a SIGSEGV on this thread is delivered to us.
+ if (setjmp(jmp) == 0) {
+ if (verbose) {
+ printf("triggering SIGSEGV\n");
+ }
+
+ *nullPointer = '\0';
+
+ fprintf(stderr, "continued after address error\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling dlsym\n");
+ }
+
+ // Make sure that a SIGSEGV in Go causes a run-time panic.
+ fn = (void (*)(void))dlsym(handle, "TestSEGV");
+ if (fn == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling TestSEGV\n");
+ }
+
+ fn();
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/libgo/misc/cgo/testcshared/main5.c b/libgo/misc/cgo/testcshared/main5.c
new file mode 100644
index 0000000..1bc9910
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/main5.c
@@ -0,0 +1,199 @@
+// Copyright 2015 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.
+
+// Test that a signal handler works in non-Go code when using
+// os/signal.Notify.
+// This is a lot like misc/cgo/testcarchive/main3.c.
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sched.h>
+#include <dlfcn.h>
+
+static void die(const char* msg) {
+ perror(msg);
+ exit(EXIT_FAILURE);
+}
+
+static volatile sig_atomic_t sigioSeen;
+
+static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
+ sigioSeen = 1;
+}
+
+int main(int argc, char** argv) {
+ int verbose;
+ struct sigaction sa;
+ void* handle;
+ void (*fn1)(void);
+ int (*sawSIGIO)(void);
+ int i;
+ struct timespec ts;
+
+ verbose = argc > 2;
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ if (verbose) {
+ printf("calling sigaction\n");
+ }
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_sigaction = ioHandler;
+ if (sigemptyset(&sa.sa_mask) < 0) {
+ die("sigemptyset");
+ }
+ sa.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGIO, &sa, NULL) < 0) {
+ die("sigaction");
+ }
+
+ if (verbose) {
+ printf("calling dlopen\n");
+ }
+
+ handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
+ if (handle == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ // At this point there should not be a Go signal handler
+ // installed for SIGIO.
+
+ if (verbose) {
+ printf("raising SIGIO\n");
+ }
+
+ if (raise(SIGIO) < 0) {
+ die("raise");
+ }
+
+ if (verbose) {
+ printf("waiting for sigioSeen\n");
+ }
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (!sigioSeen) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ i++;
+ if (i > 5000) {
+ fprintf(stderr, "looping too long waiting for signal\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ sigioSeen = 0;
+
+ // Tell the Go code to catch SIGIO.
+
+ if (verbose) {
+ printf("calling dlsym\n");
+ }
+
+ fn1 = (void(*)(void))dlsym(handle, "CatchSIGIO");
+ if (fn1 == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling CatchSIGIO\n");
+ }
+
+ fn1();
+
+ if (verbose) {
+ printf("raising SIGIO\n");
+ }
+
+ if (raise(SIGIO) < 0) {
+ die("raise");
+ }
+
+ if (verbose) {
+ printf("calling dlsym\n");
+ }
+
+ // Check that the Go code saw SIGIO.
+ sawSIGIO = (int (*)(void))dlsym(handle, "SawSIGIO");
+ if (sawSIGIO == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling SawSIGIO\n");
+ }
+
+ if (!sawSIGIO()) {
+ fprintf(stderr, "Go handler did not see SIGIO\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (sigioSeen != 0) {
+ fprintf(stderr, "C handler saw SIGIO when only Go handler should have\n");
+ exit(EXIT_FAILURE);
+ }
+
+ // Tell the Go code to stop catching SIGIO.
+
+ if (verbose) {
+ printf("calling dlsym\n");
+ }
+
+ fn1 = (void(*)(void))dlsym(handle, "ResetSIGIO");
+ if (fn1 == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling ResetSIGIO\n");
+ }
+
+ fn1();
+
+ if (verbose) {
+ printf("raising SIGIO\n");
+ }
+
+ if (raise(SIGIO) < 0) {
+ die("raise");
+ }
+
+ if (verbose) {
+ printf("calling SawSIGIO\n");
+ }
+
+ if (sawSIGIO()) {
+ fprintf(stderr, "Go handler saw SIGIO after Reset\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("waiting for sigioSeen\n");
+ }
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (!sigioSeen) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ i++;
+ if (i > 5000) {
+ fprintf(stderr, "looping too long waiting for signal\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/libgo/misc/cgo/testcshared/src/libgo/libgo.go b/libgo/misc/cgo/testcshared/src/libgo/libgo.go
new file mode 100644
index 0000000..8a4bf79
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/src/libgo/libgo.go
@@ -0,0 +1,46 @@
+// Copyright 2015 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 main
+
+import (
+ _ "p"
+ "syscall"
+ "time"
+)
+
+import "C"
+
+var initCh = make(chan int, 1)
+var ranMain bool
+
+func init() {
+ // emulate an exceedingly slow package initialization function
+ time.Sleep(100 * time.Millisecond)
+ initCh <- 42
+}
+
+func main() {
+ ranMain = true
+}
+
+//export DidInitRun
+func DidInitRun() bool {
+ select {
+ case x := <-initCh:
+ if x != 42 {
+ // Just in case initCh was not correctly made.
+ println("want init value of 42, got: ", x)
+ syscall.Exit(2)
+ }
+ return true
+ default:
+ return false
+ }
+}
+
+//export DidMainRun
+func DidMainRun() bool {
+ return ranMain
+}
diff --git a/libgo/misc/cgo/testcshared/src/libgo2/dup2.go b/libgo/misc/cgo/testcshared/src/libgo2/dup2.go
new file mode 100644
index 0000000..d18f0b1
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/src/libgo2/dup2.go
@@ -0,0 +1,13 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux,!arm64 netbsd openbsd
+
+package main
+
+import "syscall"
+
+func dup2(oldfd, newfd int) error {
+ return syscall.Dup2(oldfd, newfd)
+}
diff --git a/libgo/misc/cgo/testcshared/src/libgo2/dup3.go b/libgo/misc/cgo/testcshared/src/libgo2/dup3.go
new file mode 100644
index 0000000..c9c65a6
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/src/libgo2/dup3.go
@@ -0,0 +1,13 @@
+// Copyright 2015 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.
+
+// +build linux,arm64
+
+package main
+
+import "syscall"
+
+func dup2(oldfd, newfd int) error {
+ return syscall.Dup3(oldfd, newfd, 0)
+}
diff --git a/libgo/misc/cgo/testcshared/src/libgo2/libgo2.go b/libgo/misc/cgo/testcshared/src/libgo2/libgo2.go
new file mode 100644
index 0000000..1b69d8f
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/src/libgo2/libgo2.go
@@ -0,0 +1,52 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package main
+
+// Test a shared library created by -buildmode=c-shared that does not
+// export anything.
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+)
+
+// To test this we want to communicate between the main program and
+// the shared library without using any exported symbols. The init
+// function creates a pipe and Dups the read end to a known number
+// that the C code can also use.
+
+const (
+ fd = 100
+)
+
+func init() {
+ var p [2]int
+ if e := syscall.Pipe(p[0:]); e != nil {
+ fmt.Fprintf(os.Stderr, "pipe: %v\n", e)
+ os.Exit(2)
+ }
+
+ if e := dup2(p[0], fd); e != nil {
+ fmt.Fprintf(os.Stderr, "dup2: %v\n", e)
+ os.Exit(2)
+ }
+
+ const str = "PASS"
+ if n, e := syscall.Write(p[1], []byte(str)); e != nil || n != len(str) {
+ fmt.Fprintf(os.Stderr, "write: %d %v\n", n, e)
+ os.Exit(2)
+ }
+
+ if e := syscall.Close(p[1]); e != nil {
+ fmt.Fprintf(os.Stderr, "close: %v\n", e)
+ os.Exit(2)
+ }
+}
+
+func main() {
+}
diff --git a/libgo/misc/cgo/testcshared/src/libgo4/libgo4.go b/libgo/misc/cgo/testcshared/src/libgo4/libgo4.go
new file mode 100644
index 0000000..ab40b75
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/src/libgo4/libgo4.go
@@ -0,0 +1,45 @@
+// Copyright 2015 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 main
+
+import "C"
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+)
+
+// RunGoroutines starts some goroutines that don't do anything.
+// The idea is to get some threads going, so that a signal will be delivered
+// to a thread started by Go.
+//export RunGoroutines
+func RunGoroutines() {
+ for i := 0; i < 4; i++ {
+ go func() {
+ runtime.LockOSThread()
+ select {}
+ }()
+ }
+}
+
+var P *byte
+
+// TestSEGV makes sure that an invalid address turns into a run-time Go panic.
+//export TestSEGV
+func TestSEGV() {
+ defer func() {
+ if recover() == nil {
+ fmt.Fprintln(os.Stderr, "no panic from segv")
+ os.Exit(1)
+ }
+ }()
+ *P = 0
+ fmt.Fprintln(os.Stderr, "continued after segv")
+ os.Exit(1)
+}
+
+func main() {
+}
diff --git a/libgo/misc/cgo/testcshared/src/libgo5/libgo5.go b/libgo/misc/cgo/testcshared/src/libgo5/libgo5.go
new file mode 100644
index 0000000..94e5d21c
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/src/libgo5/libgo5.go
@@ -0,0 +1,44 @@
+// Copyright 2015 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 main
+
+import "C"
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+ "time"
+)
+
+// The channel used to read SIGIO signals.
+var sigioChan chan os.Signal
+
+// CatchSIGIO starts catching SIGIO signals.
+//export CatchSIGIO
+func CatchSIGIO() {
+ sigioChan = make(chan os.Signal, 1)
+ signal.Notify(sigioChan, syscall.SIGIO)
+}
+
+// ResetSIGIO stops catching SIGIO signals.
+//export ResetSIGIO
+func ResetSIGIO() {
+ signal.Reset(syscall.SIGIO)
+}
+
+// SawSIGIO returns whether we saw a SIGIO within a brief pause.
+//export SawSIGIO
+func SawSIGIO() C.int {
+ select {
+ case <-sigioChan:
+ return 1
+ case <-time.After(100 * time.Millisecond):
+ return 0
+ }
+}
+
+func main() {
+}
diff --git a/libgo/misc/cgo/testcshared/src/p/p.go b/libgo/misc/cgo/testcshared/src/p/p.go
new file mode 100644
index 0000000..82b445c
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/src/p/p.go
@@ -0,0 +1,10 @@
+// Copyright 2015 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 p
+
+import "C"
+
+//export FromPkg
+func FromPkg() int32 { return 1024 }
diff --git a/libgo/misc/cgo/testcshared/test.bash b/libgo/misc/cgo/testcshared/test.bash
new file mode 100644
index 0000000..0315fb0
--- /dev/null
+++ b/libgo/misc/cgo/testcshared/test.bash
@@ -0,0 +1,193 @@
+#!/usr/bin/env bash
+# Copyright 2015 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.
+
+# For testing Android, this script requires adb to push and run compiled
+# binaries on a target device.
+
+set -e
+
+if [ ! -f src/libgo/libgo.go ]; then
+ cwd=$(pwd)
+ echo "misc/cgo/testcshared/test.bash is running in $cwd" 1>&2
+ exit 1
+fi
+
+goos=$(go env GOOS)
+goarch=$(go env GOARCH)
+goroot=$(go env GOROOT)
+if [ ! -d "$goroot" ]; then
+ echo 'misc/cgo/testcshared/test.bash cannot find GOROOT' 1>&2
+ echo '$GOROOT:' "$GOROOT" 1>&2
+ echo 'go env GOROOT:' "$goroot" 1>&2
+ exit 1
+fi
+
+# Directory where cgo headers and outputs will be installed.
+# The installation directory format varies depending on the platform.
+installdir=pkg/${goos}_${goarch}_testcshared_shared
+if [ "${goos}" == "darwin" ]; then
+ installdir=pkg/${goos}_${goarch}_testcshared
+fi
+
+# Temporary directory on the android device.
+androidpath=/data/local/tmp/testcshared-$$
+
+function cleanup() {
+ rm -f libgo.$libext libgo2.$libext libgo4.$libext libgo5.$libext
+ rm -f libgo.h libgo4.h libgo5.h
+ rm -f testp testp2 testp3 testp4 testp5
+ rm -rf pkg "${goroot}/${installdir}"
+
+ if [ "$goos" == "android" ]; then
+ adb shell rm -rf "$androidpath"
+ fi
+}
+trap cleanup EXIT
+
+if [ "$goos" == "android" ]; then
+ adb shell mkdir -p "$androidpath"
+fi
+
+function run() {
+ case "$goos" in
+ "android")
+ local args=$@
+ output=$(adb shell "cd ${androidpath}; $@")
+ output=$(echo $output|tr -d '\r')
+ case $output in
+ *PASS) echo "PASS";;
+ *) echo "$output";;
+ esac
+ ;;
+ *)
+ echo $(env $@)
+ ;;
+ esac
+}
+
+function binpush() {
+ bin=${1}
+ if [ "$goos" == "android" ]; then
+ adb push "$bin" "${androidpath}/${bin}" 2>/dev/null
+ fi
+}
+
+rm -rf pkg
+
+suffix="-installsuffix testcshared"
+
+libext="so"
+if [ "$goos" == "darwin" ]; then
+ libext="dylib"
+fi
+
+# Create the header files.
+GOPATH=$(pwd) go install -buildmode=c-shared $suffix libgo
+
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.$libext src/libgo/libgo.go
+binpush libgo.$libext
+
+if [ "$goos" == "linux" ] || [ "$goos" == "android" ] ; then
+ if readelf -d libgo.$libext | grep TEXTREL >/dev/null; then
+ echo "libgo.$libext has TEXTREL set"
+ exit 1
+ fi
+fi
+
+GOGCCFLAGS=$(go env GOGCCFLAGS)
+if [ "$goos" == "android" ]; then
+ GOGCCFLAGS="${GOGCCFLAGS} -pie"
+fi
+
+status=0
+
+# test0: exported symbols in shared lib are accessible.
+# TODO(iant): using _shared here shouldn't really be necessary.
+$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c ./libgo.$libext
+binpush testp
+
+output=$(run LD_LIBRARY_PATH=. ./testp)
+if [ "$output" != "PASS" ]; then
+ echo "FAIL test0 got ${output}"
+ status=1
+fi
+
+# test1: shared library can be dynamically loaded and exported symbols are accessible.
+$(go env CC) ${GOGCCFLAGS} -o testp main1.c -ldl
+binpush testp
+output=$(run ./testp ./libgo.$libext)
+if [ "$output" != "PASS" ]; then
+ echo "FAIL test1 got ${output}"
+ status=1
+fi
+
+# test2: tests libgo2 which does not export any functions.
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.$libext libgo2
+binpush libgo2.$libext
+linkflags="-Wl,--no-as-needed"
+if [ "$goos" == "darwin" ]; then
+ linkflags=""
+fi
+$(go env CC) ${GOGCCFLAGS} -o testp2 main2.c $linkflags libgo2.$libext
+binpush testp2
+output=$(run LD_LIBRARY_PATH=. ./testp2)
+if [ "$output" != "PASS" ]; then
+ echo "FAIL test2 got ${output}"
+ status=1
+fi
+
+# test3: tests main.main is exported on android.
+if [ "$goos" == "android" ]; then
+ $(go env CC) ${GOGCCFLAGS} -o testp3 main3.c -ldl
+ binpush testp3
+ output=$(run ./testp ./libgo.so)
+ if [ "$output" != "PASS" ]; then
+ echo "FAIL test3 got ${output}"
+ status=1
+ fi
+fi
+
+# test4: tests signal handlers
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo4.$libext libgo4
+binpush libgo4.$libext
+$(go env CC) ${GOGCCFLAGS} -pthread -o testp4 main4.c -ldl
+binpush testp4
+output=$(run ./testp4 ./libgo4.$libext 2>&1)
+if test "$output" != "PASS"; then
+ echo "FAIL test4 got ${output}"
+ if test "$goos" != "android"; then
+ echo "re-running test4 in verbose mode"
+ ./testp4 ./libgo4.$libext verbose
+ fi
+ status=1
+fi
+
+# test5: tests signal handlers with os/signal.Notify
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo5.$libext libgo5
+binpush libgo5.$libext
+$(go env CC) ${GOGCCFLAGS} -pthread -o testp5 main5.c -ldl
+binpush testp5
+output=$(run ./testp5 ./libgo5.$libext 2>&1)
+if test "$output" != "PASS"; then
+ echo "FAIL test5 got ${output}"
+ if test "$goos" != "android"; then
+ echo "re-running test5 in verbose mode"
+ ./testp5 ./libgo5.$libext verbose
+ fi
+ status=1
+fi
+
+if test "$libext" = "dylib"; then
+ # make sure dylibs are well-formed
+ if ! otool -l libgo*.dylib >/dev/null; then
+ status=1
+ fi
+fi
+
+if test $status = 0; then
+ echo "ok"
+fi
+
+exit $status