github.com/kidsbmilk/gofronted_all@v0.0.0-20220701224323-6479d5976c5d/libgo/runtime/stack.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 // Stack scanning code for the garbage collector. 6 7 #include "runtime.h" 8 9 #ifdef USING_SPLIT_STACK 10 11 extern void * __splitstack_find (void *, void *, size_t *, void **, void **, 12 void **); 13 14 extern void * __splitstack_find_context (void *context[10], size_t *, void **, 15 void **, void **); 16 17 #endif 18 19 bool runtime_usestackmaps; 20 21 // Calling unwind_init in doscanstack only works if it does not do a 22 // tail call to doscanstack1. 23 #pragma GCC optimize ("-fno-optimize-sibling-calls") 24 25 extern void scanstackblock(uintptr addr, uintptr size, void *gcw) 26 __asm__(GOSYM_PREFIX "runtime.scanstackblock"); 27 28 static bool doscanstack1(G*, void*) 29 __attribute__ ((noinline)); 30 31 // Scan gp's stack, passing stack chunks to scanstackblock. 32 bool doscanstack(G *gp, void* gcw) { 33 // Save registers on the stack, so that if we are scanning our 34 // own stack we will see them. 35 if (!runtime_usestackmaps) { 36 __builtin_unwind_init(); 37 flush_registers_to_secondary_stack(); 38 } 39 40 return doscanstack1(gp, gcw); 41 } 42 43 // Scan gp's stack after saving registers. 44 static bool doscanstack1(G *gp, void *gcw) { 45 #ifdef USING_SPLIT_STACK 46 void* sp; 47 size_t spsize; 48 void* next_segment; 49 void* next_sp; 50 void* initial_sp; 51 G* _g_; 52 53 _g_ = runtime_g(); 54 if (runtime_usestackmaps) { 55 // If stack map is enabled, we get here only when we can unwind 56 // the stack being scanned. That is, either we are scanning our 57 // own stack, or we are scanning through a signal handler. 58 __go_assert((_g_ == gp) || ((_g_ == gp->m->gsignal) && (gp == gp->m->curg))); 59 return scanstackwithmap(gcw); 60 } 61 if (_g_ == gp) { 62 // Scanning our own stack. 63 // If we are on a signal stack, it can unwind through the signal 64 // handler and see the g stack, so just scan our own stack. 65 sp = __splitstack_find(nil, nil, &spsize, &next_segment, 66 &next_sp, &initial_sp); 67 } else { 68 // Scanning another goroutine's stack. 69 // The goroutine is usually asleep (the world is stopped). 70 71 // The exception is that if the goroutine is about to enter or might 72 // have just exited a system call, it may be executing code such 73 // as schedlock and may have needed to start a new stack segment. 74 // Use the stack segment and stack pointer at the time of 75 // the system call instead, since that won't change underfoot. 76 if(gp->gcstack != 0) { 77 sp = (void*)(gp->gcstack); 78 spsize = gp->gcstacksize; 79 next_segment = (void*)(gp->gcnextsegment); 80 next_sp = (void*)(gp->gcnextsp); 81 initial_sp = (void*)(gp->gcinitialsp); 82 } else { 83 sp = __splitstack_find_context((void**)(&gp->stackcontext[0]), 84 &spsize, &next_segment, 85 &next_sp, &initial_sp); 86 } 87 } 88 if(sp != nil) { 89 scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw); 90 while((sp = __splitstack_find(next_segment, next_sp, 91 &spsize, &next_segment, 92 &next_sp, &initial_sp)) != nil) 93 scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw); 94 } 95 #else 96 byte* bottom; 97 byte* top; 98 byte* nextsp2; 99 byte* initialsp2; 100 101 if(gp == runtime_g()) { 102 // Scanning our own stack. 103 bottom = (byte*)&gp; 104 nextsp2 = secondary_stack_pointer(); 105 } else { 106 // Scanning another goroutine's stack. 107 // The goroutine is usually asleep (the world is stopped). 108 bottom = (void*)gp->gcnextsp; 109 if(bottom == nil) 110 return true; 111 nextsp2 = (void*)gp->gcnextsp2; 112 } 113 top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize; 114 if(top > bottom) 115 scanstackblock((uintptr)(bottom), (uintptr)(top - bottom), gcw); 116 else 117 scanstackblock((uintptr)(top), (uintptr)(bottom - top), gcw); 118 if (nextsp2 != nil) { 119 initialsp2 = (byte*)(void*)(gp->gcinitialsp2); 120 if(initialsp2 > nextsp2) 121 scanstackblock((uintptr)(nextsp2), (uintptr)(initialsp2 - nextsp2), gcw); 122 else 123 scanstackblock((uintptr)(initialsp2), (uintptr)(nextsp2 - initialsp2), gcw); 124 } 125 #endif 126 return true; 127 } 128 129 extern bool onCurrentStack(uintptr p) 130 __asm__(GOSYM_PREFIX "runtime.onCurrentStack"); 131 132 bool onCurrentStack(uintptr p) 133 { 134 #ifdef USING_SPLIT_STACK 135 136 void* sp; 137 size_t spsize; 138 void* next_segment; 139 void* next_sp; 140 void* initial_sp; 141 142 sp = __splitstack_find(nil, nil, &spsize, &next_segment, &next_sp, 143 &initial_sp); 144 while (sp != nil) { 145 if (p >= (uintptr)(sp) && p < (uintptr)(sp) + spsize) { 146 return true; 147 } 148 sp = __splitstack_find(next_segment, next_sp, &spsize, 149 &next_segment, &next_sp, &initial_sp); 150 } 151 return false; 152 153 #else 154 155 G* gp; 156 byte* bottom; 157 byte* top; 158 byte* temp; 159 byte* nextsp2; 160 byte* initialsp2; 161 162 gp = runtime_g(); 163 bottom = (byte*)(&p); 164 top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize; 165 if ((uintptr)(top) < (uintptr)(bottom)) { 166 temp = top; 167 top = bottom; 168 bottom = temp; 169 } 170 if (p >= (uintptr)(bottom) && p < (uintptr)(top)) { 171 return true; 172 } 173 174 nextsp2 = secondary_stack_pointer(); 175 if (nextsp2 != nil) { 176 initialsp2 = (byte*)(void*)(gp->gcinitialsp2); 177 if ((uintptr)(initialsp2) < (uintptr)(nextsp2)) { 178 temp = initialsp2; 179 initialsp2 = nextsp2; 180 nextsp2 = temp; 181 } 182 if (p >= (uintptr)(nextsp2) && p < (uintptr)(initialsp2)) { 183 return true; 184 } 185 } 186 187 return false; 188 189 #endif 190 }