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