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