Rebase.
[official-gcc.git] / libgo / runtime / panic.c
blob6a5d007f03c6b4a8251124ed2a5e1dc9ba929c06
1 // Copyright 2012 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 #include "runtime.h"
6 #include "malloc.h"
7 #include "go-defer.h"
8 #include "go-panic.h"
10 // Code related to defer, panic and recover.
12 uint32 runtime_panicking;
13 static Lock paniclk;
15 // Allocate a Defer, usually using per-P pool.
16 // Each defer must be released with freedefer.
17 Defer*
18 runtime_newdefer()
20 Defer *d;
21 P *p;
23 d = nil;
24 p = runtime_m()->p;
25 d = p->deferpool;
26 if(d)
27 p->deferpool = d->__next;
28 if(d == nil) {
29 // deferpool is empty
30 d = runtime_malloc(sizeof(Defer));
32 return d;
35 // Free the given defer.
36 // The defer cannot be used after this call.
37 void
38 runtime_freedefer(Defer *d)
40 P *p;
42 if(d->__special)
43 return;
44 p = runtime_m()->p;
45 d->__next = p->deferpool;
46 p->deferpool = d;
47 // No need to wipe out pointers in argp/pc/fn/args,
48 // because we empty the pool before GC.
51 // Run all deferred functions for the current goroutine.
52 static void
53 rundefer(void)
55 G *g;
56 Defer *d;
58 g = runtime_g();
59 while((d = g->defer) != nil) {
60 void (*pfn)(void*);
62 g->defer = d->__next;
63 pfn = d->__pfn;
64 d->__pfn = nil;
65 if (pfn != nil)
66 (*pfn)(d->__arg);
67 runtime_freedefer(d);
71 void
72 runtime_startpanic(void)
74 M *m;
76 m = runtime_m();
77 if(runtime_mheap.cachealloc.size == 0) { // very early
78 runtime_printf("runtime: panic before malloc heap initialized\n");
79 m->mallocing = 1; // tell rest of panic not to try to malloc
80 } else if(m->mcache == nil) // can happen if called from signal handler or throw
81 m->mcache = runtime_allocmcache();
82 switch(m->dying) {
83 case 0:
84 m->dying = 1;
85 if(runtime_g() != nil)
86 runtime_g()->writebuf = nil;
87 runtime_xadd(&runtime_panicking, 1);
88 runtime_lock(&paniclk);
89 if(runtime_debug.schedtrace > 0 || runtime_debug.scheddetail > 0)
90 runtime_schedtrace(true);
91 runtime_freezetheworld();
92 return;
93 case 1:
94 // Something failed while panicing, probably the print of the
95 // argument to panic(). Just print a stack trace and exit.
96 m->dying = 2;
97 runtime_printf("panic during panic\n");
98 runtime_dopanic(0);
99 runtime_exit(3);
100 case 2:
101 // This is a genuine bug in the runtime, we couldn't even
102 // print the stack trace successfully.
103 m->dying = 3;
104 runtime_printf("stack trace unavailable\n");
105 runtime_exit(4);
106 default:
107 // Can't even print! Just exit.
108 runtime_exit(5);
112 void
113 runtime_dopanic(int32 unused __attribute__ ((unused)))
115 G *g;
116 static bool didothers;
117 bool crash;
118 int32 t;
120 g = runtime_g();
121 if(g->sig != 0)
122 runtime_printf("[signal %x code=%p addr=%p]\n",
123 g->sig, (void*)g->sigcode0, (void*)g->sigcode1);
125 if((t = runtime_gotraceback(&crash)) > 0){
126 if(g != runtime_m()->g0) {
127 runtime_printf("\n");
128 runtime_goroutineheader(g);
129 runtime_traceback();
130 runtime_printcreatedby(g);
131 } else if(t >= 2 || runtime_m()->throwing > 0) {
132 runtime_printf("\nruntime stack:\n");
133 runtime_traceback();
135 if(!didothers) {
136 didothers = true;
137 runtime_tracebackothers(g);
140 runtime_unlock(&paniclk);
141 if(runtime_xadd(&runtime_panicking, -1) != 0) {
142 // Some other m is panicking too.
143 // Let it print what it needs to print.
144 // Wait forever without chewing up cpu.
145 // It will exit when it's done.
146 static Lock deadlock;
147 runtime_lock(&deadlock);
148 runtime_lock(&deadlock);
151 if(crash)
152 runtime_crash();
154 runtime_exit(2);
157 bool
158 runtime_canpanic(G *gp)
160 M *m = runtime_m();
161 byte g;
163 USED(&g); // don't use global g, it points to gsignal
165 // Is it okay for gp to panic instead of crashing the program?
166 // Yes, as long as it is running Go code, not runtime code,
167 // and not stuck in a system call.
168 if(gp == nil || gp != m->curg)
169 return false;
170 if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
171 return false;
172 if(gp->status != Grunning)
173 return false;
174 #ifdef GOOS_windows
175 if(m->libcallsp != 0)
176 return false;
177 #endif
178 return true;
181 void
182 runtime_throw(const char *s)
184 M *mp;
186 mp = runtime_m();
187 if(mp->throwing == 0)
188 mp->throwing = 1;
189 runtime_startpanic();
190 runtime_printf("fatal error: %s\n", s);
191 runtime_dopanic(0);
192 *(int32*)0 = 0; // not reached
193 runtime_exit(1); // even more not reached
196 void
197 runtime_panicstring(const char *s)
199 Eface err;
201 if(runtime_m()->mallocing) {
202 runtime_printf("panic: %s\n", s);
203 runtime_throw("panic during malloc");
205 if(runtime_m()->gcing) {
206 runtime_printf("panic: %s\n", s);
207 runtime_throw("panic during gc");
209 if(runtime_m()->locks) {
210 runtime_printf("panic: %s\n", s);
211 runtime_throw("panic holding locks");
213 runtime_newErrorCString(s, &err);
214 runtime_panic(err);
217 void runtime_Goexit (void) __asm__ (GOSYM_PREFIX "runtime.Goexit");
219 void
220 runtime_Goexit(void)
222 rundefer();
223 runtime_goexit();
226 void
227 runtime_panicdivide(void)
229 runtime_panicstring("integer divide by zero");