]>
Commit | Line | Data |
---|---|---|
f163907e ILT |
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 | ||
b4b7464b ILT |
19 | bool runtime_usestackmaps; |
20 | ||
f163907e ILT |
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 | ||
8a9f2a6b | 25 | extern void scanstackblock(uintptr addr, uintptr size, void *gcw) |
c5b21c3f | 26 | __asm__(GOSYM_PREFIX "runtime.scanstackblock"); |
f163907e | 27 | |
c43137e8 | 28 | static bool doscanstack1(G*, void*) |
f163907e ILT |
29 | __attribute__ ((noinline)); |
30 | ||
31 | // Scan gp's stack, passing stack chunks to scanstackblock. | |
c43137e8 | 32 | bool doscanstack(G *gp, void* gcw) { |
f163907e ILT |
33 | // Save registers on the stack, so that if we are scanning our |
34 | // own stack we will see them. | |
c43137e8 ILT |
35 | if (!runtime_usestackmaps) { |
36 | __builtin_unwind_init(); | |
37 | flush_registers_to_secondary_stack(); | |
38 | } | |
f163907e | 39 | |
c43137e8 | 40 | return doscanstack1(gp, gcw); |
f163907e ILT |
41 | } |
42 | ||
43 | // Scan gp's stack after saving registers. | |
c43137e8 | 44 | static bool doscanstack1(G *gp, void *gcw) { |
f163907e ILT |
45 | #ifdef USING_SPLIT_STACK |
46 | void* sp; | |
47 | size_t spsize; | |
48 | void* next_segment; | |
49 | void* next_sp; | |
50 | void* initial_sp; | |
c43137e8 ILT |
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) { | |
f163907e | 62 | // Scanning our own stack. |
c43137e8 ILT |
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. | |
f163907e ILT |
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. | |
3b0ddadf ILT |
76 | if(gp->gcstack != 0) { |
77 | sp = (void*)(gp->gcstack); | |
f163907e | 78 | spsize = gp->gcstacksize; |
3b0ddadf ILT |
79 | next_segment = (void*)(gp->gcnextsegment); |
80 | next_sp = (void*)(gp->gcnextsp); | |
81 | initial_sp = (void*)(gp->gcinitialsp); | |
f163907e ILT |
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) { | |
8a9f2a6b | 89 | scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw); |
f163907e ILT |
90 | while((sp = __splitstack_find(next_segment, next_sp, |
91 | &spsize, &next_segment, | |
92 | &next_sp, &initial_sp)) != nil) | |
8a9f2a6b | 93 | scanstackblock((uintptr)(sp), (uintptr)(spsize), gcw); |
f163907e ILT |
94 | } |
95 | #else | |
f163907e ILT |
96 | byte* bottom; |
97 | byte* top; | |
38f08ec0 ILT |
98 | byte* nextsp2; |
99 | byte* initialsp2; | |
f163907e ILT |
100 | |
101 | if(gp == runtime_g()) { | |
102 | // Scanning our own stack. | |
103 | bottom = (byte*)&gp; | |
38f08ec0 | 104 | nextsp2 = secondary_stack_pointer(); |
f163907e ILT |
105 | } else { |
106 | // Scanning another goroutine's stack. | |
107 | // The goroutine is usually asleep (the world is stopped). | |
3b0ddadf | 108 | bottom = (void*)gp->gcnextsp; |
f163907e | 109 | if(bottom == nil) |
c43137e8 | 110 | return true; |
38f08ec0 | 111 | nextsp2 = (void*)gp->gcnextsp2; |
f163907e | 112 | } |
3b0ddadf | 113 | top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize; |
f163907e | 114 | if(top > bottom) |
d86dd249 | 115 | scanstackblock((uintptr)(bottom), (uintptr)(top - bottom), gcw); |
f163907e | 116 | else |
d86dd249 | 117 | scanstackblock((uintptr)(top), (uintptr)(bottom - top), gcw); |
38f08ec0 ILT |
118 | if (nextsp2 != nil) { |
119 | initialsp2 = (byte*)(void*)(gp->gcinitialsp2); | |
120 | if(initialsp2 > nextsp2) | |
d86dd249 | 121 | scanstackblock((uintptr)(nextsp2), (uintptr)(initialsp2 - nextsp2), gcw); |
38f08ec0 | 122 | else |
d86dd249 | 123 | scanstackblock((uintptr)(initialsp2), (uintptr)(nextsp2 - initialsp2), gcw); |
38f08ec0 | 124 | } |
f163907e | 125 | #endif |
c43137e8 | 126 | return true; |
f163907e | 127 | } |
c5b21c3f ILT |
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); | |
e5c00544 | 177 | if ((uintptr)(initialsp2) < (uintptr)(nextsp2)) { |
c5b21c3f ILT |
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 | } |