PR fortran/77666
[official-gcc.git] / libgo / runtime / panic.c
blobd493b54a5093d3314fe02eeb4d3fa571475c5623
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-panic.h"
9 // Code related to defer, panic and recover.
11 uint32 runtime_panicking;
12 static Lock paniclk;
14 // Allocate a Defer, usually using per-P pool.
15 // Each defer must be released with freedefer.
16 Defer*
17 runtime_newdefer()
19 Defer *d;
20 P *p;
22 d = nil;
23 p = (P*)runtime_m()->p;
24 d = p->deferpool;
25 if(d)
26 p->deferpool = d->next;
27 if(d == nil) {
28 // deferpool is empty
29 d = runtime_malloc(sizeof(Defer));
31 return d;
34 // Free the given defer.
35 // The defer cannot be used after this call.
36 void
37 runtime_freedefer(Defer *d)
39 P *p;
41 if(d->special)
42 return;
43 p = (P*)runtime_m()->p;
44 d->next = p->deferpool;
45 p->deferpool = d;
46 // No need to wipe out pointers in argp/pc/fn/args,
47 // because we empty the pool before GC.
50 // Run all deferred functions for the current goroutine.
51 // This is noinline for go_can_recover.
52 static void __go_rundefer (void) __attribute__ ((noinline));
53 static void
54 __go_rundefer(void)
56 G *g;
57 Defer *d;
59 g = runtime_g();
60 while((d = g->_defer) != nil) {
61 void (*pfn)(void*);
63 g->_defer = d->next;
64 pfn = (void (*) (void *))d->pfn;
65 d->pfn = 0;
66 if (pfn != nil)
67 (*pfn)(d->arg);
68 runtime_freedefer(d);
72 void
73 runtime_startpanic(void)
75 M *m;
77 m = runtime_m();
78 if(runtime_mheap.cachealloc.size == 0) { // very early
79 runtime_printf("runtime: panic before malloc heap initialized\n");
80 m->mallocing = 1; // tell rest of panic not to try to malloc
81 } else if(m->mcache == nil) // can happen if called from signal handler or throw
82 m->mcache = runtime_allocmcache();
83 switch(m->dying) {
84 case 0:
85 m->dying = 1;
86 if(runtime_g() != nil)
87 runtime_g()->writebuf = nil;
88 runtime_xadd(&runtime_panicking, 1);
89 runtime_lock(&paniclk);
90 if(runtime_debug.schedtrace > 0 || runtime_debug.scheddetail > 0)
91 runtime_schedtrace(true);
92 runtime_freezetheworld();
93 return;
94 case 1:
95 // Something failed while panicing, probably the print of the
96 // argument to panic(). Just print a stack trace and exit.
97 m->dying = 2;
98 runtime_printf("panic during panic\n");
99 runtime_dopanic(0);
100 runtime_exit(3);
101 case 2:
102 // This is a genuine bug in the runtime, we couldn't even
103 // print the stack trace successfully.
104 m->dying = 3;
105 runtime_printf("stack trace unavailable\n");
106 runtime_exit(4);
107 default:
108 // Can't even print! Just exit.
109 runtime_exit(5);
113 void
114 runtime_dopanic(int32 unused __attribute__ ((unused)))
116 G *g;
117 static bool didothers;
118 bool crash;
119 int32 t;
121 g = runtime_g();
122 if(g->sig != 0)
123 runtime_printf("[signal %x code=%p addr=%p]\n",
124 g->sig, (void*)g->sigcode0, (void*)g->sigcode1);
126 if((t = runtime_gotraceback(&crash)) > 0){
127 if(g != runtime_m()->g0) {
128 runtime_printf("\n");
129 runtime_goroutineheader(g);
130 runtime_traceback();
131 runtime_printcreatedby(g);
132 } else if(t >= 2 || runtime_m()->throwing > 0) {
133 runtime_printf("\nruntime stack:\n");
134 runtime_traceback();
136 if(!didothers) {
137 didothers = true;
138 runtime_tracebackothers(g);
141 runtime_unlock(&paniclk);
142 if(runtime_xadd(&runtime_panicking, -1) != 0) {
143 // Some other m is panicking too.
144 // Let it print what it needs to print.
145 // Wait forever without chewing up cpu.
146 // It will exit when it's done.
147 static Lock deadlock;
148 runtime_lock(&deadlock);
149 runtime_lock(&deadlock);
152 if(crash)
153 runtime_crash();
155 runtime_exit(2);
158 bool
159 runtime_canpanic(G *gp)
161 M *m = runtime_m();
162 byte g;
164 USED(&g); // don't use global g, it points to gsignal
166 // Is it okay for gp to panic instead of crashing the program?
167 // Yes, as long as it is running Go code, not runtime code,
168 // and not stuck in a system call.
169 if(gp == nil || gp != m->curg)
170 return false;
171 if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
172 return false;
173 if(gp->atomicstatus != _Grunning)
174 return false;
175 #ifdef GOOS_windows
176 if(m->libcallsp != 0)
177 return false;
178 #endif
179 return true;
182 void
183 runtime_throw(const char *s)
185 M *mp;
187 mp = runtime_m();
188 if(mp->throwing == 0)
189 mp->throwing = 1;
190 runtime_startpanic();
191 runtime_printf("fatal error: %s\n", s);
192 runtime_dopanic(0);
193 *(int32*)0 = 0; // not reached
194 runtime_exit(1); // even more not reached
197 void throw(String) __asm__ (GOSYM_PREFIX "runtime.throw");
198 void
199 throw(String s)
201 M *mp;
203 mp = runtime_m();
204 if(mp->throwing == 0)
205 mp->throwing = 1;
206 runtime_startpanic();
207 runtime_printf("fatal error: %S\n", s);
208 runtime_dopanic(0);
209 *(int32*)0 = 0; // not reached
210 runtime_exit(1); // even more not reached
213 void
214 runtime_panicstring(const char *s)
216 Eface err;
218 if(runtime_m()->mallocing) {
219 runtime_printf("panic: %s\n", s);
220 runtime_throw("panic during malloc");
222 if(runtime_m()->gcing) {
223 runtime_printf("panic: %s\n", s);
224 runtime_throw("panic during gc");
226 if(runtime_m()->locks) {
227 runtime_printf("panic: %s\n", s);
228 runtime_throw("panic holding locks");
230 runtime_newErrorCString(s, &err);
231 runtime_panic(err);
234 void runtime_Goexit (void) __asm__ (GOSYM_PREFIX "runtime.Goexit");
236 void
237 runtime_Goexit(void)
239 __go_rundefer();
240 runtime_goexit();
243 void
244 runtime_panicdivide(void)
246 runtime_panicstring("integer divide by zero");