github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/panic.c (about) 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* 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 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 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 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 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 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 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 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 222 runtime_Goexit(void) 223 { 224 __go_rundefer(); 225 runtime_goexit(); 226 } 227 228 void 229 runtime_panicdivide(void) 230 { 231 runtime_panicstring("integer divide by zero"); 232 }