|
| 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; |
0 commit comments