github.com/fenixara/go@v0.0.0-20170127160404-96ea0918e670/src/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  #include "libcgo_unix.h"
    10  
    11  static void* threadentry(void*);
    12  static pthread_key_t k1;
    13  
    14  #define magic1 (0x23581321345589ULL)
    15  
    16  static void
    17  inittls(void)
    18  {
    19  	uint64 x;
    20  	pthread_key_t tofree[128], k;
    21  	int i, ntofree;
    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 offset is
    27  	 * 0x60+8*0x108 = 0x8a0.
    28  	 *
    29  	 * The linker and runtime hard-code this constant offset
    30  	 * from %gs where we expect to find g.
    31  	 * Known to ../../../liblink/sym.c:/8a0
    32  	 * and to ../sys_darwin_amd64.s:/8a0
    33  	 *
    34  	 * As disgusting as on the 386; same justification.
    35  	 */
    36  	ntofree = 0;
    37  	for(;;) {
    38  		if(pthread_key_create(&k, nil) < 0) {
    39  			fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
    40  			abort();
    41  		}
    42  		pthread_setspecific(k, (void*)magic1);
    43  		asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
    44  		pthread_setspecific(k, 0);
    45  		if(x == magic1) {
    46  			k1 = k;
    47  			break;
    48  		}
    49  		if(ntofree >= nelem(tofree)) {
    50  			fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
    51  			fprintf(stderr, "\ttried");
    52  			for(i=0; i<ntofree; i++)
    53  				fprintf(stderr, " %#x", (unsigned)tofree[i]);
    54  			fprintf(stderr, "\n");
    55  			abort();
    56  		}
    57  		tofree[ntofree++] = k;
    58  	}
    59  
    60  	/*
    61  	 * We got the key we wanted.  Free the others.
    62  	 */
    63  	for(i=0; i<ntofree; i++)
    64  		pthread_key_delete(tofree[i]);
    65  }
    66  
    67  void
    68  x_cgo_init(G *g)
    69  {
    70  	pthread_attr_t attr;
    71  	size_t size;
    72  
    73  	pthread_attr_init(&attr);
    74  	pthread_attr_getstacksize(&attr, &size);
    75  	g->stacklo = (uintptr)&attr - size + 4096;
    76  	pthread_attr_destroy(&attr);
    77  
    78  	inittls();
    79  }
    80  
    81  
    82  void
    83  _cgo_sys_thread_start(ThreadStart *ts)
    84  {
    85  	pthread_attr_t attr;
    86  	sigset_t ign, oset;
    87  	pthread_t p;
    88  	size_t size;
    89  	int err;
    90  
    91  	sigfillset(&ign);
    92  	pthread_sigmask(SIG_SETMASK, &ign, &oset);
    93  
    94  	pthread_attr_init(&attr);
    95  	pthread_attr_getstacksize(&attr, &size);
    96  	// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
    97  	ts->g->stackhi = size;
    98  	err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
    99  
   100  	pthread_sigmask(SIG_SETMASK, &oset, nil);
   101  
   102  	if (err != 0) {
   103  		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
   104  		abort();
   105  	}
   106  }
   107  
   108  static void*
   109  threadentry(void *v)
   110  {
   111  	ThreadStart ts;
   112  
   113  	ts = *(ThreadStart*)v;
   114  	free(v);
   115  
   116  	pthread_setspecific(k1, (void*)ts.g);
   117  
   118  	crosscall_amd64(ts.fn);
   119  	return nil;
   120  }