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