|  | /* 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); | 
|  | } |