github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/runtime/cgo/gcc_darwin_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 <string.h> /* for strerror */ 6 #include <pthread.h> 7 #include <signal.h> 8 #include "libcgo.h" 9 10 static void* threadentry(void*); 11 static pthread_key_t k1; 12 13 #define magic1 (0x23581321345589ULL) 14 15 static void 16 inittls(void) 17 { 18 uint64 x; 19 pthread_key_t tofree[128], k; 20 int i, ntofree; 21 22 /* 23 * Same logic, code as darwin_386.c:/inittls, except that words 24 * are 8 bytes long now, and the thread-local storage starts 25 * at 0x60 on Leopard / Snow Leopard. So the offset is 26 * 0x60+8*0x108 = 0x8a0. 27 * 28 * The linker and runtime hard-code this constant offset 29 * from %gs where we expect to find g. 30 * Known to ../../../liblink/sym.c:/8a0 31 * and to ../sys_darwin_amd64.s:/8a0 32 * 33 * As disgusting as on the 386; same justification. 34 */ 35 ntofree = 0; 36 for(;;) { 37 if(pthread_key_create(&k, nil) < 0) { 38 fprintf(stderr, "runtime/cgo: pthread_key_create failed\n"); 39 abort(); 40 } 41 pthread_setspecific(k, (void*)magic1); 42 asm volatile("movq %%gs:0x8a0, %0" : "=r"(x)); 43 pthread_setspecific(k, 0); 44 if(x == magic1) { 45 k1 = k; 46 break; 47 } 48 if(ntofree >= nelem(tofree)) { 49 fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n"); 50 fprintf(stderr, "\ttried"); 51 for(i=0; i<ntofree; i++) 52 fprintf(stderr, " %#x", (unsigned)tofree[i]); 53 fprintf(stderr, "\n"); 54 abort(); 55 } 56 tofree[ntofree++] = k; 57 } 58 59 /* 60 * We got the key we wanted. Free the others. 61 */ 62 for(i=0; i<ntofree; i++) 63 pthread_key_delete(tofree[i]); 64 } 65 66 void 67 x_cgo_init(G *g) 68 { 69 pthread_attr_t attr; 70 size_t size; 71 72 pthread_attr_init(&attr); 73 pthread_attr_getstacksize(&attr, &size); 74 g->stacklo = (uintptr)&attr - size + 4096; 75 pthread_attr_destroy(&attr); 76 77 inittls(); 78 } 79 80 81 void 82 _cgo_sys_thread_start(ThreadStart *ts) 83 { 84 pthread_attr_t attr; 85 sigset_t ign, oset; 86 pthread_t p; 87 size_t size; 88 int err; 89 90 sigfillset(&ign); 91 pthread_sigmask(SIG_SETMASK, &ign, &oset); 92 93 pthread_attr_init(&attr); 94 pthread_attr_getstacksize(&attr, &size); 95 // Leave stacklo=0 and set stackhi=size; mstack will do the rest. 96 ts->g->stackhi = size; 97 err = pthread_create(&p, &attr, threadentry, ts); 98 99 pthread_sigmask(SIG_SETMASK, &oset, nil); 100 101 if (err != 0) { 102 fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err)); 103 abort(); 104 } 105 } 106 107 static void* 108 threadentry(void *v) 109 { 110 ThreadStart ts; 111 112 ts = *(ThreadStart*)v; 113 free(v); 114 115 pthread_setspecific(k1, (void*)ts.g); 116 117 crosscall_amd64(ts.fn); 118 return nil; 119 }