re PR c++/84661 (internal compiler error: Segmentation fault (strip_array_types()))
[official-gcc.git] / libgo / runtime / go-libmain.c
blob00a8e6b1bda31c035c9912c6e3688e64a0617cb6
1 /* go-libmain.c -- the startup function for a Go library.
3 Copyright 2015 The Go Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file. */
7 #include "config.h"
9 #include <errno.h>
10 #include <pthread.h>
11 #include <stdlib.h>
12 #include <time.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
18 #include "runtime.h"
19 #include "array.h"
20 #include "arch.h"
22 #if defined(__sun) && defined(__SVR4)
24 /* Read a file into memory on Solaris, returning an malloc'ed buffer
25 and setting *SIZE to its size. */
27 static char *
28 read_file (const char *fn, size_t *size)
30 struct stat st;
31 char *buf;
32 int o;
33 ssize_t got;
35 if (stat (fn, &st) < 0)
36 return NULL;
37 buf = malloc ((size_t) st.st_size);
38 if (buf == NULL)
39 return NULL;
40 o = open (fn, O_RDONLY);
41 if (o < 0)
43 free (buf);
44 return NULL;
46 got = read (o, buf, st.st_size);
47 close (o);
48 if (got != st.st_size)
50 free (buf);
51 return NULL;
54 *size = (size_t) got;
55 return buf;
58 /* On Solaris we don't get passed argc/argv, but we can fetch it from
59 /proc/PID/cmdline. */
61 static void
62 read_cmdline (int *argc, char ***argv)
64 pid_t pid;
65 char fn[50];
66 char *argbuf;
67 size_t argsize;
68 char *envbuf;
69 size_t envsize;
70 char *p;
71 int i;
72 int ac;
74 *argc = 0;
75 *argv = NULL;
77 pid = getpid ();
78 snprintf (fn, sizeof fn, "/proc/%ld/cmdline", (long) pid);
79 argbuf = read_file (fn, &argsize);
80 if (argbuf == NULL)
81 return;
83 snprintf (fn, sizeof fn, "/proc/%ld/environ", (long) pid);
84 envbuf = read_file (fn, &envsize);
85 if (envbuf == NULL)
87 free (argbuf);
88 return;
91 i = 0;
92 for (p = argbuf; p < argbuf + argsize; p++)
93 if (*p == '\0')
94 ++i;
95 ac = i;
96 ++i; // For trailing NULL.
97 for (p = envbuf; p < envbuf + envsize; p++)
98 if (*p == '\0')
99 ++i;
100 ++i; // For trailing NULL.
102 *argv = (char **) malloc (i * sizeof (char *));
103 if (*argv == NULL)
105 free (argbuf);
106 free (envbuf);
107 return;
110 *argc = ac;
111 (*argv)[0] = argbuf;
112 i = 0;
113 for (p = argbuf; p < argbuf + argsize; p++)
115 if (*p == '\0')
117 ++i;
118 (*argv)[i] = p + 1;
121 (*argv)[i] = NULL;
122 ++i;
123 (*argv)[i] = envbuf;
124 for (p = envbuf; p < envbuf + envsize; p++)
126 if (*p == '\0')
128 ++i;
129 (*argv)[i] = p + 1;
132 (*argv)[i] = NULL;
135 #endif /* defined(__sun) && defined(__SVR4) */
137 /* This is used when building a standalone Go library using the Go
138 command's -buildmode=c-archive or -buildmode=c-shared option. It
139 starts up the Go code as a global constructor but does not take any
140 other action. The main program is written in some other language
141 and calls exported Go functions as needed. */
143 static void die (const char *, int);
144 /* .init_array section does not exist in AIX XCOFF.
145 -Wl,-binitfini:__go_init option will be required to build go
146 libraries and make sure __go_init is called when the library is
147 loaded. This requires __go_init to be exported. */
149 void __go_init (int, char **, char **);
150 static void *gostart (void *);
152 /* Used to pass arguments to the thread that runs the Go startup. */
154 struct args {
155 int argc;
156 char **argv;
159 #ifndef _AIX
160 /* We use .init_array so that we can get the command line arguments.
161 This obviously assumes .init_array support; different systems may
162 require other approaches. */
164 typedef void (*initarrayfn) (int, char **, char **);
166 static initarrayfn initarray[1]
167 __attribute__ ((section (".init_array"), used)) =
168 { __go_init };
169 #endif
171 /* This function is called at program startup time. It starts a new
172 thread to do the actual Go startup, so that program startup is not
173 paused waiting for the Go initialization functions. Exported cgo
174 functions will wait for initialization to complete if
175 necessary. */
177 void
178 __go_init (int argc, char **argv, char** env __attribute__ ((unused)))
180 int err;
181 pthread_attr_t attr;
182 struct args *a;
183 pthread_t tid;
185 #if defined(__sun) && defined(__SVR4)
186 read_cmdline (&argc, &argv);
187 #endif
189 runtime_isarchive = true;
191 setIsCgo ();
192 runtime_cpuinit ();
193 runtime_initsig(true);
195 a = (struct args *) malloc (sizeof *a);
196 if (a == NULL)
197 die ("malloc", errno);
198 a->argc = argc;
199 a->argv = argv;
201 err = pthread_attr_init (&attr);
202 if (err != 0)
203 die ("pthread_attr_init", err);
204 err = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
205 if (err != 0)
206 die ("pthread_attr_setdetachstate", err);
208 err = pthread_create (&tid, &attr, gostart, (void *) a);
209 if (err != 0)
210 die ("pthread_create", err);
212 err = pthread_attr_destroy (&attr);
213 if (err != 0)
214 die ("pthread_attr_destroy", err);
217 /* Start up the Go runtime. */
219 static void *
220 gostart (void *arg)
222 struct args *a = (struct args *) arg;
224 if (runtime_isstarted)
225 return NULL;
226 runtime_isstarted = true;
228 runtime_check ();
229 runtime_args (a->argc, (byte **) a->argv);
230 setncpu (getproccount ());
231 setpagesize (getpagesize ());
232 runtime_sched = runtime_getsched();
233 runtime_schedinit ();
234 __go_go ((uintptr)(runtime_main), NULL);
235 runtime_mstart (runtime_m ());
236 abort ();
239 /* If something goes wrong during program startup, crash. There is no
240 way to report failure and nobody to whom to report it. */
242 static void
243 die (const char *fn, int err)
245 fprintf (stderr, "%s: %d\n", fn, err);
246 exit (EXIT_FAILURE);