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.
5 // Stack scanning code for the garbage collector.
9 #ifdef USING_SPLIT_STACK
11 extern void * __splitstack_find (void *, void *, size_t *, void **, void **,
14 extern void * __splitstack_find_context (void *context
[10], size_t *, void **,
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")
23 extern void scanstackblock(void *addr
, uintptr size
, void *gcw
)
24 __asm__("runtime.scanstackblock");
26 static bool doscanstack1(G
*, void*)
27 __attribute__ ((noinline
));
29 // Scan gp's stack, passing stack chunks to scanstackblock.
30 bool doscanstack(G
*gp
, void* gcw
) {
31 // Save registers on the stack, so that if we are scanning our
32 // own stack we will see them.
33 if (!runtime_usestackmaps
) {
34 __builtin_unwind_init();
35 flush_registers_to_secondary_stack();
38 return doscanstack1(gp
, gcw
);
41 // Scan gp's stack after saving registers.
42 static bool doscanstack1(G
*gp
, void *gcw
) {
43 #ifdef USING_SPLIT_STACK
52 if (runtime_usestackmaps
) {
53 // If stack map is enabled, we get here only when we can unwind
54 // the stack being scanned. That is, either we are scanning our
55 // own stack, or we are scanning through a signal handler.
56 __go_assert((_g_
== gp
) || ((_g_
== gp
->m
->gsignal
) && (gp
== gp
->m
->curg
)));
57 return scanstackwithmap(gcw
);
60 // Scanning our own stack.
61 // If we are on a signal stack, it can unwind through the signal
62 // handler and see the g stack, so just scan our own stack.
63 sp
= __splitstack_find(nil
, nil
, &spsize
, &next_segment
,
64 &next_sp
, &initial_sp
);
66 // Scanning another goroutine's stack.
67 // The goroutine is usually asleep (the world is stopped).
69 // The exception is that if the goroutine is about to enter or might
70 // have just exited a system call, it may be executing code such
71 // as schedlock and may have needed to start a new stack segment.
72 // Use the stack segment and stack pointer at the time of
73 // the system call instead, since that won't change underfoot.
74 if(gp
->gcstack
!= 0) {
75 sp
= (void*)(gp
->gcstack
);
76 spsize
= gp
->gcstacksize
;
77 next_segment
= (void*)(gp
->gcnextsegment
);
78 next_sp
= (void*)(gp
->gcnextsp
);
79 initial_sp
= (void*)(gp
->gcinitialsp
);
81 sp
= __splitstack_find_context((void**)(&gp
->stackcontext
[0]),
82 &spsize
, &next_segment
,
83 &next_sp
, &initial_sp
);
87 scanstackblock(sp
, (uintptr
)(spsize
), gcw
);
88 while((sp
= __splitstack_find(next_segment
, next_sp
,
89 &spsize
, &next_segment
,
90 &next_sp
, &initial_sp
)) != nil
)
91 scanstackblock(sp
, (uintptr
)(spsize
), gcw
);
99 if(gp
== runtime_g()) {
100 // Scanning our own stack.
102 nextsp2
= secondary_stack_pointer();
104 // Scanning another goroutine's stack.
105 // The goroutine is usually asleep (the world is stopped).
106 bottom
= (void*)gp
->gcnextsp
;
109 nextsp2
= (void*)gp
->gcnextsp2
;
111 top
= (byte
*)(void*)(gp
->gcinitialsp
) + gp
->gcstacksize
;
113 scanstackblock(bottom
, (uintptr
)(top
- bottom
), gcw
);
115 scanstackblock(top
, (uintptr
)(bottom
- top
), gcw
);
116 if (nextsp2
!= nil
) {
117 initialsp2
= (byte
*)(void*)(gp
->gcinitialsp2
);
118 if(initialsp2
> nextsp2
)
119 scanstackblock(nextsp2
, (uintptr
)(initialsp2
- nextsp2
), gcw
);
121 scanstackblock(initialsp2
, (uintptr
)(nextsp2
- initialsp2
), gcw
);