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  }