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