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