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();
38 doscanstack1(gp
, gcw
);
41 // Scan gp's stack after saving registers.
42 static void doscanstack1(G
*gp
, void *gcw
) {
43 #ifdef USING_SPLIT_STACK
50 if (gp
== runtime_g()) {
51 // Scanning our own stack.
52 sp
= __splitstack_find(nil
, nil
, &spsize
, &next_segment
,
53 &next_sp
, &initial_sp
);
55 // Scanning another goroutine's stack.
56 // The goroutine is usually asleep (the world is stopped).
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
);
70 sp
= __splitstack_find_context((void**)(&gp
->stackcontext
[0]),
71 &spsize
, &next_segment
,
72 &next_sp
, &initial_sp
);
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
);
86 if(gp
== runtime_g()) {
87 // Scanning our own stack.
90 // Scanning another goroutine's stack.
91 // The goroutine is usually asleep (the world is stopped).
92 bottom
= (void*)gp
->gcnextsp
;
96 top
= (byte
*)(void*)(gp
->gcinitialsp
) + gp
->gcstacksize
;
98 scanstackblock(bottom
, (uintptr
)(top
- bottom
), gcw
);
100 scanstackblock(top
, (uintptr
)(bottom
- top
), gcw
);