2015-05-22 Robert Dewar <dewar@adacore.com>
[official-gcc.git] / libgo / runtime / panic.c
blobde000db988993fbe8abb8f7eef82e4f86a2080d8
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 // This is noinline for go_can_recover.
53 static void __go_rundefer (void) __attribute__ ((noinline));
54 static void
55 __go_rundefer(void)
57 G *g;
58 Defer *d;
60 g = runtime_g();
61 while((d = g->defer) != nil) {
62 void (*pfn)(void*);
64 g->defer = d->__next;
65 pfn = d->__pfn;
66 d->__pfn = nil;
67 if (pfn != nil)
68 (*pfn)(d->__arg);
69 runtime_freedefer(d);
73 void
74 runtime_startpanic(void)
76 M *m;
78 m = runtime_m();
79 if(runtime_mheap.cachealloc.size == 0) { // very early
80 runtime_printf("runtime: panic before malloc heap initialized\n");
81 m->mallocing = 1; // tell rest of panic not to try to malloc
82 } else if(m->mcache == nil) // can happen if called from signal handler or throw
83 m->mcache = runtime_allocmcache();
84 switch(m->dying) {
85 case 0:
86 m->dying = 1;
87 if(runtime_g() != nil)
88 runtime_g()->writebuf = nil;
89 runtime_xadd(&runtime_panicking, 1);
90 runtime_lock(&paniclk);
91 if(runtime_debug.schedtrace > 0 || runtime_debug.scheddetail > 0)
92 runtime_schedtrace(true);
93 runtime_freezetheworld();
94 return;
95 case 1:
96 // Something failed while panicing, probably the print of the
97 // argument to panic(). Just print a stack trace and exit.
98 m->dying = 2;
99 runtime_printf("panic during panic\n");
100 runtime_dopanic(0);
101 runtime_exit(3);
102 case 2:
103 // This is a genuine bug in the runtime, we couldn't even
104 // print the stack trace successfully.
105 m->dying = 3;
106 runtime_printf("stack trace unavailable\n");
107 runtime_exit(4);
108 default:
109 // Can't even print! Just exit.
110 runtime_exit(5);
114 void
115 runtime_dopanic(int32 unused __attribute__ ((unused)))
117 G *g;
118 static bool didothers;
119 bool crash;
120 int32 t;
122 g = runtime_g();
123 if(g->sig != 0)
124 runtime_printf("[signal %x code=%p addr=%p]\n",
125 g->sig, (void*)g->sigcode0, (void*)g->sigcode1);
127 if((t = runtime_gotraceback(&crash)) > 0){
128 if(g != runtime_m()->g0) {
129 runtime_printf("\n");
130 runtime_goroutineheader(g);
131 runtime_traceback();
132 runtime_printcreatedby(g);
133 } else if(t >= 2 || runtime_m()->throwing > 0) {
134 runtime_printf("\nruntime stack:\n");
135 runtime_traceback();
137 if(!didothers) {
138 didothers = true;
139 runtime_tracebackothers(g);
142 runtime_unlock(&paniclk);
143 if(runtime_xadd(&runtime_panicking, -1) != 0) {
144 // Some other m is panicking too.
145 // Let it print what it needs to print.
146 // Wait forever without chewing up cpu.
147 // It will exit when it's done.
148 static Lock deadlock;
149 runtime_lock(&deadlock);
150 runtime_lock(&deadlock);
153 if(crash)
154 runtime_crash();
156 runtime_exit(2);
159 bool
160 runtime_canpanic(G *gp)
162 M *m = runtime_m();
163 byte g;
165 USED(&g); // don't use global g, it points to gsignal
167 // Is it okay for gp to panic instead of crashing the program?
168 // Yes, as long as it is running Go code, not runtime code,
169 // and not stuck in a system call.
170 if(gp == nil || gp != m->curg)
171 return false;
172 if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
173 return false;
174 if(gp->status != Grunning)
175 return false;
176 #ifdef GOOS_windows
177 if(m->libcallsp != 0)
178 return false;
179 #endif
180 return true;
183 void
184 runtime_throw(const char *s)
186 M *mp;
188 mp = runtime_m();
189 if(mp->throwing == 0)
190 mp->throwing = 1;
191 runtime_startpanic();
192 runtime_printf("fatal error: %s\n", s);
193 runtime_dopanic(0);
194 *(int32*)0 = 0; // not reached
195 runtime_exit(1); // even more not reached
198 void
199 runtime_panicstring(const char *s)
201 Eface err;
203 if(runtime_m()->mallocing) {
204 runtime_printf("panic: %s\n", s);
205 runtime_throw("panic during malloc");
207 if(runtime_m()->gcing) {
208 runtime_printf("panic: %s\n", s);
209 runtime_throw("panic during gc");
211 if(runtime_m()->locks) {
212 runtime_printf("panic: %s\n", s);
213 runtime_throw("panic holding locks");
215 runtime_newErrorCString(s, &err);
216 runtime_panic(err);
219 void runtime_Goexit (void) __asm__ (GOSYM_PREFIX "runtime.Goexit");
221 void
222 runtime_Goexit(void)
224 __go_rundefer();
225 runtime_goexit();
228 void
229 runtime_panicdivide(void)
231 runtime_panicstring("integer divide by zero");