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
|
145
|
19 bool runtime_usestackmaps;
|
|
20
|
111
|
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
|
145
|
25 extern void scanstackblock(uintptr addr, uintptr size, void *gcw)
|
111
|
26 __asm__("runtime.scanstackblock");
|
|
27
|
145
|
28 static bool doscanstack1(G*, void*)
|
111
|
29 __attribute__ ((noinline));
|
|
30
|
|
31 // Scan gp's stack, passing stack chunks to scanstackblock.
|
145
|
32 bool doscanstack(G *gp, void* gcw) {
|
111
|
33 // Save registers on the stack, so that if we are scanning our
|
|
34 // own stack we will see them.
|
145
|
35 if (!runtime_usestackmaps) {
|
|
36 __builtin_unwind_init();
|
|
37 flush_registers_to_secondary_stack();
|
|
38 }
|
111
|
39
|
145
|
40 return doscanstack1(gp, gcw);
|
111
|
41 }
|
|
42
|
|
43 // Scan gp's stack after saving registers.
|
145
|
44 static bool doscanstack1(G *gp, void *gcw) {
|
111
|
45 #ifdef USING_SPLIT_STACK
|
|
46 void* sp;
|
|
47 size_t spsize;
|
|
48 void* next_segment;
|
|
49 void* next_sp;
|
|
50 void* initial_sp;
|
145
|
51 G* _g_;
|
111
|
52
|
145
|
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) {
|
111
|
62 // Scanning our own stack.
|
145
|
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.
|
111
|
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) {
|
145
|
89 scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw);
|
111
|
90 while((sp = __splitstack_find(next_segment, next_sp,
|
|
91 &spsize, &next_segment,
|
|
92 &next_sp, &initial_sp)) != nil)
|
145
|
93 scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw);
|
111
|
94 }
|
|
95 #else
|
|
96 byte* bottom;
|
|
97 byte* top;
|
131
|
98 byte* nextsp2;
|
|
99 byte* initialsp2;
|
111
|
100
|
|
101 if(gp == runtime_g()) {
|
|
102 // Scanning our own stack.
|
|
103 bottom = (byte*)&gp;
|
131
|
104 nextsp2 = secondary_stack_pointer();
|
111
|
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)
|
145
|
110 return true;
|
131
|
111 nextsp2 = (void*)gp->gcnextsp2;
|
111
|
112 }
|
|
113 top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
|
|
114 if(top > bottom)
|
145
|
115 scanstackblock((uintptr)(bottom), (uintptr)(top - bottom), gcw);
|
111
|
116 else
|
145
|
117 scanstackblock((uintptr)(top), (uintptr)(bottom - top), gcw);
|
131
|
118 if (nextsp2 != nil) {
|
|
119 initialsp2 = (byte*)(void*)(gp->gcinitialsp2);
|
|
120 if(initialsp2 > nextsp2)
|
145
|
121 scanstackblock((uintptr)(nextsp2), (uintptr)(initialsp2 - nextsp2), gcw);
|
131
|
122 else
|
145
|
123 scanstackblock((uintptr)(initialsp2), (uintptr)(nextsp2 - initialsp2), gcw);
|
131
|
124 }
|
111
|
125 #endif
|
145
|
126 return true;
|
111
|
127 }
|