github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/cgo/gcc_netbsd_arm.c (about) 1 // Copyright 2013 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 <sys/types.h> 6 #include <pthread.h> 7 #include <signal.h> 8 #include <string.h> 9 #include "libcgo.h" 10 11 static void *threadentry(void*); 12 13 // We have to resort to TLS variable to save g(R10) and 14 // m(R9). One reason is that external code might trigger 15 // SIGSEGV, and our runtime.sigtramp don't even know we 16 // are in external code, and will continue to use R10/R9, 17 // this might as well result in another SIGSEGV. 18 // Note: all three functions will clobber R0, and the last 19 // two can be called from 5c ABI code. 20 void __aeabi_read_tp(void) __attribute__((naked)); 21 void x_cgo_save_gm(void) __attribute__((naked)); 22 void x_cgo_load_gm(void) __attribute__((naked)); 23 24 void 25 __aeabi_read_tp(void) 26 { 27 // this function is only allowed to clobber r0 28 __asm__ __volatile__ ( 29 "mrc p15, 0, r0, c13, c0, 3\n\t" 30 "cmp r0, #0\n\t" 31 "movne pc, lr\n\t" 32 "push {r1,r2,r3,r12}\n\t" 33 "svc 0x00a0013c\n\t" // _lwp_getprivate 34 "pop {r1,r2,r3,r12}\n\t" 35 "mov pc, lr\n\t" 36 ); 37 } 38 39 // g (R10) at 8(TP), m (R9) at 12(TP) 40 void 41 x_cgo_load_gm(void) 42 { 43 __asm__ __volatile__ ( 44 "push {lr}\n\t" 45 "bl __aeabi_read_tp\n\t" 46 "ldr r10, [r0, #8]\n\t" 47 "ldr r9, [r0, #12]\n\t" 48 "pop {pc}\n\t" 49 ); 50 } 51 52 void 53 x_cgo_save_gm(void) 54 { 55 __asm__ __volatile__ ( 56 "push {lr}\n\t" 57 "bl __aeabi_read_tp\n\t" 58 "str r10, [r0, #8]\n\t" 59 "str r9, [r0, #12]\n\t" 60 "pop {pc}\n\t" 61 ); 62 } 63 64 void 65 x_cgo_init(G *g) 66 { 67 pthread_attr_t attr; 68 size_t size; 69 x_cgo_save_gm(); // save g and m for the initial thread 70 71 pthread_attr_init(&attr); 72 pthread_attr_getstacksize(&attr, &size); 73 g->stackguard = (uintptr)&attr - size + 4096; 74 pthread_attr_destroy(&attr); 75 } 76 77 78 void 79 _cgo_sys_thread_start(ThreadStart *ts) 80 { 81 pthread_attr_t attr; 82 sigset_t ign, oset; 83 pthread_t p; 84 size_t size; 85 int err; 86 87 sigfillset(&ign); 88 sigprocmask(SIG_SETMASK, &ign, &oset); 89 90 pthread_attr_init(&attr); 91 pthread_attr_getstacksize(&attr, &size); 92 ts->g->stackguard = size; 93 err = pthread_create(&p, &attr, threadentry, ts); 94 95 sigprocmask(SIG_SETMASK, &oset, nil); 96 97 if (err != 0) { 98 fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err)); 99 abort(); 100 } 101 } 102 103 extern void crosscall_arm2(void (*fn)(void), void *g, void *m); 104 static void* 105 threadentry(void *v) 106 { 107 ThreadStart ts; 108 109 ts = *(ThreadStart*)v; 110 free(v); 111 112 ts.g->stackbase = (uintptr)&ts; 113 114 /* 115 * _cgo_sys_thread_start set stackguard to stack size; 116 * change to actual guard pointer. 117 */ 118 ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2; 119 120 crosscall_arm2(ts.fn, (void *)ts.g, (void *)ts.m); 121 return nil; 122 }