summaryrefslogtreecommitdiffstats
path: root/misc/cgo/testcarchive/testdata
diff options
context:
space:
mode:
Diffstat (limited to 'misc/cgo/testcarchive/testdata')
-rw-r--r--misc/cgo/testcarchive/testdata/libgo/libgo.go53
-rw-r--r--misc/cgo/testcarchive/testdata/libgo2/libgo2.go86
-rw-r--r--misc/cgo/testcarchive/testdata/libgo3/libgo3.go56
-rw-r--r--misc/cgo/testcarchive/testdata/libgo4/libgo4.go52
-rw-r--r--misc/cgo/testcarchive/testdata/libgo6/sigprof.go25
-rw-r--r--misc/cgo/testcarchive/testdata/libgo7/sink.go17
-rw-r--r--misc/cgo/testcarchive/testdata/libgo8/a.go36
-rw-r--r--misc/cgo/testcarchive/testdata/main.c48
-rw-r--r--misc/cgo/testcarchive/testdata/main2.c239
-rw-r--r--misc/cgo/testcarchive/testdata/main3.c210
-rw-r--r--misc/cgo/testcarchive/testdata/main4.c204
-rw-r--r--misc/cgo/testcarchive/testdata/main5.c105
-rw-r--r--misc/cgo/testcarchive/testdata/main6.c34
-rw-r--r--misc/cgo/testcarchive/testdata/main7.c18
-rw-r--r--misc/cgo/testcarchive/testdata/main8.c16
-rw-r--r--misc/cgo/testcarchive/testdata/main_unix.c59
-rw-r--r--misc/cgo/testcarchive/testdata/main_windows.c17
-rw-r--r--misc/cgo/testcarchive/testdata/p/p.go10
18 files changed, 1285 insertions, 0 deletions
diff --git a/misc/cgo/testcarchive/testdata/libgo/libgo.go b/misc/cgo/testcarchive/testdata/libgo/libgo.go
new file mode 100644
index 0000000..37b30c1
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/libgo/libgo.go
@@ -0,0 +1,53 @@
+// 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 (
+ "fmt"
+ "os"
+ "syscall"
+ "time"
+
+ _ "testcarchive/p"
+)
+
+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 }
+
+//export CheckArgs
+func CheckArgs() {
+ if len(os.Args) != 3 || os.Args[1] != "arg1" || os.Args[2] != "arg2" {
+ fmt.Printf("CheckArgs: want [_, arg1, arg2], got: %v\n", os.Args)
+ os.Exit(2)
+ }
+}
diff --git a/misc/cgo/testcarchive/testdata/libgo2/libgo2.go b/misc/cgo/testcarchive/testdata/libgo2/libgo2.go
new file mode 100644
index 0000000..35c89ae
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/libgo2/libgo2.go
@@ -0,0 +1,86 @@
+// 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
+
+/*
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+// Raise SIGPIPE.
+static void CRaiseSIGPIPE() {
+ int fds[2];
+
+ if (pipe(fds) == -1) {
+ perror("pipe");
+ exit(EXIT_FAILURE);
+ }
+ // Close the reader end
+ close(fds[0]);
+ // Write to the writer end to provoke a SIGPIPE
+ if (write(fds[1], "some data", 9) != -1) {
+ fprintf(stderr, "write to a closed pipe succeeded\n");
+ exit(EXIT_FAILURE);
+ }
+ close(fds[1]);
+}
+*/
+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 {}
+ }()
+ }
+}
+
+// Block blocks the current thread while running Go code.
+//export Block
+func Block() {
+ 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)
+}
+
+// Noop ensures that the Go runtime is initialized.
+//export Noop
+func Noop() {
+}
+
+// Raise SIGPIPE.
+//export GoRaiseSIGPIPE
+func GoRaiseSIGPIPE() {
+ C.CRaiseSIGPIPE()
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcarchive/testdata/libgo3/libgo3.go b/misc/cgo/testcarchive/testdata/libgo3/libgo3.go
new file mode 100644
index 0000000..3725f7a
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/libgo3/libgo3.go
@@ -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.
+
+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 reports whether we saw a SIGIO.
+//export SawSIGIO
+func SawSIGIO() C.int {
+ select {
+ case <-sigioChan:
+ return 1
+ case <-time.After(5 * time.Second):
+ return 0
+ }
+}
+
+// ProvokeSIGPIPE provokes a kernel-initiated SIGPIPE.
+//export ProvokeSIGPIPE
+func ProvokeSIGPIPE() {
+ r, w, err := os.Pipe()
+ if err != nil {
+ panic(err)
+ }
+ r.Close()
+ defer w.Close()
+ w.Write([]byte("some data"))
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcarchive/testdata/libgo4/libgo4.go b/misc/cgo/testcarchive/testdata/libgo4/libgo4.go
new file mode 100644
index 0000000..8cc1895
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/libgo4/libgo4.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.
+
+package main
+
+/*
+#include <signal.h>
+#include <pthread.h>
+
+// Raise SIGIO.
+static void CRaiseSIGIO(pthread_t* p) {
+ pthread_kill(*p, SIGIO);
+}
+*/
+import "C"
+
+import (
+ "os"
+ "os/signal"
+ "sync/atomic"
+ "syscall"
+)
+
+var sigioCount int32
+
+// Catch SIGIO.
+//export GoCatchSIGIO
+func GoCatchSIGIO() {
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, syscall.SIGIO)
+ go func() {
+ for range c {
+ atomic.AddInt32(&sigioCount, 1)
+ }
+ }()
+}
+
+// Raise SIGIO.
+//export GoRaiseSIGIO
+func GoRaiseSIGIO(p *C.pthread_t) {
+ C.CRaiseSIGIO(p)
+}
+
+// Return the number of SIGIO signals seen.
+//export SIGIOCount
+func SIGIOCount() C.int {
+ return C.int(atomic.LoadInt32(&sigioCount))
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcarchive/testdata/libgo6/sigprof.go b/misc/cgo/testcarchive/testdata/libgo6/sigprof.go
new file mode 100644
index 0000000..31527c5
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/libgo6/sigprof.go
@@ -0,0 +1,25 @@
+// Copyright 2016 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 (
+ "io"
+ "runtime/pprof"
+)
+
+import "C"
+
+//export go_start_profile
+func go_start_profile() {
+ pprof.StartCPUProfile(io.Discard)
+}
+
+//export go_stop_profile
+func go_stop_profile() {
+ pprof.StopCPUProfile()
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcarchive/testdata/libgo7/sink.go b/misc/cgo/testcarchive/testdata/libgo7/sink.go
new file mode 100644
index 0000000..d61638b
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/libgo7/sink.go
@@ -0,0 +1,17 @@
+// Copyright 2019 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"
+
+var sink []byte
+
+//export GoFunction7
+func GoFunction7() {
+ sink = make([]byte, 4096)
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcarchive/testdata/libgo8/a.go b/misc/cgo/testcarchive/testdata/libgo8/a.go
new file mode 100644
index 0000000..718418e
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/libgo8/a.go
@@ -0,0 +1,36 @@
+// Copyright 2021 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"
+ "runtime"
+ "sync/atomic"
+)
+
+var started int32
+
+// Start a goroutine that loops forever.
+func init() {
+ runtime.GOMAXPROCS(1)
+ go func() {
+ for {
+ atomic.StoreInt32(&started, 1)
+ }
+ }()
+}
+
+//export GoFunction8
+func GoFunction8() {
+ for atomic.LoadInt32(&started) == 0 {
+ runtime.Gosched()
+ }
+ os.Exit(0)
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcarchive/testdata/main.c b/misc/cgo/testcarchive/testdata/main.c
new file mode 100644
index 0000000..163b539
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main.c
@@ -0,0 +1,48 @@
+// 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 <string.h>
+
+#include "p.h"
+#include "libgo.h"
+
+extern int install_handler();
+extern int check_handler();
+
+int main(void) {
+ int32_t res;
+
+ int r1 = install_handler();
+ if (r1!=0) {
+ return r1;
+ }
+
+ if (!DidInitRun()) {
+ fprintf(stderr, "ERROR: buildmode=c-archive init should run\n");
+ return 2;
+ }
+
+ if (DidMainRun()) {
+ fprintf(stderr, "ERROR: buildmode=c-archive should not run main\n");
+ return 2;
+ }
+
+ int r2 = check_handler();
+ if (r2!=0) {
+ return r2;
+ }
+
+ res = FromPkg();
+ if (res != 1024) {
+ fprintf(stderr, "ERROR: FromPkg()=%d, want 1024\n", res);
+ return 2;
+ }
+
+ CheckArgs();
+
+ fprintf(stderr, "PASS\n");
+ return 0;
+}
diff --git a/misc/cgo/testcarchive/testdata/main2.c b/misc/cgo/testcarchive/testdata/main2.c
new file mode 100644
index 0000000..da35673
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main2.c
@@ -0,0 +1,239 @@
+// 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 installing a signal handler before the Go code starts.
+// This is a lot like misc/cgo/testcshared/main4.c.
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sched.h>
+#include <time.h>
+#include <errno.h>
+
+#include "libgo2.h"
+
+static void die(const char* msg) {
+ perror(msg);
+ exit(EXIT_FAILURE);
+}
+
+static volatile sig_atomic_t sigioSeen;
+static volatile sig_atomic_t sigpipeSeen;
+
+// Use up some stack space.
+static void recur(int i, char *p) {
+ char a[1024];
+
+ *p = '\0';
+ if (i > 0) {
+ recur(i - 1, a);
+ }
+}
+
+static void pipeHandler(int signo, siginfo_t* info, void* ctxt) {
+ sigpipeSeen = 1;
+}
+
+// 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;
+
+// An arbitrary function which requires proper stack alignment; see
+// http://golang.org/issue/17641.
+static void callWithVarargs(void* dummy, ...) {
+ va_list args;
+ va_start(args, dummy);
+ va_end(args);
+}
+
+// Signal handler for SIGSEGV on a C thread.
+static void segvHandler(int signo, siginfo_t* info, void* ctxt) {
+ sigset_t mask;
+ int i;
+
+ // Call an arbitrary function that requires the stack to be properly aligned.
+ callWithVarargs("dummy arg", 3.1415);
+
+ 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();
+}
+
+// Set up the signal handlers in a high priority constructor,
+// so that they are installed before the Go code starts.
+
+static void init(void) __attribute__ ((constructor (200)));
+
+static void init() {
+ struct sigaction sa;
+
+ 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");
+ }
+
+ sa.sa_sigaction = pipeHandler;
+ if (sigaction(SIGPIPE, &sa, NULL) < 0) {
+ die("sigaction");
+ }
+}
+
+int main(int argc, char** argv) {
+ int verbose;
+ sigset_t mask;
+ int i;
+ struct timespec ts;
+ int darwin;
+
+ darwin = atoi(argv[1]);
+
+ 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 RunGoroutines\n");
+ }
+
+ RunGoroutines();
+
+ // 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 SIGIO\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (verbose) {
+ printf("provoking SIGPIPE\n");
+ }
+
+ // SIGPIPE is never forwarded on Darwin, see golang.org/issue/33384.
+ if (!darwin) {
+ GoRaiseSIGPIPE();
+
+ if (verbose) {
+ printf("waiting for sigpipeSeen\n");
+ }
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (!sigpipeSeen) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ i++;
+ if (i > 5000) {
+ fprintf(stderr, "looping too long waiting for SIGPIPE\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 TestSEGV\n");
+ }
+
+ TestSEGV();
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/misc/cgo/testcarchive/testdata/main3.c b/misc/cgo/testcarchive/testdata/main3.c
new file mode 100644
index 0000000..4d11d9c
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main3.c
@@ -0,0 +1,210 @@
+// 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 os/signal.Notify and os/signal.Reset.
+// This is a lot like misc/cgo/testcshared/main5.c.
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sched.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "libgo3.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;
+}
+
+// Set up the SIGPIPE signal handler in a high priority constructor, so
+// that it is installed before the Go code starts.
+
+static void pipeHandler(int signo, siginfo_t* info, void* ctxt) {
+ const char *s = "unexpected SIGPIPE\n";
+ write(2, s, strlen(s));
+ exit(EXIT_FAILURE);
+}
+
+static void init(void) __attribute__ ((constructor (200)));
+
+static void init() {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_sigaction = pipeHandler;
+ if (sigemptyset(&sa.sa_mask) < 0) {
+ die("sigemptyset");
+ }
+ sa.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGPIPE, &sa, NULL) < 0) {
+ die("sigaction");
+ }
+}
+
+static void *provokeSIGPIPE(void *arg) {
+ ProvokeSIGPIPE();
+ return NULL;
+}
+
+int main(int argc, char** argv) {
+ int verbose;
+ struct sigaction sa;
+ int i;
+ struct timespec ts;
+ int res;
+ pthread_t tid;
+
+ verbose = argc > 2;
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ if (verbose) {
+ printf("raising SIGPIPE\n");
+ }
+
+ // Test that the Go runtime handles SIGPIPE, even if we installed
+ // a non-default SIGPIPE handler before the runtime initializes.
+ ProvokeSIGPIPE();
+
+ // Test that SIGPIPE on a non-main thread is also handled by Go.
+ res = pthread_create(&tid, NULL, provokeSIGPIPE, NULL);
+ if (res != 0) {
+ fprintf(stderr, "pthread_create: %s\n", strerror(res));
+ exit(EXIT_FAILURE);
+ }
+
+ res = pthread_join(tid, NULL);
+ if (res != 0) {
+ fprintf(stderr, "pthread_join: %s\n", strerror(res));
+ exit(EXIT_FAILURE);
+ }
+
+ 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");
+ }
+
+ // 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 CatchSIGIO\n");
+ }
+
+ CatchSIGIO();
+
+ if (verbose) {
+ printf("raising SIGIO\n");
+ }
+
+ if (raise(SIGIO) < 0) {
+ die("raise");
+ }
+
+ 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 ResetSIGIO\n");
+ }
+
+ ResetSIGIO();
+
+ 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/misc/cgo/testcarchive/testdata/main4.c b/misc/cgo/testcarchive/testdata/main4.c
new file mode 100644
index 0000000..04f7740
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main4.c
@@ -0,0 +1,204 @@
+// 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 a C thread that calls sigaltstack and then calls Go code.
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sched.h>
+#include <pthread.h>
+
+#include "libgo4.h"
+
+#ifdef _AIX
+// On AIX, CSIGSTKSZ is too small to handle Go sighandler.
+#define CSIGSTKSZ 0x4000
+#else
+#define CSIGSTKSZ SIGSTKSZ
+#endif
+
+static void die(const char* msg) {
+ perror(msg);
+ exit(EXIT_FAILURE);
+}
+
+static int ok = 1;
+
+static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
+}
+
+// Set up the SIGIO signal handler in a high priority constructor, so
+// that it is installed before the Go code starts.
+
+static void init(void) __attribute__ ((constructor (200)));
+
+static void init() {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_sigaction = ioHandler;
+ if (sigemptyset(&sa.sa_mask) < 0) {
+ die("sigemptyset");
+ }
+ sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
+ if (sigaction(SIGIO, &sa, NULL) < 0) {
+ die("sigaction");
+ }
+}
+
+// Test raising SIGIO on a C thread with an alternate signal stack
+// when there is a Go signal handler for SIGIO.
+static void* thread1(void* arg __attribute__ ((unused))) {
+ stack_t ss;
+ int i;
+ stack_t nss;
+ struct timespec ts;
+
+ // Set up an alternate signal stack for this thread.
+ memset(&ss, 0, sizeof ss);
+ ss.ss_sp = malloc(CSIGSTKSZ);
+ if (ss.ss_sp == NULL) {
+ die("malloc");
+ }
+ ss.ss_flags = 0;
+ ss.ss_size = CSIGSTKSZ;
+ if (sigaltstack(&ss, NULL) < 0) {
+ die("sigaltstack");
+ }
+
+ // Send ourselves a SIGIO. This will be caught by the Go
+ // signal handler which should forward to the C signal
+ // handler.
+ i = pthread_kill(pthread_self(), SIGIO);
+ if (i != 0) {
+ fprintf(stderr, "pthread_kill: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (SIGIOCount() == 0) {
+ 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);
+ }
+ }
+
+ // We should still be on the same signal stack.
+ if (sigaltstack(NULL, &nss) < 0) {
+ die("sigaltstack check");
+ }
+ if ((nss.ss_flags & SS_DISABLE) != 0) {
+ fprintf(stderr, "sigaltstack disabled on return from Go\n");
+ ok = 0;
+ } else if (nss.ss_sp != ss.ss_sp) {
+ fprintf(stderr, "sigaltstack changed on return from Go\n");
+ ok = 0;
+ }
+
+ return NULL;
+}
+
+// Test calling a Go function to raise SIGIO on a C thread with an
+// alternate signal stack when there is a Go signal handler for SIGIO.
+static void* thread2(void* arg __attribute__ ((unused))) {
+ stack_t ss;
+ int i;
+ int oldcount;
+ pthread_t tid;
+ struct timespec ts;
+ stack_t nss;
+
+ // Set up an alternate signal stack for this thread.
+ memset(&ss, 0, sizeof ss);
+ ss.ss_sp = malloc(CSIGSTKSZ);
+ if (ss.ss_sp == NULL) {
+ die("malloc");
+ }
+ ss.ss_flags = 0;
+ ss.ss_size = CSIGSTKSZ;
+ if (sigaltstack(&ss, NULL) < 0) {
+ die("sigaltstack");
+ }
+
+ oldcount = SIGIOCount();
+
+ // Call a Go function that will call a C function to send us a
+ // SIGIO.
+ tid = pthread_self();
+ GoRaiseSIGIO(&tid);
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (SIGIOCount() == oldcount) {
+ 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);
+ }
+ }
+
+ // We should still be on the same signal stack.
+ if (sigaltstack(NULL, &nss) < 0) {
+ die("sigaltstack check");
+ }
+ if ((nss.ss_flags & SS_DISABLE) != 0) {
+ fprintf(stderr, "sigaltstack disabled on return from Go\n");
+ ok = 0;
+ } else if (nss.ss_sp != ss.ss_sp) {
+ fprintf(stderr, "sigaltstack changed on return from Go\n");
+ ok = 0;
+ }
+
+ return NULL;
+}
+
+int main(int argc, char **argv) {
+ pthread_t tid;
+ int i;
+
+ // Tell the Go library to start looking for SIGIO.
+ GoCatchSIGIO();
+
+ i = pthread_create(&tid, NULL, thread1, NULL);
+ if (i != 0) {
+ fprintf(stderr, "pthread_create: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ i = pthread_join(tid, NULL);
+ if (i != 0) {
+ fprintf(stderr, "pthread_join: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ i = pthread_create(&tid, NULL, thread2, NULL);
+ if (i != 0) {
+ fprintf(stderr, "pthread_create: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ i = pthread_join(tid, NULL);
+ if (i != 0) {
+ fprintf(stderr, "pthread_join: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ if (!ok) {
+ exit(EXIT_FAILURE);
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/misc/cgo/testcarchive/testdata/main5.c b/misc/cgo/testcarchive/testdata/main5.c
new file mode 100644
index 0000000..c64c246
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main5.c
@@ -0,0 +1,105 @@
+// 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 for verifying that the Go runtime properly forwards
+// signals when non-Go signals are raised.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/select.h>
+
+#include "libgo2.h"
+
+int *nilp;
+
+int main(int argc, char** argv) {
+ int verbose;
+ int test;
+
+ if (argc < 2) {
+ printf("Missing argument\n");
+ return 1;
+ }
+
+ test = atoi(argv[1]);
+
+ verbose = (argc > 2);
+
+ Noop();
+
+ switch (test) {
+ case 1: {
+ if (verbose) {
+ printf("attempting segfault\n");
+ }
+
+ *nilp = 0;
+ break;
+ }
+
+ case 2: {
+ struct timeval tv;
+
+ if (verbose) {
+ printf("attempting external signal test\n");
+ }
+
+ fprintf(stderr, "OK\n");
+ fflush(stderr);
+
+ // The program should be interrupted before
+ // this sleep finishes. We use select rather
+ // than sleep because in older versions of
+ // glibc the sleep function does some signal
+ // fiddling to handle SIGCHLD. If this
+ // program is fiddling signals just when the
+ // test program sends the signal, the signal
+ // may be delivered to a Go thread which will
+ // break this test.
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ select(0, NULL, NULL, NULL, &tv);
+
+ break;
+ }
+ case 3: {
+ if (verbose) {
+ printf("attempting SIGPIPE\n");
+ }
+
+ int fd[2];
+ if (pipe(fd) != 0) {
+ printf("pipe(2) failed\n");
+ return 0;
+ }
+ // Close the reading end.
+ close(fd[0]);
+ // Expect that write(2) fails (EPIPE)
+ if (write(fd[1], "some data", 9) != -1) {
+ printf("write(2) unexpectedly succeeded\n");
+ return 0;
+ }
+ printf("did not receive SIGPIPE\n");
+ return 0;
+ }
+ case 4: {
+ fprintf(stderr, "OK\n");
+ fflush(stderr);
+
+ if (verbose) {
+ printf("calling Block\n");
+ }
+ Block();
+ }
+ default:
+ printf("Unknown test: %d\n", test);
+ return 0;
+ }
+
+ printf("FAIL\n");
+ return 0;
+}
diff --git a/misc/cgo/testcarchive/testdata/main6.c b/misc/cgo/testcarchive/testdata/main6.c
new file mode 100644
index 0000000..2745eb9
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main6.c
@@ -0,0 +1,34 @@
+// Copyright 2016 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 using the Go profiler in a C program does not crash.
+
+#include <stddef.h>
+#include <sys/time.h>
+
+#include "libgo6.h"
+
+int main(int argc, char **argv) {
+ struct timeval tvstart, tvnow;
+ int diff;
+
+ gettimeofday(&tvstart, NULL);
+
+ go_start_profile();
+
+ // Busy wait so we have something to profile.
+ // If we just sleep the profiling signal will never fire.
+ while (1) {
+ gettimeofday(&tvnow, NULL);
+ diff = (tvnow.tv_sec - tvstart.tv_sec) * 1000 * 1000 + (tvnow.tv_usec - tvstart.tv_usec);
+
+ // Profile frequency is 100Hz so we should definitely
+ // get a signal in 50 milliseconds.
+ if (diff > 50 * 1000)
+ break;
+ }
+
+ go_stop_profile();
+ return 0;
+}
diff --git a/misc/cgo/testcarchive/testdata/main7.c b/misc/cgo/testcarchive/testdata/main7.c
new file mode 100644
index 0000000..2c6d98d
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main7.c
@@ -0,0 +1,18 @@
+// Copyright 2019 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 lots of calls don't deadlock.
+
+#include <stdio.h>
+
+#include "libgo7.h"
+
+int main() {
+ int i;
+
+ for (i = 0; i < 100000; i++) {
+ GoFunction7();
+ }
+ return 0;
+}
diff --git a/misc/cgo/testcarchive/testdata/main8.c b/misc/cgo/testcarchive/testdata/main8.c
new file mode 100644
index 0000000..95fb7a3
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main8.c
@@ -0,0 +1,16 @@
+// Copyright 2021 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 preemption.
+
+#include <stdlib.h>
+
+#include "libgo8.h"
+
+int main() {
+ GoFunction8();
+
+ // That should have exited the program.
+ abort();
+}
diff --git a/misc/cgo/testcarchive/testdata/main_unix.c b/misc/cgo/testcarchive/testdata/main_unix.c
new file mode 100644
index 0000000..bd00f9d
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main_unix.c
@@ -0,0 +1,59 @@
+// 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 <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct sigaction sa;
+struct sigaction osa;
+
+static void (*oldHandler)(int, siginfo_t*, void*);
+
+static void handler(int signo, siginfo_t* info, void* ctxt) {
+ if (oldHandler) {
+ oldHandler(signo, info, ctxt);
+ }
+}
+
+int install_handler() {
+ // Install our own signal handler.
+ memset(&sa, 0, sizeof sa);
+ sa.sa_sigaction = handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
+ memset(&osa, 0, sizeof osa);
+ sigemptyset(&osa.sa_mask);
+ if (sigaction(SIGSEGV, &sa, &osa) < 0) {
+ perror("sigaction");
+ return 2;
+ }
+ if (osa.sa_handler == SIG_DFL) {
+ fprintf(stderr, "Go runtime did not install signal handler\n");
+ return 2;
+ }
+ // gccgo does not set SA_ONSTACK for SIGSEGV.
+ if (getenv("GCCGO") == NULL && (osa.sa_flags&SA_ONSTACK) == 0) {
+ fprintf(stderr, "Go runtime did not install signal handler\n");
+ return 2;
+ }
+ oldHandler = osa.sa_sigaction;
+
+ return 0;
+}
+
+int check_handler() {
+ if (sigaction(SIGSEGV, NULL, &sa) < 0) {
+ perror("sigaction check");
+ return 2;
+ }
+ if (sa.sa_sigaction != handler) {
+ fprintf(stderr, "ERROR: wrong signal handler: %p != %p\n", sa.sa_sigaction, handler);
+ return 2;
+ }
+ return 0;
+}
+
diff --git a/misc/cgo/testcarchive/testdata/main_windows.c b/misc/cgo/testcarchive/testdata/main_windows.c
new file mode 100644
index 0000000..eded8af
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main_windows.c
@@ -0,0 +1,17 @@
+// 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.
+
+/*
+ * Dummy implementations for Windows, because Windows doesn't
+ * support Unix-style signal handling.
+ */
+
+int install_handler() {
+ return 0;
+}
+
+
+int check_handler() {
+ return 0;
+}
diff --git a/misc/cgo/testcarchive/testdata/p/p.go b/misc/cgo/testcarchive/testdata/p/p.go
new file mode 100644
index 0000000..82b445c
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/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 }