LEFT | RIGHT |
(no file at all) | |
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 <sys/types.h> | 5 #include <sys/types.h> |
| 6 #include <dlfcn.h> |
| 7 #include <errno.h> |
6 #include <pthread.h> | 8 #include <pthread.h> |
7 #include <signal.h> | 9 #include <signal.h> |
8 #include <string.h> | 10 #include <string.h> |
9 #include "libcgo.h" | 11 #include "libcgo.h" |
10 | 12 |
11 static void* threadentry(void*); | 13 static void* threadentry(void*); |
12 | 14 |
| 15 // TCB_SIZE is sizeof(struct thread_control_block), |
| 16 // as defined in /usr/src/lib/librthread/tcb.h |
| 17 #define TCB_SIZE (4 * sizeof(void *)) |
| 18 #define TLS_SIZE (2 * sizeof(void *)) |
| 19 |
| 20 void *__get_tcb(void); |
| 21 void __set_tcb(void *); |
| 22 |
| 23 static int (*sys_pthread_create)(pthread_t *thread, const pthread_attr_t *attr, |
| 24 void *(*start_routine)(void *), void *arg); |
| 25 |
| 26 struct thread_args { |
| 27 void *(*func)(void *); |
| 28 void *arg; |
| 29 }; |
| 30 |
| 31 static void |
| 32 tcb_fixup(int mainthread) |
| 33 { |
| 34 void *newtcb, *oldtcb; |
| 35 |
| 36 // The OpenBSD ld.so(1) does not currently support PT_TLS. As a result, |
| 37 // we need to allocate our own TLS space while preserving the existing |
| 38 // TCB that has been setup via librthread. |
| 39 |
| 40 newtcb = malloc(TCB_SIZE + TLS_SIZE); |
| 41 if(newtcb == NULL) |
| 42 abort(); |
| 43 |
| 44 // The signal trampoline expects the TLS slots to be zeroed. |
| 45 bzero(newtcb, TLS_SIZE); |
| 46 |
| 47 oldtcb = __get_tcb(); |
| 48 bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE); |
| 49 __set_tcb(newtcb + TLS_SIZE); |
| 50 |
| 51 // The main thread TCB is a static allocation - do not try to free it. |
| 52 if(!mainthread) |
| 53 free(oldtcb); |
| 54 } |
| 55 |
| 56 static void * |
| 57 thread_start_wrapper(void *arg) |
| 58 { |
| 59 struct thread_args args = *(struct thread_args *)arg; |
| 60 |
| 61 free(arg); |
| 62 tcb_fixup(0); |
| 63 |
| 64 return args.func(args.arg); |
| 65 } |
| 66 |
| 67 int |
| 68 pthread_create(pthread_t *thread, const pthread_attr_t *attr, |
| 69 void *(*start_routine)(void *), void *arg) |
| 70 { |
| 71 struct thread_args *p; |
| 72 |
| 73 p = malloc(sizeof(*p)); |
| 74 if(p == NULL) { |
| 75 errno = ENOMEM; |
| 76 return -1; |
| 77 } |
| 78 p->func = start_routine; |
| 79 p->arg = arg; |
| 80 |
| 81 return sys_pthread_create(thread, attr, thread_start_wrapper, p); |
| 82 } |
| 83 |
13 static void | 84 static void |
14 xinitcgo(G *g) | 85 xinitcgo(G *g) |
15 { | 86 { |
16 pthread_attr_t attr; | 87 pthread_attr_t attr; |
17 size_t size; | 88 size_t size; |
| 89 void *handle; |
18 | 90 |
19 pthread_attr_init(&attr); | 91 pthread_attr_init(&attr); |
20 pthread_attr_getstacksize(&attr, &size); | 92 pthread_attr_getstacksize(&attr, &size); |
21 g->stackguard = (uintptr)&attr - size + 4096; | 93 g->stackguard = (uintptr)&attr - size + 4096; |
22 pthread_attr_destroy(&attr); | 94 pthread_attr_destroy(&attr); |
| 95 |
| 96 // Locate symbol for the system pthread_create function. |
| 97 handle = dlopen("libpthread.so", RTLD_LAZY); |
| 98 if(handle == NULL) { |
| 99 fprintf(stderr, "dlopen: failed to load libpthread: %s\n", dlerr
or()); |
| 100 abort(); |
| 101 } |
| 102 sys_pthread_create = dlsym(handle, "pthread_create"); |
| 103 if(sys_pthread_create == NULL) { |
| 104 fprintf(stderr, "dlsym: failed to find pthread_create: %s\n", dl
error()); |
| 105 abort(); |
| 106 } |
| 107 dlclose(handle); |
| 108 |
| 109 tcb_fixup(1); |
23 } | 110 } |
24 | 111 |
25 void (*initcgo)(G*) = xinitcgo; | 112 void (*initcgo)(G*) = xinitcgo; |
26 | 113 |
27 void | 114 void |
28 libcgo_sys_thread_start(ThreadStart *ts) | 115 libcgo_sys_thread_start(ThreadStart *ts) |
29 { | 116 { |
30 pthread_attr_t attr; | 117 pthread_attr_t attr; |
31 sigset_t ign, oset; | 118 sigset_t ign, oset; |
32 pthread_t p; | 119 pthread_t p; |
33 size_t size; | 120 size_t size; |
34 int err; | 121 int err; |
35 | 122 |
36 sigfillset(&ign); | 123 sigfillset(&ign); |
37 sigprocmask(SIG_SETMASK, &ign, &oset); | 124 sigprocmask(SIG_SETMASK, &ign, &oset); |
38 | 125 |
39 pthread_attr_init(&attr); | 126 pthread_attr_init(&attr); |
40 pthread_attr_getstacksize(&attr, &size); | 127 pthread_attr_getstacksize(&attr, &size); |
41 | 128 |
42 ts->g->stackguard = size; | 129 ts->g->stackguard = size; |
43 » err = pthread_create(&p, &attr, threadentry, ts); | 130 » err = sys_pthread_create(&p, &attr, threadentry, ts); |
44 | 131 |
45 sigprocmask(SIG_SETMASK, &oset, nil); | 132 sigprocmask(SIG_SETMASK, &oset, nil); |
46 | 133 |
47 if (err != 0) { | 134 if (err != 0) { |
48 fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", stre
rror(err)); | 135 fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", stre
rror(err)); |
49 abort(); | 136 abort(); |
50 } | 137 } |
51 } | 138 } |
52 | 139 |
53 static void* | 140 static void* |
54 threadentry(void *v) | 141 threadentry(void *v) |
55 { | 142 { |
56 ThreadStart ts; | 143 ThreadStart ts; |
57 | 144 |
| 145 tcb_fixup(0); |
| 146 |
58 ts = *(ThreadStart*)v; | 147 ts = *(ThreadStart*)v; |
59 free(v); | 148 free(v); |
60 | 149 |
61 ts.g->stackbase = (uintptr)&ts; | 150 ts.g->stackbase = (uintptr)&ts; |
62 | 151 |
63 /* | 152 /* |
64 * libcgo_sys_thread_start set stackguard to stack size; | 153 * libcgo_sys_thread_start set stackguard to stack size; |
65 * change to actual guard pointer. | 154 * change to actual guard pointer. |
66 */ | 155 */ |
67 ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; | 156 ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; |
68 | 157 |
69 /* | 158 /* |
70 » * Set specific keys. On NetBSD/ELF, the thread local storage | 159 » * Set specific keys. On OpenBSD/ELF, the thread local storage |
71 * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes | 160 * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes |
72 * for the two words g and m at %fs:-16 and %fs:-8. | 161 * for the two words g and m at %fs:-16 and %fs:-8. |
73 */ | 162 */ |
74 asm volatile ( | 163 asm volatile ( |
75 "movq %0, %%fs:-16\n" // MOVL g, -16(FS) | 164 "movq %0, %%fs:-16\n" // MOVL g, -16(FS) |
76 "movq %1, %%fs:-8\n" // MOVL m, -8(FS) | 165 "movq %1, %%fs:-8\n" // MOVL m, -8(FS) |
77 :: "r"(ts.g), "r"(ts.m) | 166 :: "r"(ts.g), "r"(ts.m) |
78 ); | 167 ); |
79 crosscall_amd64(ts.fn); | 168 crosscall_amd64(ts.fn); |
80 return nil; | 169 return nil; |
81 } | 170 } |
LEFT | RIGHT |