LEFT | RIGHT |
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 |
13 #define TCB_SIZE 16 | 15 // TCB_SIZE is sizeof(struct thread_control_block), |
14 #define TLS_SIZE 8 | 16 // as defined in /usr/src/lib/librthread/tcb.h |
| 17 #define TCB_SIZE (4 * sizeof(void *)) |
| 18 #define TLS_SIZE (2 * sizeof(void *)) |
15 | 19 |
16 void *__get_tcb(void); | 20 void *__get_tcb(void); |
17 void __set_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 }; |
18 | 30 |
19 static void | 31 static void |
20 tcb_fixup(int mainthread) | 32 tcb_fixup(int mainthread) |
21 { | 33 { |
22 void *newtcb, *oldtcb; | 34 void *newtcb, *oldtcb; |
23 | 35 |
24 // The OpenBSD ld.so(1) does not currently support PT_TLS. As a result, | 36 // The OpenBSD ld.so(1) does not currently support PT_TLS. As a result, |
25 // we need to allocate our own TLS space while preserving the existing | 37 // we need to allocate our own TLS space while preserving the existing |
26 // TCB that has been setup via librthread. | 38 // TCB that has been setup via librthread. |
27 | 39 |
28 newtcb = malloc(TCB_SIZE + TLS_SIZE); | 40 newtcb = malloc(TCB_SIZE + TLS_SIZE); |
29 if(newtcb == NULL) | 41 if(newtcb == NULL) |
30 abort(); | 42 abort(); |
31 | 43 |
| 44 // The signal trampoline expects the TLS slots to be zeroed. |
| 45 bzero(newtcb, TLS_SIZE); |
| 46 |
32 oldtcb = __get_tcb(); | 47 oldtcb = __get_tcb(); |
33 bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE); | 48 bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE); |
34 __set_tcb(newtcb + TLS_SIZE); | 49 __set_tcb(newtcb + TLS_SIZE); |
35 | 50 |
36 // The main thread TCB is a static allocation - do not try to free it. | 51 // The main thread TCB is a static allocation - do not try to free it. |
37 if(!mainthread) | 52 if(!mainthread) |
38 free(oldtcb); | 53 free(oldtcb); |
39 } | 54 } |
40 | 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 |
41 static void | 84 static void |
42 xinitcgo(G *g) | 85 xinitcgo(G *g) |
43 { | 86 { |
44 pthread_attr_t attr; | 87 pthread_attr_t attr; |
45 size_t size; | 88 size_t size; |
| 89 void *handle; |
46 | 90 |
47 pthread_attr_init(&attr); | 91 pthread_attr_init(&attr); |
48 pthread_attr_getstacksize(&attr, &size); | 92 pthread_attr_getstacksize(&attr, &size); |
49 g->stackguard = (uintptr)&attr - size + 4096; | 93 g->stackguard = (uintptr)&attr - size + 4096; |
50 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); |
51 | 108 |
52 tcb_fixup(1); | 109 tcb_fixup(1); |
53 } | 110 } |
54 | 111 |
55 void (*initcgo)(G*) = xinitcgo; | 112 void (*initcgo)(G*) = xinitcgo; |
56 | 113 |
57 void | 114 void |
58 libcgo_sys_thread_start(ThreadStart *ts) | 115 libcgo_sys_thread_start(ThreadStart *ts) |
59 { | 116 { |
60 pthread_attr_t attr; | 117 pthread_attr_t attr; |
61 sigset_t ign, oset; | 118 sigset_t ign, oset; |
62 pthread_t p; | 119 pthread_t p; |
63 size_t size; | 120 size_t size; |
64 int err; | 121 int err; |
65 | 122 |
66 sigfillset(&ign); | 123 sigfillset(&ign); |
67 sigprocmask(SIG_SETMASK, &ign, &oset); | 124 sigprocmask(SIG_SETMASK, &ign, &oset); |
68 | 125 |
69 pthread_attr_init(&attr); | 126 pthread_attr_init(&attr); |
70 pthread_attr_getstacksize(&attr, &size); | 127 pthread_attr_getstacksize(&attr, &size); |
71 ts->g->stackguard = size; | 128 ts->g->stackguard = size; |
72 » err = pthread_create(&p, &attr, threadentry, ts); | 129 » err = sys_pthread_create(&p, &attr, threadentry, ts); |
73 | 130 |
74 sigprocmask(SIG_SETMASK, &oset, nil); | 131 sigprocmask(SIG_SETMASK, &oset, nil); |
75 | 132 |
76 if (err != 0) { | 133 if (err != 0) { |
77 fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", stre
rror(err)); | 134 fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", stre
rror(err)); |
78 abort(); | 135 abort(); |
79 } | 136 } |
80 } | 137 } |
81 | 138 |
82 static void* | 139 static void* |
(...skipping 21 matching lines...) Expand all Loading... |
104 */ | 161 */ |
105 asm volatile ( | 162 asm volatile ( |
106 "movl %0, %%gs:-8\n" // MOVL g, -8(GS) | 163 "movl %0, %%gs:-8\n" // MOVL g, -8(GS) |
107 "movl %1, %%gs:-4\n" // MOVL m, -4(GS) | 164 "movl %1, %%gs:-4\n" // MOVL m, -4(GS) |
108 :: "r"(ts.g), "r"(ts.m) | 165 :: "r"(ts.g), "r"(ts.m) |
109 ); | 166 ); |
110 | 167 |
111 crosscall_386(ts.fn); | 168 crosscall_386(ts.fn); |
112 return nil; | 169 return nil; |
113 } | 170 } |
LEFT | RIGHT |