2010-12-08 12:10:00 -07:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include "libcgo.h"
|
|
|
|
|
|
|
|
static void* threadentry(void*);
|
|
|
|
static pthread_key_t k1, k2;
|
|
|
|
|
2011-06-16 09:10:31 -06:00
|
|
|
#define magic1 (0x23581321345589ULL)
|
|
|
|
|
2010-12-08 12:10:00 -07:00
|
|
|
static void
|
|
|
|
inittls(void)
|
|
|
|
{
|
|
|
|
uint64 x, y;
|
2011-06-16 09:10:31 -06:00
|
|
|
pthread_key_t tofree[128], k;
|
2010-12-08 12:10:00 -07:00
|
|
|
int i, ntofree;
|
|
|
|
int havek1, havek2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Same logic, code as darwin_386.c:/inittls, except that words
|
2011-06-16 09:10:31 -06:00
|
|
|
* are 8 bytes long now, and the thread-local storage starts
|
|
|
|
* at 0x60 on Leopard / Snow Leopard. So the offsets are
|
2010-12-08 12:10:00 -07:00
|
|
|
* 0x60+8*0x108 = 0x8a0 and 0x60+8*0x109 = 0x8a8.
|
|
|
|
*
|
|
|
|
* The linker and runtime hard-code these constant offsets
|
2011-06-16 09:10:31 -06:00
|
|
|
* from %gs where we expect to find m and g.
|
|
|
|
* Known to ../cmd/6l/obj.c:/8a0
|
2010-12-08 12:10:00 -07:00
|
|
|
* and to ../pkg/runtime/darwin/amd64/sys.s:/8a0
|
|
|
|
*
|
|
|
|
* As disgusting as on the 386; same justification.
|
|
|
|
*/
|
|
|
|
havek1 = 0;
|
|
|
|
havek2 = 0;
|
|
|
|
ntofree = 0;
|
|
|
|
while(!havek1 || !havek2) {
|
|
|
|
if(pthread_key_create(&k, nil) < 0) {
|
2011-06-16 09:10:31 -06:00
|
|
|
fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
|
2010-12-08 12:10:00 -07:00
|
|
|
abort();
|
|
|
|
}
|
2011-06-16 09:10:31 -06:00
|
|
|
pthread_setspecific(k, (void*)magic1);
|
|
|
|
asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
|
|
|
|
asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
|
|
|
|
if(x == magic1) {
|
2010-12-08 12:10:00 -07:00
|
|
|
havek1 = 1;
|
|
|
|
k1 = k;
|
2011-06-16 09:10:31 -06:00
|
|
|
} else if(y == magic1) {
|
2010-12-08 12:10:00 -07:00
|
|
|
havek2 = 1;
|
|
|
|
k2 = k;
|
2011-06-16 09:10:31 -06:00
|
|
|
} else {
|
|
|
|
if(ntofree >= nelem(tofree)) {
|
|
|
|
fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
|
|
|
|
fprintf(stderr, "\ttried");
|
|
|
|
for(i=0; i<ntofree; i++)
|
|
|
|
fprintf(stderr, " %#x", (unsigned)tofree[i]);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
tofree[ntofree++] = k;
|
2010-12-08 12:10:00 -07:00
|
|
|
}
|
2011-06-16 09:10:31 -06:00
|
|
|
pthread_setspecific(k, 0);
|
2010-12-08 12:10:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2011-06-16 09:10:31 -06:00
|
|
|
* We got the keys we wanted. Free the others.
|
2010-12-08 12:10:00 -07:00
|
|
|
*/
|
2011-06-16 09:10:31 -06:00
|
|
|
for(i=0; i<ntofree; i++)
|
|
|
|
pthread_key_delete(tofree[i]);
|
2010-12-08 12:10:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xinitcgo(void)
|
|
|
|
{
|
|
|
|
inittls();
|
|
|
|
}
|
|
|
|
|
|
|
|
void (*initcgo) = xinitcgo;
|
|
|
|
|
|
|
|
void
|
|
|
|
libcgo_sys_thread_start(ThreadStart *ts)
|
|
|
|
{
|
|
|
|
pthread_attr_t attr;
|
|
|
|
pthread_t p;
|
|
|
|
size_t size;
|
2011-06-28 10:04:50 -06:00
|
|
|
int err;
|
2010-12-08 12:10:00 -07:00
|
|
|
|
|
|
|
pthread_attr_init(&attr);
|
|
|
|
pthread_attr_getstacksize(&attr, &size);
|
|
|
|
ts->g->stackguard = size;
|
2011-06-28 10:04:50 -06:00
|
|
|
err = pthread_create(&p, &attr, threadentry, ts);
|
|
|
|
if (err != 0) {
|
|
|
|
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
|
|
|
|
abort();
|
|
|
|
}
|
2010-12-08 12:10:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
|
|
|
threadentry(void *v)
|
|
|
|
{
|
|
|
|
ThreadStart ts;
|
|
|
|
|
|
|
|
ts = *(ThreadStart*)v;
|
|
|
|
free(v);
|
|
|
|
|
|
|
|
ts.g->stackbase = (uintptr)&ts;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* libcgo_sys_thread_start set stackguard to stack size;
|
|
|
|
* change to actual guard pointer.
|
|
|
|
*/
|
|
|
|
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
|
|
|
|
|
|
|
|
pthread_setspecific(k1, (void*)ts.g);
|
|
|
|
pthread_setspecific(k2, (void*)ts.m);
|
|
|
|
|
|
|
|
crosscall_amd64(ts.fn);
|
|
|
|
return nil;
|
|
|
|
}
|