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 void doscanstack(G
*, void*)
27 __asm__("runtime.doscanstack");
29 static void doscanstack1(G
*, void*)
30 __attribute__ ((noinline
));
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 flush_registers_to_secondary_stack();
39 doscanstack1(gp
, gcw
);
42 // Scan gp's stack after saving registers.
43 static void doscanstack1(G
*gp
, void *gcw
) {
44 #ifdef USING_SPLIT_STACK
51 if (gp
== runtime_g()) {
52 // Scanning our own stack.
53 sp
= __splitstack_find(nil
, nil
, &spsize
, &next_segment
,
54 &next_sp
, &initial_sp
);
56 // Scanning another goroutine's stack.
57 // The goroutine is usually asleep (the world is stopped).
59 // The exception is that if the goroutine is about to enter or might
60 // have just exited a system call, it may be executing code such
61 // as schedlock and may have needed to start a new stack segment.
62 // Use the stack segment and stack pointer at the time of
63 // the system call instead, since that won't change underfoot.
64 if(gp
->gcstack
!= 0) {
65 sp
= (void*)(gp
->gcstack
);
66 spsize
= gp
->gcstacksize
;
67 next_segment
= (void*)(gp
->gcnextsegment
);
68 next_sp
= (void*)(gp
->gcnextsp
);
69 initial_sp
= (void*)(gp
->gcinitialsp
);
71 sp
= __splitstack_find_context((void**)(&gp
->stackcontext
[0]),
72 &spsize
, &next_segment
,
73 &next_sp
, &initial_sp
);
77 scanstackblock(sp
, (uintptr
)(spsize
), gcw
);
78 while((sp
= __splitstack_find(next_segment
, next_sp
,
79 &spsize
, &next_segment
,
80 &next_sp
, &initial_sp
)) != nil
)
81 scanstackblock(sp
, (uintptr
)(spsize
), gcw
);
89 if(gp
== runtime_g()) {
90 // Scanning our own stack.
92 nextsp2
= secondary_stack_pointer();
94 // Scanning another goroutine's stack.
95 // The goroutine is usually asleep (the world is stopped).
96 bottom
= (void*)gp
->gcnextsp
;
99 nextsp2
= (void*)gp
->gcnextsp2
;
101 top
= (byte
*)(void*)(gp
->gcinitialsp
) + gp
->gcstacksize
;
103 scanstackblock(bottom
, (uintptr
)(top
- bottom
), gcw
);
105 scanstackblock(top
, (uintptr
)(bottom
- top
), gcw
);
106 if (nextsp2
!= nil
) {
107 initialsp2
= (byte
*)(void*)(gp
->gcinitialsp2
);
108 if(initialsp2
> nextsp2
)
109 scanstackblock(nextsp2
, (uintptr
)(initialsp2
- nextsp2
), gcw
);
111 scanstackblock(initialsp2
, (uintptr
)(nextsp2
- initialsp2
), gcw
);