111
|
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 // Calling unwind_init in doscanstack only works if it does not do a
|
|
20 // tail call to doscanstack1.
|
|
21 #pragma GCC optimize ("-fno-optimize-sibling-calls")
|
|
22
|
|
23 extern void scanstackblock(void *addr, uintptr size, void *gcw)
|
|
24 __asm__("runtime.scanstackblock");
|
|
25
|
|
26 void doscanstack(G*, void*)
|
|
27 __asm__("runtime.doscanstack");
|
|
28
|
|
29 static void doscanstack1(G*, void*)
|
|
30 __attribute__ ((noinline));
|
|
31
|
|
32 // Scan gp's stack, passing stack chunks to scanstackblock.
|
|
33 void doscanstack(G *gp, void* gcw) {
|
|
34 // Save registers on the stack, so that if we are scanning our
|
|
35 // own stack we will see them.
|
|
36 __builtin_unwind_init();
|
|
37
|
|
38 doscanstack1(gp, gcw);
|
|
39 }
|
|
40
|
|
41 // Scan gp's stack after saving registers.
|
|
42 static void doscanstack1(G *gp, void *gcw) {
|
|
43 #ifdef USING_SPLIT_STACK
|
|
44 void* sp;
|
|
45 size_t spsize;
|
|
46 void* next_segment;
|
|
47 void* next_sp;
|
|
48 void* initial_sp;
|
|
49
|
|
50 if (gp == runtime_g()) {
|
|
51 // Scanning our own stack.
|
|
52 sp = __splitstack_find(nil, nil, &spsize, &next_segment,
|
|
53 &next_sp, &initial_sp);
|
|
54 } else {
|
|
55 // Scanning another goroutine's stack.
|
|
56 // The goroutine is usually asleep (the world is stopped).
|
|
57
|
|
58 // The exception is that if the goroutine is about to enter or might
|
|
59 // have just exited a system call, it may be executing code such
|
|
60 // as schedlock and may have needed to start a new stack segment.
|
|
61 // Use the stack segment and stack pointer at the time of
|
|
62 // the system call instead, since that won't change underfoot.
|
|
63 if(gp->gcstack != 0) {
|
|
64 sp = (void*)(gp->gcstack);
|
|
65 spsize = gp->gcstacksize;
|
|
66 next_segment = (void*)(gp->gcnextsegment);
|
|
67 next_sp = (void*)(gp->gcnextsp);
|
|
68 initial_sp = (void*)(gp->gcinitialsp);
|
|
69 } else {
|
|
70 sp = __splitstack_find_context((void**)(&gp->stackcontext[0]),
|
|
71 &spsize, &next_segment,
|
|
72 &next_sp, &initial_sp);
|
|
73 }
|
|
74 }
|
|
75 if(sp != nil) {
|
|
76 scanstackblock(sp, (uintptr)(spsize), gcw);
|
|
77 while((sp = __splitstack_find(next_segment, next_sp,
|
|
78 &spsize, &next_segment,
|
|
79 &next_sp, &initial_sp)) != nil)
|
|
80 scanstackblock(sp, (uintptr)(spsize), gcw);
|
|
81 }
|
|
82 #else
|
|
83 byte* bottom;
|
|
84 byte* top;
|
|
85
|
|
86 if(gp == runtime_g()) {
|
|
87 // Scanning our own stack.
|
|
88 bottom = (byte*)&gp;
|
|
89 } else {
|
|
90 // Scanning another goroutine's stack.
|
|
91 // The goroutine is usually asleep (the world is stopped).
|
|
92 bottom = (void*)gp->gcnextsp;
|
|
93 if(bottom == nil)
|
|
94 return;
|
|
95 }
|
|
96 top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
|
|
97 if(top > bottom)
|
|
98 scanstackblock(bottom, (uintptr)(top - bottom), gcw);
|
|
99 else
|
|
100 scanstackblock(top, (uintptr)(bottom - top), gcw);
|
|
101 #endif
|
|
102 }
|