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.
4 
5 #include "runtime.h"
6 #include "malloc.h"
7 #include "go-defer.h"
8 #include "go-panic.h"
9 
10 // Code related to defer, panic and recover.
11 
12 uint32 runtime_panicking;
13 static Lock paniclk;
14 
15 // Allocate a Defer, usually using per-P pool.
16 // Each defer must be released with freedefer.
17 Defer*
runtime_newdefer()18 runtime_newdefer()
19 {
20 	Defer *d;
21 	P *p;
22 
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));
31 	}
32 	return d;
33 }
34 
35 // Free the given defer.
36 // The defer cannot be used after this call.
37 void
runtime_freedefer(Defer * d)38 runtime_freedefer(Defer *d)
39 {
40 	P *p;
41 
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.
49 }
50 
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
__go_rundefer(void)55 __go_rundefer(void)
56 {
57 	G *g;
58 	Defer *d;
59 
60 	g = runtime_g();
61 	while((d = g->defer) != nil) {
62 		void (*pfn)(void*);
63 
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);
70 	}
71 }
72 
73 void
runtime_startpanic(void)74 runtime_startpanic(void)
75 {
76 	M *m;
77 
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);
111 	}
112 }
113 
114 void
runtime_dopanic(int32 unused)115 runtime_dopanic(int32 unused __attribute__ ((unused)))
116 {
117 	G *g;
118 	static bool didothers;
119 	bool crash;
120 	int32 t;
121 
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);
126 
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();
136 		}
137 		if(!didothers) {
138 			didothers = true;
139 			runtime_tracebackothers(g);
140 		}
141 	}
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);
151 	}
152 
153 	if(crash)
154 		runtime_crash();
155 
156 	runtime_exit(2);
157 }
158 
159 bool
runtime_canpanic(G * gp)160 runtime_canpanic(G *gp)
161 {
162 	M *m = runtime_m();
163 	byte g;
164 
165 	USED(&g);  // don't use global g, it points to gsignal
166 
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;
181 }
182 
183 void
runtime_throw(const char * s)184 runtime_throw(const char *s)
185 {
186 	M *mp;
187 
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
196 }
197 
198 void
runtime_panicstring(const char * s)199 runtime_panicstring(const char *s)
200 {
201 	Eface err;
202 
203 	if(runtime_m()->mallocing) {
204 		runtime_printf("panic: %s\n", s);
205 		runtime_throw("panic during malloc");
206 	}
207 	if(runtime_m()->gcing) {
208 		runtime_printf("panic: %s\n", s);
209 		runtime_throw("panic during gc");
210 	}
211 	if(runtime_m()->locks) {
212 		runtime_printf("panic: %s\n", s);
213 		runtime_throw("panic holding locks");
214 	}
215 	runtime_newErrorCString(s, &err);
216 	runtime_panic(err);
217 }
218 
219 void runtime_Goexit (void) __asm__ (GOSYM_PREFIX "runtime.Goexit");
220 
221 void
runtime_Goexit(void)222 runtime_Goexit(void)
223 {
224 	__go_rundefer();
225 	runtime_goexit();
226 }
227 
228 void
runtime_panicdivide(void)229 runtime_panicdivide(void)
230 {
231 	runtime_panicstring("integer divide by zero");
232 }
233