b9f04a8461
From-SVN: r178905
128 lines
2.9 KiB
C
128 lines
2.9 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 "malloc.h"
|
|
#include "go-alloc.h"
|
|
#include "go-defer.h"
|
|
#include "go-panic.h"
|
|
#include "go-string.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);
|
|
printf ("\t");
|
|
}
|
|
printf ("panic: ");
|
|
printany (p->__arg);
|
|
if (p->__was_recovered)
|
|
printf (" [recovered]");
|
|
putchar ('\n');
|
|
}
|
|
|
|
/* This implements __go_panic which is used for the panic
|
|
function. */
|
|
|
|
void
|
|
__go_panic (struct __go_empty_interface arg)
|
|
{
|
|
struct __go_panic_stack *n;
|
|
|
|
if (__go_panic_defer == NULL)
|
|
__go_panic_defer = ((struct __go_panic_defer_struct *)
|
|
__go_alloc (sizeof (struct __go_panic_defer_struct)));
|
|
|
|
n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack));
|
|
n->__arg = arg;
|
|
n->__next = __go_panic_defer->__panic;
|
|
__go_panic_defer->__panic = n;
|
|
|
|
/* Run all the defer functions. */
|
|
|
|
while (1)
|
|
{
|
|
struct __go_defer_stack *d;
|
|
void (*pfn) (void *);
|
|
|
|
d = __go_panic_defer->__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. */
|
|
|
|
__go_panic_defer->__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;
|
|
}
|
|
|
|
__go_panic_defer->__defer = d->__next;
|
|
__go_free (d);
|
|
}
|
|
|
|
/* The panic was not recovered. */
|
|
|
|
__printpanics (__go_panic_defer->__panic);
|
|
|
|
/* FIXME: We should dump a call stack here. */
|
|
abort ();
|
|
}
|
|
|
|
/* This is used by the runtime library. */
|
|
|
|
void
|
|
__go_panic_msg (const char* msg)
|
|
{
|
|
size_t len;
|
|
unsigned char *sdata;
|
|
struct __go_string s;
|
|
struct __go_empty_interface arg;
|
|
|
|
len = __builtin_strlen (msg);
|
|
sdata = runtime_mallocgc (len, FlagNoPointers, 0, 0);
|
|
__builtin_memcpy (sdata, msg, len);
|
|
s.__data = sdata;
|
|
s.__length = len;
|
|
newErrorString(s, &arg);
|
|
__go_panic (arg);
|
|
}
|