...
Source file
src/runtime/debugcall.go
Documentation: runtime
1
2
3
4
5
6
7
8 package runtime
9
10 import "unsafe"
11
12 const (
13 debugCallSystemStack = "executing on Go runtime stack"
14 debugCallUnknownFunc = "call from unknown function"
15 debugCallRuntime = "call from within the Go runtime"
16 debugCallUnsafePoint = "call not at safe point"
17 )
18
19 func debugCallV2()
20 func debugCallPanicked(val interface{})
21
22
23
24
25
26
27 func debugCallCheck(pc uintptr) string {
28
29 if getg() != getg().m.curg {
30 return debugCallSystemStack
31 }
32 if sp := getcallersp(); !(getg().stack.lo < sp && sp <= getg().stack.hi) {
33
34
35
36
37 return debugCallSystemStack
38 }
39
40
41
42 var ret string
43 systemstack(func() {
44 f := findfunc(pc)
45 if !f.valid() {
46 ret = debugCallUnknownFunc
47 return
48 }
49
50 name := funcname(f)
51
52 switch name {
53 case "debugCall32",
54 "debugCall64",
55 "debugCall128",
56 "debugCall256",
57 "debugCall512",
58 "debugCall1024",
59 "debugCall2048",
60 "debugCall4096",
61 "debugCall8192",
62 "debugCall16384",
63 "debugCall32768",
64 "debugCall65536":
65
66
67 return
68 }
69
70
71
72
73
74
75 if pfx := "runtime."; len(name) > len(pfx) && name[:len(pfx)] == pfx {
76 ret = debugCallRuntime
77 return
78 }
79
80
81 if pc != f.entry {
82 pc--
83 }
84 up := pcdatavalue(f, _PCDATA_UnsafePoint, pc, nil)
85 if up != _PCDATA_UnsafePointSafe {
86
87 ret = debugCallUnsafePoint
88 }
89 })
90 return ret
91 }
92
93
94
95
96
97
98
99
100
101
102 func debugCallWrap(dispatch uintptr) {
103 var lockedm bool
104 var lockedExt uint32
105 callerpc := getcallerpc()
106 gp := getg()
107
108
109
110 systemstack(func() {
111
112
113
114 fn := debugCallWrap1
115 newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), nil, 0, gp, callerpc)
116 args := &debugCallWrapArgs{
117 dispatch: dispatch,
118 callingG: gp,
119 }
120 newg.param = unsafe.Pointer(args)
121
122
123
124 if gp.lockedm != 0 {
125
126 mp := gp.m
127 if mp != gp.lockedm.ptr() {
128 throw("inconsistent lockedm")
129 }
130
131 lockedm = true
132 lockedExt = mp.lockedExt
133
134
135
136 mp.lockedInt++
137 mp.lockedExt = 0
138
139 mp.lockedg.set(newg)
140 newg.lockedm.set(mp)
141 gp.lockedm = 0
142 }
143
144
145
146
147
148 gp.asyncSafePoint = true
149
150
151
152 gp.schedlink.set(newg)
153 })
154
155
156 mcall(func(gp *g) {
157
158 newg := gp.schedlink.ptr()
159 gp.schedlink = 0
160
161
162 gp.waitreason = waitReasonDebugCall
163 if trace.enabled {
164 traceGoPark(traceEvGoBlock, 1)
165 }
166 casgstatus(gp, _Grunning, _Gwaiting)
167 dropg()
168
169
170
171
172
173 execute(newg, true)
174 })
175
176
177
178
179 if lockedm {
180 mp := gp.m
181 mp.lockedExt = lockedExt
182 mp.lockedInt--
183 mp.lockedg.set(gp)
184 gp.lockedm.set(mp)
185 }
186
187 gp.asyncSafePoint = false
188 }
189
190 type debugCallWrapArgs struct {
191 dispatch uintptr
192 callingG *g
193 }
194
195
196
197 func debugCallWrap1() {
198 gp := getg()
199 args := (*debugCallWrapArgs)(gp.param)
200 dispatch, callingG := args.dispatch, args.callingG
201 gp.param = nil
202
203
204 debugCallWrap2(dispatch)
205
206
207 getg().schedlink.set(callingG)
208 mcall(func(gp *g) {
209 callingG := gp.schedlink.ptr()
210 gp.schedlink = 0
211
212
213
214 if gp.lockedm != 0 {
215 gp.lockedm = 0
216 gp.m.lockedg = 0
217 }
218
219
220
221
222 if trace.enabled {
223 traceGoSched()
224 }
225 casgstatus(gp, _Grunning, _Grunnable)
226 dropg()
227 lock(&sched.lock)
228 globrunqput(gp)
229 unlock(&sched.lock)
230
231 if trace.enabled {
232 traceGoUnpark(callingG, 0)
233 }
234 casgstatus(callingG, _Gwaiting, _Grunnable)
235 execute(callingG, true)
236 })
237 }
238
239 func debugCallWrap2(dispatch uintptr) {
240
241 var dispatchF func()
242 dispatchFV := funcval{dispatch}
243 *(*unsafe.Pointer)(unsafe.Pointer(&dispatchF)) = noescape(unsafe.Pointer(&dispatchFV))
244
245 var ok bool
246 defer func() {
247 if !ok {
248 err := recover()
249 debugCallPanicked(err)
250 }
251 }()
252 dispatchF()
253 ok = true
254 }
255
View as plain text