blob: 8522cd48c4ac9fec18e06c53fe850ef91da4d6dc [file] [log] [blame]
Joel Sing708db792012-12-21 01:43:19 +11001// Copyright 2009 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 <sys/types.h>
6#include <dlfcn.h>
7#include <errno.h>
8#include <pthread.h>
9#include <signal.h>
10#include <string.h>
11#include "libcgo.h"
12
13static void* threadentry(void*);
Russ Cox89f185f2014-06-26 11:54:39 -040014static void (*setg_gcc)(void*);
Joel Sing708db792012-12-21 01:43:19 +110015
16// TCB_SIZE is sizeof(struct thread_control_block),
17// as defined in /usr/src/lib/librthread/tcb.h
18#define TCB_SIZE (4 * sizeof(void *))
19#define TLS_SIZE (2 * sizeof(void *))
20
21void *__get_tcb(void);
22void __set_tcb(void *);
23
24static int (*sys_pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
25 void *(*start_routine)(void *), void *arg);
26
27struct thread_args {
28 void *(*func)(void *);
29 void *arg;
30};
31
32static void
33tcb_fixup(int mainthread)
34{
35 void *newtcb, *oldtcb;
36
37 // The OpenBSD ld.so(1) does not currently support PT_TLS. As a result,
38 // we need to allocate our own TLS space while preserving the existing
39 // TCB that has been setup via librthread.
40
41 newtcb = malloc(TCB_SIZE + TLS_SIZE);
42 if(newtcb == NULL)
43 abort();
44
45 // The signal trampoline expects the TLS slots to be zeroed.
46 bzero(newtcb, TLS_SIZE);
47
48 oldtcb = __get_tcb();
49 bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
50 __set_tcb(newtcb + TLS_SIZE);
51
Shenghou Ma960d7082013-03-11 14:24:51 +080052 // NOTE(jsing, minux): we can't free oldtcb without causing double-free
53 // problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
54 // has proper support for PT_TLS.
Joel Sing708db792012-12-21 01:43:19 +110055}
56
57static void *
58thread_start_wrapper(void *arg)
59{
60 struct thread_args args = *(struct thread_args *)arg;
61
62 free(arg);
63 tcb_fixup(0);
64
65 return args.func(args.arg);
66}
67
Shenghou Ma77cd6192014-12-31 20:30:57 -050068static void init_pthread_wrapper(void) {
69 void *handle;
70
71 // Locate symbol for the system pthread_create function.
72 handle = dlopen("libpthread.so", RTLD_LAZY);
73 if(handle == NULL) {
74 fprintf(stderr, "runtime/cgo: dlopen failed to load libpthread: %s\n", dlerror());
75 abort();
76 }
77 sys_pthread_create = dlsym(handle, "pthread_create");
78 if(sys_pthread_create == NULL) {
79 fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror());
80 abort();
81 }
82 dlclose(handle);
83}
84
85static pthread_once_t init_pthread_wrapper_once = PTHREAD_ONCE_INIT;
86
Joel Sing708db792012-12-21 01:43:19 +110087int
88pthread_create(pthread_t *thread, const pthread_attr_t *attr,
89 void *(*start_routine)(void *), void *arg)
90{
91 struct thread_args *p;
92
Shenghou Ma77cd6192014-12-31 20:30:57 -050093 // we must initialize our wrapper in pthread_create, because it is valid to call
94 // pthread_create in a static constructor, and in fact, our test for issue 9456
95 // does just that.
96 if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
97 fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
98 abort();
99 }
100
Joel Sing708db792012-12-21 01:43:19 +1100101 p = malloc(sizeof(*p));
102 if(p == NULL) {
103 errno = ENOMEM;
104 return -1;
105 }
106 p->func = start_routine;
107 p->arg = arg;
108
109 return sys_pthread_create(thread, attr, thread_start_wrapper, p);
110}
111
Russ Coxf8d49b52013-02-28 16:24:38 -0500112void
Russ Cox89f185f2014-06-26 11:54:39 -0400113x_cgo_init(G *g, void (*setg)(void*))
Joel Sing708db792012-12-21 01:43:19 +1100114{
115 pthread_attr_t attr;
116 size_t size;
Joel Sing708db792012-12-21 01:43:19 +1100117
Russ Cox89f185f2014-06-26 11:54:39 -0400118 setg_gcc = setg;
Joel Sing708db792012-12-21 01:43:19 +1100119 pthread_attr_init(&attr);
120 pthread_attr_getstacksize(&attr, &size);
Russ Cox15b76ad2014-09-09 13:39:57 -0400121 g->stacklo = (uintptr)&attr - size + 4096;
Joel Sing708db792012-12-21 01:43:19 +1100122 pthread_attr_destroy(&attr);
123
Shenghou Ma77cd6192014-12-31 20:30:57 -0500124 if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) {
125 fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n");
Joel Sing708db792012-12-21 01:43:19 +1100126 abort();
127 }
Joel Sing708db792012-12-21 01:43:19 +1100128
129 tcb_fixup(1);
130}
131
Joel Sing708db792012-12-21 01:43:19 +1100132
133void
Russ Coxf8d49b52013-02-28 16:24:38 -0500134_cgo_sys_thread_start(ThreadStart *ts)
Joel Sing708db792012-12-21 01:43:19 +1100135{
136 pthread_attr_t attr;
137 sigset_t ign, oset;
138 pthread_t p;
139 size_t size;
140 int err;
141
142 sigfillset(&ign);
S.Çağlar Onur41183d02013-12-22 08:55:29 -0800143 pthread_sigmask(SIG_SETMASK, &ign, &oset);
Joel Sing708db792012-12-21 01:43:19 +1100144
145 pthread_attr_init(&attr);
146 pthread_attr_getstacksize(&attr, &size);
147
Russ Cox15b76ad2014-09-09 13:39:57 -0400148 // Leave stacklo=0 and set stackhi=size; mstack will do the rest.
149 ts->g->stackhi = size;
Joel Sing708db792012-12-21 01:43:19 +1100150 err = sys_pthread_create(&p, &attr, threadentry, ts);
151
S.Çağlar Onur41183d02013-12-22 08:55:29 -0800152 pthread_sigmask(SIG_SETMASK, &oset, nil);
Joel Sing708db792012-12-21 01:43:19 +1100153
154 if (err != 0) {
155 fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
156 abort();
157 }
158}
159
160static void*
161threadentry(void *v)
162{
163 ThreadStart ts;
164
165 tcb_fixup(0);
166
167 ts = *(ThreadStart*)v;
168 free(v);
169
Joel Sing708db792012-12-21 01:43:19 +1100170 /*
Russ Cox6a70f9d2013-03-25 18:14:02 -0400171 * Set specific keys.
Joel Sing708db792012-12-21 01:43:19 +1100172 */
Russ Cox89f185f2014-06-26 11:54:39 -0400173 setg_gcc((void*)ts.g);
Russ Cox6a70f9d2013-03-25 18:14:02 -0400174
Joel Sing708db792012-12-21 01:43:19 +1100175 crosscall_amd64(ts.fn);
176 return nil;
177}