mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			113 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			113 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
| /* go-panic.c -- support for the go panic function.
 | |
| 
 | |
|    Copyright 2009 The Go Authors. All rights reserved.
 | |
|    Use of this source code is governed by a BSD-style
 | |
|    license that can be found in the LICENSE file.  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #include "runtime.h"
 | |
| #include "arch.h"
 | |
| #include "malloc.h"
 | |
| #include "go-alloc.h"
 | |
| #include "go-defer.h"
 | |
| #include "go-panic.h"
 | |
| #include "interface.h"
 | |
| 
 | |
| /* Print the panic stack.  This is used when there is no recover.  */
 | |
| 
 | |
| static void
 | |
| __printpanics (struct __go_panic_stack *p)
 | |
| {
 | |
|   if (p->__next != NULL)
 | |
|     {
 | |
|       __printpanics (p->__next);
 | |
|       runtime_printf ("\t");
 | |
|     }
 | |
|   runtime_printf ("panic: ");
 | |
|   runtime_printany (p->__arg);
 | |
|   if (p->__was_recovered)
 | |
|     runtime_printf (" [recovered]");
 | |
|   runtime_printf ("\n");
 | |
| }
 | |
| 
 | |
| /* This implements __go_panic which is used for the panic
 | |
|    function.  */
 | |
| 
 | |
| void
 | |
| __go_panic (struct __go_empty_interface arg)
 | |
| {
 | |
|   G *g;
 | |
|   struct __go_panic_stack *n;
 | |
| 
 | |
|   g = runtime_g ();
 | |
| 
 | |
|   n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack));
 | |
|   n->__arg = arg;
 | |
|   n->__next = g->panic;
 | |
|   g->panic = n;
 | |
| 
 | |
|   /* Run all the defer functions.  */
 | |
| 
 | |
|   while (1)
 | |
|     {
 | |
|       struct __go_defer_stack *d;
 | |
|       void (*pfn) (void *);
 | |
| 
 | |
|       d = g->defer;
 | |
|       if (d == NULL)
 | |
| 	break;
 | |
| 
 | |
|       pfn = d->__pfn;
 | |
|       d->__pfn = NULL;
 | |
| 
 | |
|       if (pfn != NULL)
 | |
| 	{
 | |
| 	  (*pfn) (d->__arg);
 | |
| 
 | |
| 	  if (n->__was_recovered)
 | |
| 	    {
 | |
| 	      /* Some defer function called recover.  That means that
 | |
| 		 we should stop running this panic.  */
 | |
| 
 | |
| 	      g->panic = n->__next;
 | |
| 	      __go_free (n);
 | |
| 
 | |
| 	      /* Now unwind the stack by throwing an exception.  The
 | |
| 		 compiler has arranged to create exception handlers in
 | |
| 		 each function which uses a defer statement.  These
 | |
| 		 exception handlers will check whether the entry on
 | |
| 		 the top of the defer stack is from the current
 | |
| 		 function.  If it is, we have unwound the stack far
 | |
| 		 enough.  */
 | |
| 	      __go_unwind_stack ();
 | |
| 
 | |
| 	      /* __go_unwind_stack should not return.  */
 | |
| 	      abort ();
 | |
| 	    }
 | |
| 
 | |
| 	  /* Because we executed that defer function by a panic, and
 | |
| 	     it did not call recover, we know that we are not
 | |
| 	     returning from the calling function--we are panicing
 | |
| 	     through it.  */
 | |
| 	  *d->__frame = 0;
 | |
| 	}
 | |
| 
 | |
|       g->defer = d->__next;
 | |
| 
 | |
|       /* This may be called by a cgo callback routine to defer the
 | |
| 	 call to syscall.CgocallBackDone, in which case we will not
 | |
| 	 have a memory context.  Don't try to free anything in that
 | |
| 	 case--the GC will release it later.  */
 | |
|       if (runtime_m () != NULL)
 | |
| 	runtime_freedefer (d);
 | |
|     }
 | |
| 
 | |
|   /* The panic was not recovered.  */
 | |
| 
 | |
|   runtime_startpanic ();
 | |
|   __printpanics (g->panic);
 | |
|   runtime_dopanic (0);
 | |
| }
 |