123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Stack scanning code for the garbage collector.
- #include "runtime.h"
- #ifdef USING_SPLIT_STACK
- extern void * __splitstack_find (void *, void *, size_t *, void **, void **,
- void **);
- extern void * __splitstack_find_context (void *context[10], size_t *, void **,
- void **, void **);
- #endif
- bool runtime_usestackmaps;
- // Calling unwind_init in doscanstack only works if it does not do a
- // tail call to doscanstack1.
- #pragma GCC optimize ("-fno-optimize-sibling-calls")
- extern void scanstackblock(uintptr addr, uintptr size, void *gcw)
- __asm__(GOSYM_PREFIX "runtime.scanstackblock");
- static bool doscanstack1(G*, void*)
- __attribute__ ((noinline));
- // Scan gp's stack, passing stack chunks to scanstackblock.
- bool doscanstack(G *gp, void* gcw) {
- // Save registers on the stack, so that if we are scanning our
- // own stack we will see them.
- if (!runtime_usestackmaps) {
- __builtin_unwind_init();
- flush_registers_to_secondary_stack();
- }
- return doscanstack1(gp, gcw);
- }
- // Scan gp's stack after saving registers.
- static bool doscanstack1(G *gp, void *gcw) {
- #ifdef USING_SPLIT_STACK
- void* sp;
- size_t spsize;
- void* next_segment;
- void* next_sp;
- void* initial_sp;
- G* _g_;
- _g_ = runtime_g();
- if (runtime_usestackmaps) {
- // If stack map is enabled, we get here only when we can unwind
- // the stack being scanned. That is, either we are scanning our
- // own stack, or we are scanning through a signal handler.
- __go_assert((_g_ == gp) || ((_g_ == gp->m->gsignal) && (gp == gp->m->curg)));
- return scanstackwithmap(gcw);
- }
- if (_g_ == gp) {
- // Scanning our own stack.
- // If we are on a signal stack, it can unwind through the signal
- // handler and see the g stack, so just scan our own stack.
- sp = __splitstack_find(nil, nil, &spsize, &next_segment,
- &next_sp, &initial_sp);
- } else {
- // Scanning another goroutine's stack.
- // The goroutine is usually asleep (the world is stopped).
- // The exception is that if the goroutine is about to enter or might
- // have just exited a system call, it may be executing code such
- // as schedlock and may have needed to start a new stack segment.
- // Use the stack segment and stack pointer at the time of
- // the system call instead, since that won't change underfoot.
- if(gp->gcstack != 0) {
- sp = (void*)(gp->gcstack);
- spsize = gp->gcstacksize;
- next_segment = (void*)(gp->gcnextsegment);
- next_sp = (void*)(gp->gcnextsp);
- initial_sp = (void*)(gp->gcinitialsp);
- } else {
- sp = __splitstack_find_context((void**)(&gp->stackcontext[0]),
- &spsize, &next_segment,
- &next_sp, &initial_sp);
- }
- }
- if(sp != nil) {
- scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw);
- while((sp = __splitstack_find(next_segment, next_sp,
- &spsize, &next_segment,
- &next_sp, &initial_sp)) != nil)
- scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw);
- }
- #else
- byte* bottom;
- byte* top;
- byte* nextsp2;
- byte* initialsp2;
- if(gp == runtime_g()) {
- // Scanning our own stack.
- bottom = (byte*)&gp;
- nextsp2 = secondary_stack_pointer();
- } else {
- // Scanning another goroutine's stack.
- // The goroutine is usually asleep (the world is stopped).
- bottom = (void*)gp->gcnextsp;
- if(bottom == nil)
- return true;
- nextsp2 = (void*)gp->gcnextsp2;
- }
- top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
- if(top > bottom)
- scanstackblock((uintptr)(bottom), (uintptr)(top - bottom), gcw);
- else
- scanstackblock((uintptr)(top), (uintptr)(bottom - top), gcw);
- if (nextsp2 != nil) {
- initialsp2 = (byte*)(void*)(gp->gcinitialsp2);
- if(initialsp2 > nextsp2)
- scanstackblock((uintptr)(nextsp2), (uintptr)(initialsp2 - nextsp2), gcw);
- else
- scanstackblock((uintptr)(initialsp2), (uintptr)(nextsp2 - initialsp2), gcw);
- }
- #endif
- return true;
- }
- extern bool onCurrentStack(uintptr p)
- __asm__(GOSYM_PREFIX "runtime.onCurrentStack");
- bool onCurrentStack(uintptr p)
- {
- #ifdef USING_SPLIT_STACK
- void* sp;
- size_t spsize;
- void* next_segment;
- void* next_sp;
- void* initial_sp;
- sp = __splitstack_find(nil, nil, &spsize, &next_segment, &next_sp,
- &initial_sp);
- while (sp != nil) {
- if (p >= (uintptr)(sp) && p < (uintptr)(sp) + spsize) {
- return true;
- }
- sp = __splitstack_find(next_segment, next_sp, &spsize,
- &next_segment, &next_sp, &initial_sp);
- }
- return false;
- #else
- G* gp;
- byte* bottom;
- byte* top;
- byte* temp;
- byte* nextsp2;
- byte* initialsp2;
- gp = runtime_g();
- bottom = (byte*)(&p);
- top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
- if ((uintptr)(top) < (uintptr)(bottom)) {
- temp = top;
- top = bottom;
- bottom = temp;
- }
- if (p >= (uintptr)(bottom) && p < (uintptr)(top)) {
- return true;
- }
- nextsp2 = secondary_stack_pointer();
- if (nextsp2 != nil) {
- initialsp2 = (byte*)(void*)(gp->gcinitialsp2);
- if ((uintptr)(initialsp2) < (uintptr)(nextsp2)) {
- temp = initialsp2;
- initialsp2 = nextsp2;
- nextsp2 = temp;
- }
- if (p >= (uintptr)(nextsp2) && p < (uintptr)(initialsp2)) {
- return true;
- }
- }
- return false;
- #endif
- }
|