github.com/golang/gofrontend@v0.0.0-20240429183944-60f985a78526/libgo/runtime/go-libmain.c (about) 1 /* go-libmain.c -- the startup function for a Go library. 2 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. */ 6 7 #include "config.h" 8 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> 17 18 #include "runtime.h" 19 #include "array.h" 20 #include "arch.h" 21 22 #if defined(__sun) && defined(__SVR4) 23 24 /* Read a file into memory on Solaris, returning an malloc'ed buffer 25 and setting *SIZE to its size. */ 26 27 static char * 28 read_file (const char *fn, size_t *size) 29 { 30 struct stat st; 31 char *buf; 32 int o; 33 ssize_t got; 34 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) 42 { 43 free (buf); 44 return NULL; 45 } 46 got = read (o, buf, st.st_size); 47 close (o); 48 if (got != st.st_size) 49 { 50 free (buf); 51 return NULL; 52 } 53 54 *size = (size_t) got; 55 return buf; 56 } 57 58 /* On Solaris we don't get passed argc/argv, but we can fetch it from 59 /proc/PID/cmdline. */ 60 61 static void 62 read_cmdline (int *argc, char ***argv) 63 { 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; 73 74 *argc = 0; 75 *argv = NULL; 76 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; 82 83 snprintf (fn, sizeof fn, "/proc/%ld/environ", (long) pid); 84 envbuf = read_file (fn, &envsize); 85 if (envbuf == NULL) 86 { 87 free (argbuf); 88 return; 89 } 90 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. 101 102 *argv = (char **) malloc (i * sizeof (char *)); 103 if (*argv == NULL) 104 { 105 free (argbuf); 106 free (envbuf); 107 return; 108 } 109 110 *argc = ac; 111 (*argv)[0] = argbuf; 112 i = 0; 113 for (p = argbuf; p < argbuf + argsize; p++) 114 { 115 if (*p == '\0') 116 { 117 ++i; 118 (*argv)[i] = p + 1; 119 } 120 } 121 (*argv)[i] = NULL; 122 ++i; 123 (*argv)[i] = envbuf; 124 for (p = envbuf; p < envbuf + envsize; p++) 125 { 126 if (*p == '\0') 127 { 128 ++i; 129 (*argv)[i] = p + 1; 130 } 131 } 132 (*argv)[i] = NULL; 133 } 134 135 #endif /* defined(__sun) && defined(__SVR4) */ 136 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. */ 142 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. */ 148 149 void __go_init (int, char **, char **); 150 static void *gostart (void *); 151 152 /* Used to pass arguments to the thread that runs the Go startup. */ 153 154 struct args { 155 int argc; 156 char **argv; 157 }; 158 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. */ 163 164 typedef void (*initarrayfn) (int, char **, char **); 165 166 static initarrayfn initarray[1] 167 __attribute__ ((section (".init_array"), used)) = 168 { __go_init }; 169 #endif 170 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. */ 176 177 void 178 __go_init (int argc, char **argv, char** env __attribute__ ((unused))) 179 { 180 int err; 181 pthread_attr_t attr; 182 struct args *a; 183 pthread_t tid; 184 185 #if defined(__sun) && defined(__SVR4) 186 read_cmdline (&argc, &argv); 187 #endif 188 189 runtime_isarchive = true; 190 191 setIsCgo (); 192 runtime_cpuinit (); 193 runtime_initsig(true); 194 195 a = (struct args *) malloc (sizeof *a); 196 if (a == NULL) 197 die ("malloc", errno); 198 a->argc = argc; 199 a->argv = argv; 200 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); 207 208 err = pthread_create (&tid, &attr, gostart, (void *) a); 209 if (err != 0) 210 die ("pthread_create", err); 211 212 err = pthread_attr_destroy (&attr); 213 if (err != 0) 214 die ("pthread_attr_destroy", err); 215 } 216 217 /* Start up the Go runtime. */ 218 219 static void * 220 gostart (void *arg) 221 { 222 struct args *a = (struct args *) arg; 223 224 if (runtime_isstarted) 225 return NULL; 226 runtime_isstarted = true; 227 228 runtime_ginit (); 229 runtime_check (); 230 runtime_args (a->argc, (byte **) a->argv); 231 runtime_osinit (); 232 runtime_schedinit (); 233 __go_go ((uintptr)(runtime_main), NULL); 234 runtime_mstart (runtime_m ()); 235 abort (); 236 } 237 238 /* If something goes wrong during program startup, crash. There is no 239 way to report failure and nobody to whom to report it. */ 240 241 static void 242 die (const char *fn, int err) 243 { 244 fprintf (stderr, "%s: %d\n", fn, err); 245 exit (EXIT_FAILURE); 246 }