github.com/shijuvar/go@v0.0.0-20141209052335-e8f13700b70c/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  
    13  static void* threadentry(void*);
    14  static void (*setg_gcc)(void*);
    15  
    16  // TCB_SIZE is sizeof(struct thread_control_block),
    17  // as defined in /usr/src/lib/librthread/tcb.h
    18  #define TCB_SIZE (4 * sizeof(void *))
    19  #define TLS_SIZE (2 * sizeof(void *))
    20  
    21  void *__get_tcb(void);
    22  void __set_tcb(void *);
    23  
    24  static int (*sys_pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
    25  	void *(*start_routine)(void *), void *arg);
    26  
    27  struct thread_args {
    28  	void *(*func)(void *);
    29  	void *arg;
    30  };
    31  
    32  static void
    33  tcb_fixup(int mainthread)
    34  {
    35  	void *newtcb, *oldtcb;
    36  
    37  	// The OpenBSD ld.so(1) does not currently support PT_TLS. As a result,
    38  	// we need to allocate our own TLS space while preserving the existing
    39  	// TCB that has been setup via librthread.
    40  
    41  	newtcb = malloc(TCB_SIZE + TLS_SIZE);
    42  	if(newtcb == NULL)
    43  		abort();
    44  
    45  	// The signal trampoline expects the TLS slots to be zeroed.
    46  	bzero(newtcb, TLS_SIZE);
    47  
    48  	oldtcb = __get_tcb();
    49  	bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
    50  	__set_tcb(newtcb + TLS_SIZE);
    51  
    52  	// NOTE(jsing, minux): we can't free oldtcb without causing double-free
    53  	// problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
    54  	// has proper support for PT_TLS.
    55  }
    56  
    57  static void *
    58  thread_start_wrapper(void *arg)
    59  {
    60  	struct thread_args args = *(struct thread_args *)arg;
    61  
    62  	free(arg);
    63  	tcb_fixup(0);
    64  
    65  	return args.func(args.arg);
    66  }
    67  
    68  int
    69  pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    70  	void *(*start_routine)(void *), void *arg)
    71  {
    72  	struct thread_args *p;
    73  
    74  	p = malloc(sizeof(*p));
    75  	if(p == NULL) {
    76  		errno = ENOMEM;
    77  		return -1;
    78  	}
    79  	p->func = start_routine;
    80  	p->arg = arg;
    81  
    82  	return sys_pthread_create(thread, attr, thread_start_wrapper, p);
    83  }
    84  
    85  void
    86  x_cgo_init(G *g, void (*setg)(void*))
    87  {
    88  	pthread_attr_t attr;
    89  	size_t size;
    90  	void *handle;
    91  
    92  	setg_gcc = setg;
    93  	pthread_attr_init(&attr);
    94  	pthread_attr_getstacksize(&attr, &size);
    95  	g->stacklo = (uintptr)&attr - size + 4096;
    96  	pthread_attr_destroy(&attr);
    97  
    98  	// Locate symbol for the system pthread_create function.
    99  	handle = dlopen("libpthread.so", RTLD_LAZY);
   100  	if(handle == NULL) {
   101  		fprintf(stderr, "dlopen: failed to load libpthread: %s\n", dlerror());
   102  		abort();
   103  	}
   104  	sys_pthread_create = dlsym(handle, "pthread_create");
   105  	if(sys_pthread_create == NULL) {
   106  		fprintf(stderr, "dlsym: failed to find pthread_create: %s\n", dlerror());
   107  		abort();
   108  	}
   109  	dlclose(handle);
   110  
   111  	tcb_fixup(1);
   112  }
   113  
   114  
   115  void
   116  _cgo_sys_thread_start(ThreadStart *ts)
   117  {
   118  	pthread_attr_t attr;
   119  	sigset_t ign, oset;
   120  	pthread_t p;
   121  	size_t size;
   122  	int err;
   123  
   124  	sigfillset(&ign);
   125  	pthread_sigmask(SIG_SETMASK, &ign, &oset);
   126  
   127  	pthread_attr_init(&attr);
   128  	pthread_attr_getstacksize(&attr, &size);
   129  	// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
   130  	ts->g->stackhi = size;
   131  	err = sys_pthread_create(&p, &attr, threadentry, ts);
   132  
   133  	pthread_sigmask(SIG_SETMASK, &oset, nil);
   134  
   135  	if (err != 0) {
   136  		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
   137  		abort();
   138  	}
   139  }
   140  
   141  static void*
   142  threadentry(void *v)
   143  {
   144  	ThreadStart ts;
   145  
   146  	tcb_fixup(0);
   147  
   148  	ts = *(ThreadStart*)v;
   149  	free(v);
   150  
   151  	/*
   152  	 * Set specific keys.
   153  	 */
   154  	setg_gcc((void*)ts.g);
   155  
   156  	crosscall_386(ts.fn);
   157  	return nil;
   158  }