| /* go-libmain.c -- the startup function for a Go library. |
| |
| 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 "config.h" |
| |
| #include <errno.h> |
| #include <pthread.h> |
| #include <stdlib.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include "runtime.h" |
| #include "array.h" |
| #include "arch.h" |
| |
| /* This is used when building a standalone Go library using the Go |
| command's -buildmode=c-archive or -buildmode=c-shared option. It |
| starts up the Go code as a global constructor but does not take any |
| other action. The main program is written in some other language |
| and calls exported Go functions as needed. */ |
| |
| static void die (const char *, int); |
| /* .init_array section does not exist in AIX XCOFF. |
| -Wl,-binitfini:__go_init option will be required to build go |
| libraries and make sure __go_init is called when the library is |
| loaded. This requires __go_init to be exported. */ |
| |
| void __go_init (int, char **, char **); |
| static void *gostart (void *); |
| |
| /* Used to pass arguments to the thread that runs the Go startup. */ |
| |
| struct args { |
| int argc; |
| char **argv; |
| }; |
| |
| #ifndef _AIX |
| /* We use .init_array so that we can get the command line arguments. |
| This obviously assumes .init_array support; different systems may |
| require other approaches. */ |
| |
| typedef void (*initarrayfn) (int, char **, char **); |
| |
| static initarrayfn initarray[1] |
| __attribute__ ((section (".init_array"), used)) = |
| { __go_init }; |
| #endif |
| |
| /* This function is called at program startup time. It starts a new |
| thread to do the actual Go startup, so that program startup is not |
| paused waiting for the Go initialization functions. Exported cgo |
| functions will wait for initialization to complete if |
| necessary. */ |
| |
| void |
| __go_init (int argc, char **argv, char** env __attribute__ ((unused))) |
| { |
| int err; |
| pthread_attr_t attr; |
| struct args *a; |
| pthread_t tid; |
| |
| runtime_isarchive = true; |
| |
| setIsCgo (); |
| runtime_cpuinit (); |
| runtime_initsig(true); |
| |
| a = (struct args *) malloc (sizeof *a); |
| if (a == NULL) |
| die ("malloc", errno); |
| a->argc = argc; |
| a->argv = argv; |
| |
| err = pthread_attr_init (&attr); |
| if (err != 0) |
| die ("pthread_attr_init", err); |
| err = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); |
| if (err != 0) |
| die ("pthread_attr_setdetachstate", err); |
| |
| err = pthread_create (&tid, &attr, gostart, (void *) a); |
| if (err != 0) |
| die ("pthread_create", err); |
| |
| err = pthread_attr_destroy (&attr); |
| if (err != 0) |
| die ("pthread_attr_destroy", err); |
| } |
| |
| /* Start up the Go runtime. */ |
| |
| static void * |
| gostart (void *arg) |
| { |
| struct args *a = (struct args *) arg; |
| |
| if (runtime_isstarted) |
| return NULL; |
| runtime_isstarted = true; |
| |
| runtime_check (); |
| runtime_args (a->argc, (byte **) a->argv); |
| setncpu (getproccount ()); |
| setpagesize (getpagesize ()); |
| runtime_sched = runtime_getsched(); |
| runtime_schedinit (); |
| __go_go (runtime_main, NULL); |
| runtime_mstart (runtime_m ()); |
| abort (); |
| } |
| |
| /* If something goes wrong during program startup, crash. There is no |
| way to report failure and nobody to whom to report it. */ |
| |
| static void |
| die (const char *fn, int err) |
| { |
| fprintf (stderr, "%s: %d\n", fn, err); |
| exit (EXIT_FAILURE); |
| } |