190 lines · 5.1 KB · C
RawDownload
// 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}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t