github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/go-panic.c (about)

     1  /* go-panic.c -- support for the go panic function.
     2  
     3     Copyright 2009 The Go Authors. All rights reserved.
     4     Use of this source code is governed by a BSD-style
     5     license that can be found in the LICENSE file.  */
     6  
     7  #include <stdio.h>
     8  #include <stdlib.h>
     9  
    10  #include "runtime.h"
    11  #include "arch.h"
    12  #include "malloc.h"
    13  #include "go-alloc.h"
    14  #include "go-defer.h"
    15  #include "go-panic.h"
    16  #include "interface.h"
    17  
    18  /* Print the panic stack.  This is used when there is no recover.  */
    19  
    20  static void
    21  __printpanics (struct __go_panic_stack *p)
    22  {
    23    if (p->__next != NULL)
    24      {
    25        __printpanics (p->__next);
    26        runtime_printf ("\t");
    27      }
    28    runtime_printf ("panic: ");
    29    runtime_printany (p->__arg);
    30    if (p->__was_recovered)
    31      runtime_printf (" [recovered]");
    32    runtime_printf ("\n");
    33  }
    34  
    35  /* This implements __go_panic which is used for the panic
    36     function.  */
    37  
    38  void
    39  __go_panic (struct __go_empty_interface arg)
    40  {
    41    G *g;
    42    struct __go_panic_stack *n;
    43  
    44    g = runtime_g ();
    45  
    46    n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack));
    47    n->__arg = arg;
    48    n->__next = g->panic;
    49    g->panic = n;
    50  
    51    /* Run all the defer functions.  */
    52  
    53    while (1)
    54      {
    55        struct __go_defer_stack *d;
    56        void (*pfn) (void *);
    57  
    58        d = g->defer;
    59        if (d == NULL)
    60  	break;
    61  
    62        pfn = d->__pfn;
    63        d->__pfn = NULL;
    64  
    65        if (pfn != NULL)
    66  	{
    67  	  (*pfn) (d->__arg);
    68  
    69  	  if (n->__was_recovered)
    70  	    {
    71  	      /* Some defer function called recover.  That means that
    72  		 we should stop running this panic.  */
    73  
    74  	      g->panic = n->__next;
    75  	      __go_free (n);
    76  
    77  	      /* Now unwind the stack by throwing an exception.  The
    78  		 compiler has arranged to create exception handlers in
    79  		 each function which uses a defer statement.  These
    80  		 exception handlers will check whether the entry on
    81  		 the top of the defer stack is from the current
    82  		 function.  If it is, we have unwound the stack far
    83  		 enough.  */
    84  	      __go_unwind_stack ();
    85  
    86  	      /* __go_unwind_stack should not return.  */
    87  	      abort ();
    88  	    }
    89  
    90  	  /* Because we executed that defer function by a panic, and
    91  	     it did not call recover, we know that we are not
    92  	     returning from the calling function--we are panicing
    93  	     through it.  */
    94  	  *d->__frame = 0;
    95  	}
    96  
    97        g->defer = d->__next;
    98  
    99        /* This may be called by a cgo callback routine to defer the
   100  	 call to syscall.CgocallBackDone, in which case we will not
   101  	 have a memory context.  Don't try to free anything in that
   102  	 case--the GC will release it later.  */
   103        if (runtime_m () != NULL)
   104  	runtime_freedefer (d);
   105      }
   106  
   107    /* The panic was not recovered.  */
   108  
   109    runtime_startpanic ();
   110    __printpanics (g->panic);
   111    runtime_dopanic (0);
   112  }