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