github.com/freddyisaac/sicortex-golang@v0.0.0-20231019035217-e03519e66f60/src/runtime/cgo/gcc_openbsd_386.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include <sys/types.h>
     6  #include <dlfcn.h>
     7  #include <errno.h>
     8  #include <pthread.h>
     9  #include <signal.h>
    10  #include <string.h>
    11  #include "libcgo.h"
    12  #include "libcgo_unix.h"
    13  
    14  static void* threadentry(void*);
    15  static void (*setg_gcc)(void*);
    16  
    17  // TCB_SIZE is sizeof(struct thread_control_block), as defined in
    18  // /usr/src/lib/librthread/tcb.h on OpenBSD 5.9 and earlier.
    19  #define TCB_SIZE (4 * sizeof(void *))
    20  
    21  // TIB_SIZE is sizeof(struct tib), as defined in
    22  // /usr/include/tib.h on OpenBSD 6.0 and later.
    23  #define TIB_SIZE (4 * sizeof(void *) + 6 * sizeof(int))
    24  
    25  // TLS_SIZE is the size of TLS needed for Go.
    26  #define TLS_SIZE (2 * sizeof(void *))
    27  
    28  void *__get_tcb(void);
    29  void __set_tcb(void *);
    30  
    31  static int (*sys_pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
    32  	void *(*start_routine)(void *), void *arg);
    33  
    34  struct thread_args {
    35  	void *(*func)(void *);
    36  	void *arg;
    37  };
    38  
    39  static int has_tib = 0;
    40  
    41  static void
    42  tcb_fixup(int mainthread)
    43  {
    44  	void *tls, *newtcb, *oldtcb;
    45  	size_t tls_size, tcb_size;
    46  
    47  	// TODO(jsing): Remove once OpenBSD 6.1 is released and OpenBSD 5.9 is
    48  	// no longer supported.
    49  
    50  	// The OpenBSD ld.so(1) does not currently support PT_TLS. As a result,
    51  	// we need to allocate our own TLS space while preserving the existing
    52  	// TCB or TIB that has been setup via librthread.
    53  
    54  	tcb_size = has_tib ? TIB_SIZE : TCB_SIZE;
    55  	tls_size = TLS_SIZE + tcb_size;
    56  	tls = malloc(tls_size);
    57  	if(tls == NULL)
    58  		abort();
    59  
    60  	// The signal trampoline expects the TLS slots to be zeroed.
    61  	bzero(tls, TLS_SIZE);
    62  
    63  	oldtcb = __get_tcb();
    64  	newtcb = tls + TLS_SIZE;
    65  	bcopy(oldtcb, newtcb, tcb_size);
    66  	if(has_tib) {
    67  		 // Fix up self pointer.
    68  		*(uintptr_t *)(newtcb) = (uintptr_t)newtcb;
    69  	}
    70  	__set_tcb(newtcb);
    71  
    72  	// NOTE(jsing, minux): we can't free oldtcb without causing double-free
    73  	// problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
    74  	// has proper support for PT_TLS.
    75  }
    76  
    77  static void *
    78  thread_start_wrapper(void *arg)
    79  {
    80  	struct thread_args args = *(struct thread_args *)arg;
    81  
    82  	free(arg);
    83  	tcb_fixup(0);
    84  
    85  	return args.func(args.arg);
    86  }
    87  
    88  static void init_pthread_wrapper(void) {
    89  	void *handle;
    90  
    91  	// Locate symbol for the system pthread_create function.
    92  	handle = dlopen("libpthread.so", RTLD_LAZY);
    93  	if(handle == NULL) {
    94  		fprintf(stderr, "runtime/cgo: dlopen failed to load libpthread: %s\n", dlerror());
    95  		abort();
    96  	}
    97  	sys_pthread_create = dlsym(handle, "pthread_create");
    98  	if(sys_pthread_create == NULL) {
    99  		fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror());
   100  		abort();
   101  	}
   102  	// _rthread_init is hidden in OpenBSD librthread that has TIB.
   103  	if(dlsym(handle, "_rthread_init") == NULL) {
   104  		has_tib = 1;
   105  	}
   106  	dlclose(handle);
   107  }
   108  
   109  static pthread_once_t init_pthread_wrapper_once = PTHREAD_ONCE_INIT;
   110  
   111  int
   112  pthread_create(pthread_t *thread, const pthread_attr_t *attr,
   113  	void *(*start_routine)(void *), void *arg)
   114  {
   115  	struct thread_args *p;
   116  
   117  	// we must initialize our wrapper in pthread_create, because it is valid to call
   118  	// pthread_create in a static constructor, and in fact, our test for issue 9456
   119  	// does just that.
   120  	if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
   121  		fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
   122  		abort();
   123  	}
   124  
   125  	p = malloc(sizeof(*p));
   126  	if(p == NULL) {
   127  		errno = ENOMEM;
   128  		return -1;
   129  	}
   130  	p->func = start_routine;
   131  	p->arg = arg;
   132  
   133  	return sys_pthread_create(thread, attr, thread_start_wrapper, p);
   134  }
   135  
   136  void
   137  x_cgo_init(G *g, void (*setg)(void*))
   138  {
   139  	pthread_attr_t attr;
   140  	size_t size;
   141  
   142  	setg_gcc = setg;
   143  	pthread_attr_init(&attr);
   144  	pthread_attr_getstacksize(&attr, &size);
   145  	g->stacklo = (uintptr)&attr - size + 4096;
   146  	pthread_attr_destroy(&attr);
   147  
   148  	if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
   149  		fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
   150  		abort();
   151  	}
   152  
   153  	tcb_fixup(1);
   154  }
   155  
   156  
   157  void
   158  _cgo_sys_thread_start(ThreadStart *ts)
   159  {
   160  	pthread_attr_t attr;
   161  	sigset_t ign, oset;
   162  	pthread_t p;
   163  	size_t size;
   164  	int err;
   165  
   166  	sigfillset(&ign);
   167  	pthread_sigmask(SIG_SETMASK, &ign, &oset);
   168  
   169  	pthread_attr_init(&attr);
   170  	pthread_attr_getstacksize(&attr, &size);
   171  
   172  	// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
   173  	ts->g->stackhi = size;
   174  	err = _cgo_openbsd_try_pthread_create(sys_pthread_create, &p, &attr, threadentry, ts);
   175  
   176  	pthread_sigmask(SIG_SETMASK, &oset, nil);
   177  
   178  	if (err != 0) {
   179  		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
   180  		abort();
   181  	}
   182  }
   183  
   184  static void*
   185  threadentry(void *v)
   186  {
   187  	ThreadStart ts;
   188  
   189  	tcb_fixup(0);
   190  
   191  	ts = *(ThreadStart*)v;
   192  	free(v);
   193  
   194  	/*
   195  	 * Set specific keys.
   196  	 */
   197  	setg_gcc((void*)ts.g);
   198  
   199  	crosscall_386(ts.fn);
   200  	return nil;
   201  }