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