1 // Copyright 2015 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 gcc_darwin_386.c:/inittls. 24 * Note that this is a temporary hack that should be fixed soon. 25 * Android-L and M bionic's pthread implementation differ 26 * significantly, and can change any time. 27 * https://android-review.googlesource.com/#/c/134202 28 * 29 * We chose %fs:0x1d0 which seems to work in testing with Android 30 * emulators (API22, API23) but it may break any time. 31 * 32 * TODO: fix this. 33 * 34 * The linker and runtime hard-code this constant offset 35 * from %fs where we expect to find g. Disgusting. 36 * 37 * Known to src/cmd/link/internal/ld/sym.go:/0x1d0 38 * and to src/runtime/sys_linux_amd64.s:/0x1d0 or /GOOS_android. 39 * 40 * As disgusting as on the darwin/386, darwin/amd64. 41 */ 42 ntofree = 0; 43 for(;;) { 44 if(pthread_key_create(&k, nil) < 0) { 45 fprintf(stderr, "runtime/cgo: pthread_key_create failed\n"); 46 abort(); 47 } 48 pthread_setspecific(k, (void*)magic1); 49 asm volatile("movq %%fs:0x1d0, %0" : "=r"(x)); 50 pthread_setspecific(k, 0); 51 if(x == magic1) { 52 k1 = k; 53 break; 54 } 55 if(ntofree >= nelem(tofree)) { 56 fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n"); 57 fprintf(stderr, "\ttried"); 58 for(i=0; i<ntofree; i++) 59 fprintf(stderr, " %#x", (unsigned)tofree[i]); 60 fprintf(stderr, "\n"); 61 abort(); 62 } 63 tofree[ntofree++] = k; 64 } 65 // TODO: output to stderr is not useful for apps. 66 // Can we fall back to Android's log library? 67 68 /* 69 * We got the key we wanted. Free the others. 70 */ 71 for(i=0; i<ntofree; i++) { 72 pthread_key_delete(tofree[i]); 73 } 74 } 75 76 77 static void* 78 threadentry(void *v) 79 { 80 ThreadStart ts; 81 82 ts = *(ThreadStart*)v; 83 free(v); 84 85 pthread_setspecific(k1, (void*)ts.g); 86 87 crosscall_amd64(ts.fn); 88 return nil; 89 } 90 91 void (*x_cgo_inittls)(void) = inittls; 92 void* (*x_cgo_threadentry)(void*) = threadentry; 93