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 // Run all deferred functions for the current goroutine.
16 static void
rundefer(void)17 rundefer(void)
18 {
19 	G *g;
20 	Defer *d;
21 
22 	g = runtime_g();
23 	while((d = g->defer) != nil) {
24 		void (*pfn)(void*);
25 
26 		g->defer = d->__next;
27 		pfn = d->__pfn;
28 		d->__pfn = nil;
29 		if (pfn != nil)
30 			(*pfn)(d->__arg);
31 		runtime_free(d);
32 	}
33 }
34 
35 void
runtime_startpanic(void)36 runtime_startpanic(void)
37 {
38 	M *m;
39 
40 	m = runtime_m();
41 	if(runtime_mheap == 0 || runtime_mheap->cachealloc.size == 0) { // very early
42 		runtime_printf("runtime: panic before malloc heap initialized\n");
43 		m->mallocing = 1; // tell rest of panic not to try to malloc
44 	} else if(m->mcache == nil) // can happen if called from signal handler or throw
45 		m->mcache = runtime_allocmcache();
46 	if(m->dying) {
47 		runtime_printf("panic during panic\n");
48 		runtime_exit(3);
49 	}
50 	m->dying = 1;
51 	runtime_xadd(&runtime_panicking, 1);
52 	runtime_lock(&paniclk);
53 }
54 
55 void
runtime_dopanic(int32 unused)56 runtime_dopanic(int32 unused __attribute__ ((unused)))
57 {
58 	G *g;
59 	static bool didothers;
60 	bool crash;
61 
62 	g = runtime_g();
63 	if(g->sig != 0)
64 		runtime_printf("[signal %x code=%p addr=%p]\n",
65 			       g->sig, (void*)g->sigcode0, (void*)g->sigcode1);
66 
67 	if(runtime_gotraceback(&crash)){
68 		if(g != runtime_m()->g0) {
69 			runtime_printf("\n");
70 			runtime_goroutineheader(g);
71 			runtime_traceback();
72 			runtime_goroutinetrailer(g);
73 		}
74 		if(!didothers) {
75 			didothers = true;
76 			runtime_tracebackothers(g);
77 		}
78 	}
79 	runtime_unlock(&paniclk);
80 	if(runtime_xadd(&runtime_panicking, -1) != 0) {
81 		// Some other m is panicking too.
82 		// Let it print what it needs to print.
83 		// Wait forever without chewing up cpu.
84 		// It will exit when it's done.
85 		static Lock deadlock;
86 		runtime_lock(&deadlock);
87 		runtime_lock(&deadlock);
88 	}
89 
90 	if(crash)
91 		runtime_crash();
92 
93 	runtime_exit(2);
94 }
95 
96 void
runtime_throw(const char * s)97 runtime_throw(const char *s)
98 {
99 	M *mp;
100 
101 	mp = runtime_m();
102 	if(mp->throwing == 0)
103 		mp->throwing = 1;
104 	runtime_startpanic();
105 	runtime_printf("fatal error: %s\n", s);
106 	runtime_dopanic(0);
107 	*(int32*)0 = 0;	// not reached
108 	runtime_exit(1);	// even more not reached
109 }
110 
111 void
runtime_panicstring(const char * s)112 runtime_panicstring(const char *s)
113 {
114 	Eface err;
115 
116 	if(runtime_m()->gcing) {
117 		runtime_printf("panic: %s\n", s);
118 		runtime_throw("panic during gc");
119 	}
120 	runtime_newErrorString(runtime_gostringnocopy((const byte*)s), &err);
121 	runtime_panic(err);
122 }
123 
124 void runtime_Goexit (void) __asm__ (GOSYM_PREFIX "runtime.Goexit");
125 
126 void
runtime_Goexit(void)127 runtime_Goexit(void)
128 {
129 	rundefer();
130 	runtime_goexit();
131 }
132