13
13
uint32 runtime·panicking;
14
14
static Lock paniclk;
21
// Allocate a Defer, usually as part of the larger frame of deferred functions.
22
// Each defer must be released with both popdefer and freedefer.
16
// Each P holds pool for defers with arg sizes 8, 24, 40, 56 and 72 bytes.
17
// Memory block is 40 (24 for 32 bits) bytes larger due to Defer header.
18
// This maps exactly to malloc size classes.
20
// defer size class for arg size sz
21
#define DEFERCLASS(sz) (((sz)+7)>>4)
22
// total size of memory block for defer with arg size sz
23
#define TOTALSIZE(sz) (sizeof(Defer) - sizeof(((Defer*)nil)->args) + ROUND(sz, sizeof(uintptr)))
25
// Allocate a Defer, usually using per-P pool.
26
// Each defer must be released with freedefer.
24
28
newdefer(int32 siz)
31
total = sizeof(*d) + ROUND(siz, sizeof(uintptr)) - sizeof(d->args);
32
if(c == nil || total > DeferChunkSize - c->off) {
33
if(total > DeferChunkSize / 2) {
34
// Not worth putting in any chunk.
35
// Allocate a separate block.
36
d = runtime·malloc(total);
45
// Cannot fit in current chunk.
46
// Switch to next chunk, allocating if necessary.
49
c = runtime·malloc(DeferChunkSize);
56
d = (Defer*)((byte*)c + c->off);
36
if(sc < nelem(p->deferpool)) {
40
p->deferpool[sc] = d->link;
43
// deferpool is empty or just a big defer
44
total = TOTALSIZE(siz);
45
d = runtime·malloc(total);
61
49
d->link = g->defer;
66
// Pop the current defer from the defer stack.
67
// Its contents are still valid until the goroutine begins executing again.
68
// In particular it is safe to call reflect.call(d->fn, d->argp, d->siz) after
79
runtime·throw("runtime: popdefer nil");
82
// Nothing else to do.
85
total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
87
if(c == nil || (byte*)d+total != (byte*)c+c->off)
88
runtime·throw("runtime: popdefer phase error");
90
if(c->off == sizeof(*c)) {
91
// Chunk now empty, so pop from stack.
92
// Save in dchunknext both to help with pingponging between frames
93
// and to make sure d is still valid on return.
94
if(g->dchunknext != nil)
95
runtime·free(g->dchunknext);
101
54
// Free the given defer.
102
// For defers in the per-goroutine chunk this just clears the saved arguments.
103
// For large defers allocated on the heap, this frees them.
104
55
// The defer cannot be used after this call.
106
57
freedefer(Defer *d)
114
// Wipe out any possible pointers in argp/pc/fn/args.
115
total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
116
runtime·memclr((byte*)d, total);
64
sc = DEFERCLASS(d->siz);
65
if(sc < nelem(p->deferpool)) {
67
d->link = p->deferpool[sc];
69
// No need to wipe out pointers in argp/pc/fn/args,
70
// because we empty the pool before GC.
120
75
// Create a new deferred function fn with siz bytes of arguments.
157
112
// is called again and again until there are no more deferred functions.
158
113
// Cannot split the stack because we reuse the caller's frame to
159
114
// call the deferred function.
161
// The ... in the prototype keeps the compiler from declaring
162
// an argument frame size. deferreturn is a very special function,
163
// and if the runtime ever asks for its frame size, that means
164
// the traceback routines are probably broken.
116
// The single argument isn't actually used - it just has its address
117
// taken so it can be matched against pending defers.
165
118
#pragma textflag NOSPLIT
167
runtime·deferreturn(uintptr arg0, ...)
120
runtime·deferreturn(uintptr arg0)
192
145
runtime·jmpdefer(fn, argp);
148
// Ensure that defer arg sizes that map to the same defer size class
149
// also map to the same malloc size class.
151
runtime·testdefersizes(void)
154
int32 i, siz, defersc, mallocsc;
155
int32 map[nelem(p->deferpool)];
157
for(i=0; i<nelem(p->deferpool); i++)
160
defersc = DEFERCLASS(i);
161
if(defersc >= nelem(p->deferpool))
164
mallocsc = runtime·SizeToClass(siz);
165
siz = runtime·class_to_size[mallocsc];
166
// runtime·printf("defer class %d: arg size %d, block size %d(%d)\n", defersc, i, siz, mallocsc);
167
if(map[defersc] < 0) {
168
map[defersc] = mallocsc;
171
if(map[defersc] != mallocsc) {
172
runtime·printf("bad defer size class: i=%d siz=%d mallocsc=%d/%d\n",
173
i, siz, map[defersc], mallocsc);
174
runtime·throw("bad defer size class");
195
179
// Run all deferred functions for the current goroutine.
223
207
static void recovery(G*);
208
static void abortpanic(Panic*);
209
static FuncVal abortpanicV = { (void(*)(void))abortpanic };
225
211
// The implementation of the predeclared function panic.
227
213
runtime·panic(Eface e)
233
p = runtime·mal(sizeof *p);
236
p->stackbase = g->stackbase;
219
runtime·memclr((byte*)&p, sizeof p);
222
p.stackbase = g->stackbase;
225
dabort.fn = &abortpanicV;
226
dabort.siz = sizeof(&p);
228
dabort.argp = NoArgs;
229
dabort.special = true;
243
235
// take defer off list in case of recursive panic
245
g->ispanic = true; // rock for newstack, where reflect.newstackcall ends up
237
g->ispanic = true; // rock for runtime·newstack, where runtime·newstackcall ends up
241
// The deferred function may cause another panic,
242
// so newstackcall may not return. Set up a defer
243
// to mark this panic aborted if that happens.
244
dabort.link = g->defer;
248
248
runtime·newstackcall(d->fn, (byte*)d->args, d->siz);
250
// Newstackcall did not panic. Remove dabort.
251
if(g->defer != &dabort)
252
runtime·throw("bad defer entry in panic");
253
g->defer = dabort.link;
258
// Aborted panics are marked but remain on the g->panic list.
259
// Recovery will unwind the stack frames containing their Panic structs.
260
// Remove them from the list and free the associated defers.
261
while(g->panic && g->panic->aborted) {
262
freedefer(g->panic->defer);
263
g->panic = g->panic->link;
252
265
if(g->panic == nil) // must be done with signal
255
267
// Pass information about recovering frame to recovery.
256
268
g->sigcode0 = (uintptr)argp;
257
269
g->sigcode1 = (uintptr)pc;
320
339
gp->stackbase = top->stackbase;
321
340
gp->stackguard = top->stackguard;
322
341
gp->stackguard0 = gp->stackguard;
324
gp->stacksize -= top->free;
325
runtime·stackfree(stk, top->free);
342
runtime·stackfree(gp, stk, top);
329
345
if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) {
371
388
m->mallocing = 1; // tell rest of panic not to try to malloc
372
389
} else if(m->mcache == nil) // can happen if called from signal handler or throw
373
390
m->mcache = runtime·allocmcache();
396
runtime·xadd(&runtime·panicking, 1);
397
runtime·lock(&paniclk);
398
if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
399
runtime·schedtrace(true);
400
runtime·freezetheworld();
403
// Something failed while panicing, probably the print of the
404
// argument to panic(). Just print a stack trace and exit.
375
406
runtime·printf("panic during panic\n");
410
// This is a genuine bug in the runtime, we couldn't even
411
// print the stack trace successfully.
413
runtime·printf("stack trace unavailable\n");
416
// Can't even print! Just exit.
381
runtime·xadd(&runtime·panicking, 1);
382
runtime·lock(&paniclk);
383
if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
384
runtime·schedtrace(true);
385
runtime·freezetheworld();
453
486
runtime·throw("recursive call during initialization - linker skew");
490
runtime·canpanic(G *gp)
494
USED(&g); // don't use global g, it points to gsignal
496
// Is it okay for gp to panic instead of crashing the program?
497
// Yes, as long as it is running Go code, not runtime code,
498
// and not stuck in a system call.
499
if(gp == nil || gp != m->curg)
501
if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
503
if(gp->status != Grunning || gp->syscallsp != 0)
506
if(m->libcallsp != 0)
457
513
runtime·throw(int8 *s)
529
// m->softfloat is set during software floating point,
530
// which might cause a fault during a memory load.
531
// It increments m->locks to avoid preemption.
532
// If we're panicking, the software floating point frames
533
// will be unwound, so decrement m->locks as they would.
473
539
if(m->mallocing) {
474
540
runtime·printf("panic: %s\n", s);
475
541
runtime·throw("panic during malloc");