github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/runtime/cgo/gcc_darwin_amd64.c (about)

     1  // 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 <string.h> /* for strerror */
     6  #include <pthread.h>
     7  #include <signal.h>
     8  #include "libcgo.h"
     9  
    10  static void* threadentry(void*);
    11  static pthread_key_t k1, k2;
    12  
    13  #define magic1 (0x23581321345589ULL)
    14  
    15  static void
    16  inittls(void)
    17  {
    18  	uint64 x, y;
    19  	pthread_key_t tofree[128], k;
    20  	int i, ntofree;
    21  	int havek1, havek2;
    22  
    23  	/*
    24  	 * Same logic, code as darwin_386.c:/inittls, except that words
    25  	 * are 8 bytes long now, and the thread-local storage starts
    26  	 * at 0x60 on Leopard / Snow Leopard. So the offsets are
    27  	 * 0x60+8*0x108 = 0x8a0 and 0x60+8*0x109 = 0x8a8.
    28  	 *
    29  	 * The linker and runtime hard-code these constant offsets
    30  	 * from %gs where we expect to find m and g.
    31  	 * Known to ../../../cmd/6l/obj.c:/8a0
    32  	 * and to ../sys_darwin_amd64.s:/8a0
    33  	 *
    34  	 * As disgusting as on the 386; same justification.
    35  	 */
    36  	havek1 = 0;
    37  	havek2 = 0;
    38  	ntofree = 0;
    39  	while(!havek1 || !havek2) {
    40  		if(pthread_key_create(&k, nil) < 0) {
    41  			fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
    42  			abort();
    43  		}
    44  		pthread_setspecific(k, (void*)magic1);
    45  		asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
    46  		asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
    47  		if(x == magic1) {
    48  			havek1 = 1;
    49  			k1 = k;
    50  		} else if(y == magic1) {
    51  			havek2 = 1;
    52  			k2 = k;
    53  		} else {
    54  			if(ntofree >= nelem(tofree)) {
    55  				fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
    56  				fprintf(stderr, "\ttried");
    57  				for(i=0; i<ntofree; i++)
    58  					fprintf(stderr, " %#x", (unsigned)tofree[i]);
    59  				fprintf(stderr, "\n");
    60  				abort();
    61  			}
    62  			tofree[ntofree++] = k;
    63  		}
    64  		pthread_setspecific(k, 0);
    65  	}
    66  
    67  	/*
    68  	 * We got the keys we wanted.  Free the others.
    69  	 */
    70  	for(i=0; i<ntofree; i++)
    71  		pthread_key_delete(tofree[i]);
    72  }
    73  
    74  void
    75  x_cgo_init(G *g)
    76  {
    77  	pthread_attr_t attr;
    78  	size_t size;
    79  
    80  	pthread_attr_init(&attr);
    81  	pthread_attr_getstacksize(&attr, &size);
    82  	g->stackguard = (uintptr)&attr - size + 4096;
    83  	pthread_attr_destroy(&attr);
    84  
    85  	inittls();
    86  }
    87  
    88  
    89  void
    90  _cgo_sys_thread_start(ThreadStart *ts)
    91  {
    92  	pthread_attr_t attr;
    93  	sigset_t ign, oset;
    94  	pthread_t p;
    95  	size_t size;
    96  	int err;
    97  
    98  	sigfillset(&ign);
    99  	pthread_sigmask(SIG_SETMASK, &ign, &oset);
   100  
   101  	pthread_attr_init(&attr);
   102  	pthread_attr_getstacksize(&attr, &size);
   103  	ts->g->stackguard = size;
   104  	err = pthread_create(&p, &attr, threadentry, ts);
   105  
   106  	pthread_sigmask(SIG_SETMASK, &oset, nil);
   107  
   108  	if (err != 0) {
   109  		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
   110  		abort();
   111  	}
   112  }
   113  
   114  static void*
   115  threadentry(void *v)
   116  {
   117  	ThreadStart ts;
   118  
   119  	ts = *(ThreadStart*)v;
   120  	free(v);
   121  
   122  	ts.g->stackbase = (uintptr)&ts;
   123  
   124  	/*
   125  	 * _cgo_sys_thread_start set stackguard to stack size;
   126  	 * change to actual guard pointer.
   127  	 */
   128  	ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
   129  
   130  	pthread_setspecific(k1, (void*)ts.g);
   131  	pthread_setspecific(k2, (void*)ts.m);
   132  
   133  	crosscall_amd64(ts.fn);
   134  	return nil;
   135  }