Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #include <string.h> /* for strerror */ | 5 #include <string.h> /* for strerror */ |
6 #include <pthread.h> | 6 #include <pthread.h> |
7 #include <signal.h> | 7 #include <signal.h> |
8 #include "libcgo.h" | 8 #include "libcgo.h" |
9 | 9 |
10 static void* threadentry(void*); | 10 static void* threadentry(void*); |
11 static pthread_key_t k1, k2; | 11 static pthread_key_t k1; |
12 | 12 |
13 #define magic1 (0x23581321U) | 13 #define magic1 (0x23581321U) |
14 | 14 |
15 static void | 15 static void |
16 inittls(void) | 16 inittls(void) |
17 { | 17 { |
18 » uint32 x, y; | 18 » uint32 x; |
19 pthread_key_t tofree[128], k; | 19 pthread_key_t tofree[128], k; |
20 int i, ntofree; | 20 int i, ntofree; |
21 int havek1, havek2; | |
22 | 21 |
23 /* | 22 /* |
24 » * Allocate thread-local storage slots for m, g. | 23 » * Allocate thread-local storage slot for g. |
25 * The key numbers start at 0x100, and we expect to be | 24 * The key numbers start at 0x100, and we expect to be |
26 * one of the early calls to pthread_key_create, so we | 25 * one of the early calls to pthread_key_create, so we |
27 » * should be able to get pretty low numbers. | 26 » * should be able to get a pretty low number. |
28 * | 27 * |
29 * In Darwin/386 pthreads, %gs points at the thread | 28 * In Darwin/386 pthreads, %gs points at the thread |
30 * structure, and each key is an index into the thread-local | 29 * structure, and each key is an index into the thread-local |
31 * storage array that begins at offset 0x48 within in that structure. | 30 * storage array that begins at offset 0x48 within in that structure. |
32 * It may happen that we are not quite the first function to try | 31 * It may happen that we are not quite the first function to try |
33 * to allocate thread-local storage keys, so instead of depending | 32 * to allocate thread-local storage keys, so instead of depending |
34 » * on getting 0x100 and 0x101, we try for 0x108 and 0x109, | 33 » * on getting 0x100, we try for 0x108, allocating keys until |
35 » * allocating keys until we get the ones we want and then freeing | 34 » * we get the one we want and then freeing the ones we didn't want. |
36 » * the ones we didn't want. | |
37 * | 35 * |
38 » * Thus the final offsets to use in %gs references are | 36 » * Thus the final offset to use in %gs references is |
39 » * 0x48+4*0x108 = 0x468 and 0x48+4*0x109 = 0x46c. | 37 » * 0x48+4*0x108 = 0x468. |
40 * | 38 * |
41 » * The linker and runtime hard-code these constant offsets | 39 » * The linker and runtime hard-code this constant offset |
42 » * from %gs where we expect to find m and g. | 40 » * from %gs where we expect to find g. |
43 * Known to ../../../cmd/8l/obj.c:/468 | 41 * Known to ../../../cmd/8l/obj.c:/468 |
minux
2014/06/16 21:32:11
it's now at:
../../../liblink/sym.c:/468
however,
rsc
2014/06/24 20:08:17
Done.
| |
44 * and to ../sys_darwin_386.s:/468 | 42 * and to ../sys_darwin_386.s:/468 |
45 * | 43 * |
46 * This is truly disgusting and a bit fragile, but taking care | 44 * This is truly disgusting and a bit fragile, but taking care |
47 * of it here protects the rest of the system from damage. | 45 * of it here protects the rest of the system from damage. |
48 * The alternative would be to use a global variable that | 46 * The alternative would be to use a global variable that |
49 * held the offset and refer to that variable each time we | 47 * held the offset and refer to that variable each time we |
50 » * need a %gs variable (m or g). That approach would | 48 » * need a %gs variable (g). That approach would |
51 * require an extra instruction and memory reference in | 49 * require an extra instruction and memory reference in |
52 * every stack growth prolog and would also require | 50 * every stack growth prolog and would also require |
53 * rewriting the code that 8c generates for extern registers. | 51 * rewriting the code that 8c generates for extern registers. |
54 * | 52 * |
55 * Things get more disgusting on OS X 10.7 Lion. | 53 * Things get more disgusting on OS X 10.7 Lion. |
56 * The 0x48 base mentioned above is the offset of the tsd | 54 * The 0x48 base mentioned above is the offset of the tsd |
57 * array within the per-thread structure on Leopard and Snow Leopard. | 55 * array within the per-thread structure on Leopard and Snow Leopard. |
58 * On Lion, the base moved a little, so while the math above | 56 * On Lion, the base moved a little, so while the math above |
59 * still applies, the base is different. Thus, we cannot | 57 * still applies, the base is different. Thus, we cannot |
60 * look for specific key values if we want to build binaries | 58 * look for specific key values if we want to build binaries |
61 * that run on both systems. Instead, forget about the | 59 * that run on both systems. Instead, forget about the |
62 * specific key values and just allocate and initialize per-thread | 60 * specific key values and just allocate and initialize per-thread |
63 * storage until we find a key that writes to the memory location | 61 * storage until we find a key that writes to the memory location |
64 * we want. Then keep that key. | 62 * we want. Then keep that key. |
65 */ | 63 */ |
66 havek1 = 0; | |
67 havek2 = 0; | |
68 ntofree = 0; | 64 ntofree = 0; |
69 » while(!havek1 || !havek2) { | 65 » for(;;) { |
70 if(pthread_key_create(&k, nil) < 0) { | 66 if(pthread_key_create(&k, nil) < 0) { |
71 fprintf(stderr, "runtime/cgo: pthread_key_create failed\ n"); | 67 fprintf(stderr, "runtime/cgo: pthread_key_create failed\ n"); |
72 abort(); | 68 abort(); |
73 } | 69 } |
74 pthread_setspecific(k, (void*)magic1); | 70 pthread_setspecific(k, (void*)magic1); |
75 asm volatile("movl %%gs:0x468, %0" : "=r"(x)); | 71 asm volatile("movl %%gs:0x468, %0" : "=r"(x)); |
76 » » asm volatile("movl %%gs:0x46c, %0" : "=r"(y)); | 72 » » pthread_setspecific(k, 0); |
77 if(x == magic1) { | 73 if(x == magic1) { |
78 havek1 = 1; | |
79 k1 = k; | 74 k1 = k; |
80 » » } else if(y == magic1) { | 75 » » » break; |
81 » » » havek2 = 1; | |
82 » » » k2 = k; | |
83 » » } else { | |
84 » » » if(ntofree >= nelem(tofree)) { | |
85 » » » » fprintf(stderr, "runtime/cgo: could not obtain p thread_keys\n"); | |
86 » » » » fprintf(stderr, "\ttried"); | |
87 » » » » for(i=0; i<ntofree; i++) | |
88 » » » » » fprintf(stderr, " %#x", (unsigned)tofree [i]); | |
89 » » » » fprintf(stderr, "\n"); | |
90 » » » » abort(); | |
91 » » » } | |
92 » » » tofree[ntofree++] = k; | |
93 } | 76 } |
94 » » pthread_setspecific(k, 0); | 77 » » if(ntofree >= nelem(tofree)) { |
78 » » » fprintf(stderr, "runtime/cgo: could not obtain pthread_k eys\n"); | |
79 » » » fprintf(stderr, "\ttried"); | |
80 » » » for(i=0; i<ntofree; i++) | |
81 » » » » fprintf(stderr, " %#x", (unsigned)tofree[i]); | |
82 » » » fprintf(stderr, "\n"); | |
83 » » » abort(); | |
84 » » } | |
95 } | 85 } |
iant
2014/06/16 20:32:34
You've dropped the line
tofree[ntofree++] = k;
rsc
2014/06/24 20:08:17
Done.
| |
96 | 86 |
97 /* | 87 /* |
98 » * We got the keys we wanted. Free the others. | 88 » * We got the key we wanted. Free the others. |
99 */ | 89 */ |
100 for(i=0; i<ntofree; i++) | 90 for(i=0; i<ntofree; i++) |
101 pthread_key_delete(tofree[i]); | 91 pthread_key_delete(tofree[i]); |
102 } | 92 } |
103 | 93 |
104 void | 94 void |
105 x_cgo_init(G *g) | 95 x_cgo_init(G *g) |
106 { | 96 { |
107 pthread_attr_t attr; | 97 pthread_attr_t attr; |
108 size_t size; | 98 size_t size; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
151 | 141 |
152 ts.g->stackbase = (uintptr)&ts; | 142 ts.g->stackbase = (uintptr)&ts; |
153 | 143 |
154 /* | 144 /* |
155 * _cgo_sys_thread_start set stackguard to stack size; | 145 * _cgo_sys_thread_start set stackguard to stack size; |
156 * change to actual guard pointer. | 146 * change to actual guard pointer. |
157 */ | 147 */ |
158 ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; | 148 ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; |
159 | 149 |
160 pthread_setspecific(k1, (void*)ts.g); | 150 pthread_setspecific(k1, (void*)ts.g); |
161 pthread_setspecific(k2, (void*)ts.m); | |
162 | 151 |
163 crosscall_386(ts.fn); | 152 crosscall_386(ts.fn); |
164 return nil; | 153 return nil; |
165 } | 154 } |
OLD | NEW |