github.com/aloncn/graphics-go@v0.0.1/src/runtime/cgo/gcc_darwin_arm64.c (about) 1 // Copyright 2014 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 <limits.h> 8 #include <pthread.h> 9 #include <signal.h> 10 #include <string.h> /* for strerror */ 11 #include <sys/param.h> 12 #include <unistd.h> 13 #include <stdlib.h> 14 15 #include "libcgo.h" 16 17 #include <CoreFoundation/CFBundle.h> 18 #include <CoreFoundation/CFString.h> 19 20 #define magic (0xc476c475c47957UL) 21 22 // inittls allocates a thread-local storage slot for g. 23 // 24 // It finds the first available slot using pthread_key_create and uses 25 // it as the offset value for runtime.tlsg. 26 static void 27 inittls(void **tlsg, void **tlsbase) 28 { 29 pthread_key_t k; 30 int i, err; 31 32 err = pthread_key_create(&k, nil); 33 if(err != 0) { 34 fprintf(stderr, "runtime/cgo: pthread_key_create failed: %d\n", err); 35 abort(); 36 } 37 //fprintf(stderr, "runtime/cgo: k = %d, tlsbase = %p\n", (int)k, tlsbase); // debug 38 pthread_setspecific(k, (void*)magic); 39 // The first key should be at 257. 40 for (i=0; i<PTHREAD_KEYS_MAX; i++) { 41 if (*(tlsbase+i) == (void*)magic) { 42 *tlsg = (void*)(i*sizeof(void *)); 43 pthread_setspecific(k, 0); 44 return; 45 } 46 } 47 fprintf(stderr, "runtime/cgo: could not find pthread key.\n"); 48 abort(); 49 } 50 51 static void *threadentry(void*); 52 void (*setg_gcc)(void*); 53 54 void 55 _cgo_sys_thread_start(ThreadStart *ts) 56 { 57 pthread_attr_t attr; 58 sigset_t ign, oset; 59 pthread_t p; 60 size_t size; 61 int err; 62 63 //fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug 64 sigfillset(&ign); 65 pthread_sigmask(SIG_SETMASK, &ign, &oset); 66 67 pthread_attr_init(&attr); 68 size = 0; 69 pthread_attr_getstacksize(&attr, &size); 70 // Leave stacklo=0 and set stackhi=size; mstack will do the rest. 71 ts->g->stackhi = size; 72 err = pthread_create(&p, &attr, threadentry, ts); 73 74 pthread_sigmask(SIG_SETMASK, &oset, nil); 75 76 if (err != 0) { 77 fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err)); 78 abort(); 79 } 80 } 81 82 extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g); 83 static void* 84 threadentry(void *v) 85 { 86 ThreadStart ts; 87 88 ts = *(ThreadStart*)v; 89 free(v); 90 91 darwin_arm_init_thread_exception_port(); 92 93 crosscall1(ts.fn, setg_gcc, (void*)ts.g); 94 return nil; 95 } 96 97 // init_working_dir sets the current working directory to the app root. 98 // By default darwin/arm processes start in "/". 99 static void 100 init_working_dir() 101 { 102 CFBundleRef bundle = CFBundleGetMainBundle(); 103 if (bundle == NULL) { 104 fprintf(stderr, "runtime/cgo: no main bundle\n"); 105 return; 106 } 107 CFURLRef url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL); 108 if (url_ref == NULL) { 109 fprintf(stderr, "runtime/cgo: no Info.plist URL\n"); 110 return; 111 } 112 CFStringRef url_str_ref = CFURLGetString(url_ref); 113 char url[MAXPATHLEN]; 114 if (!CFStringGetCString(url_str_ref, url, sizeof(url), kCFStringEncodingUTF8)) { 115 fprintf(stderr, "runtime/cgo: cannot get URL string\n"); 116 return; 117 } 118 119 // url is of the form "file:///path/to/Info.plist". 120 // strip it down to the working directory "/path/to". 121 int url_len = strlen(url); 122 if (url_len < sizeof("file://")+sizeof("/Info.plist")) { 123 fprintf(stderr, "runtime/cgo: bad URL: %s\n", url); 124 return; 125 } 126 url[url_len-sizeof("/Info.plist")+1] = 0; 127 char *dir = &url[0] + sizeof("file://")-1; 128 129 if (chdir(dir) != 0) { 130 fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir); 131 } 132 133 // No-op to set a breakpoint on, immediately after the real chdir. 134 // Gives the test harness in go_darwin_arm_exec (which uses lldb) a 135 // chance to move the working directory. 136 getwd(dir); 137 } 138 139 void 140 x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) 141 { 142 pthread_attr_t attr; 143 size_t size; 144 145 //fprintf(stderr, "x_cgo_init = %p\n", &x_cgo_init); // aid debugging in presence of ASLR 146 setg_gcc = setg; 147 pthread_attr_init(&attr); 148 pthread_attr_getstacksize(&attr, &size); 149 g->stacklo = (uintptr)&attr - size + 4096; 150 pthread_attr_destroy(&attr); 151 152 // yes, tlsbase from mrs might not be correctly aligned. 153 inittls(tlsg, (void**)((uintptr)tlsbase & ~7)); 154 155 darwin_arm_init_mach_exception_handler(); 156 darwin_arm_init_thread_exception_port(); 157 158 init_working_dir(); 159 }