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