--- /dev/null
+// Copyright 2012 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 "runtime.h"
+#include "arch_GOARCH.h"
+#include "stack.h"
+
+// Code related to defer, panic and recover.
+
+uint32 runtime·panicking;
+static Lock paniclk;
+
+// Create a new deferred function fn with siz bytes of arguments.
+// The compiler turns a defer statement into a call to this.
+// Cannot split the stack because it assumes that the arguments
+// are available sequentially after &fn; they would not be
+// copied if a stack split occurred. It's OK for this to call
+// functions that split the stack.
+#pragma textflag 7
+uintptr
+runtime·deferproc(int32 siz, byte* fn, ...)
+{
+ Defer *d;
+ int32 mallocsiz;
+
+ mallocsiz = sizeof(*d);
+ if(siz > sizeof(d->args))
+ mallocsiz += siz - sizeof(d->args);
+ d = runtime·malloc(mallocsiz);
+ d->fn = fn;
+ d->siz = siz;
+ d->pc = runtime·getcallerpc(&siz);
+ if(thechar == '5')
+ d->argp = (byte*)(&fn+2); // skip caller's saved link register
+ else
+ d->argp = (byte*)(&fn+1);
+ runtime·memmove(d->args, d->argp, d->siz);
+
+ d->link = g->defer;
+ g->defer = d;
+
+ // deferproc returns 0 normally.
+ // a deferred func that stops a panic
+ // makes the deferproc return 1.
+ // the code the compiler generates always
+ // checks the return value and jumps to the
+ // end of the function if deferproc returns != 0.
+ return 0;
+}
+
+// Run a deferred function if there is one.
+// The compiler inserts a call to this at the end of any
+// function which calls defer.
+// If there is a deferred function, this will call runtime·jmpdefer,
+// which will jump to the deferred function such that it appears
+// to have been called by the caller of deferreturn at the point
+// just before deferreturn was called. The effect is that deferreturn
+// is called again and again until there are no more deferred functions.
+// Cannot split the stack because we reuse the caller's frame to
+// call the deferred function.
+#pragma textflag 7
+void
+runtime·deferreturn(uintptr arg0)
+{
+ Defer *d;
+ byte *argp, *fn;
+
+ d = g->defer;
+ if(d == nil)
+ return;
+ argp = (byte*)&arg0;
+ if(d->argp != argp)
+ return;
+ runtime·memmove(argp, d->args, d->siz);
+ g->defer = d->link;
+ fn = d->fn;
+ if(!d->nofree)
+ runtime·free(d);
+ runtime·jmpdefer(fn, argp);
+}
+
+// Run all deferred functions for the current goroutine.
+static void
+rundefer(void)
+{
+ Defer *d;
+
+ while((d = g->defer) != nil) {
+ g->defer = d->link;
+ reflect·call(d->fn, (byte*)d->args, d->siz);
+ if(!d->nofree)
+ runtime·free(d);
+ }
+}
+
+// Print all currently active panics. Used when crashing.
+static void
+printpanics(Panic *p)
+{
+ if(p->link) {
+ printpanics(p->link);
+ runtime·printf("\t");
+ }
+ runtime·printf("panic: ");
+ runtime·printany(p->arg);
+ if(p->recovered)
+ runtime·printf(" [recovered]");
+ runtime·printf("\n");
+}
+
+static void recovery(G*);
+
+// The implementation of the predeclared function panic.
+void
+runtime·panic(Eface e)
+{
+ Defer *d;
+ Panic *p;
+
+ p = runtime·mal(sizeof *p);
+ p->arg = e;
+ p->link = g->panic;
+ p->stackbase = (byte*)g->stackbase;
+ g->panic = p;
+
+ for(;;) {
+ d = g->defer;
+ if(d == nil)
+ break;
+ // take defer off list in case of recursive panic
+ g->defer = d->link;
+ g->ispanic = true; // rock for newstack, where reflect.call ends up
+ reflect·call(d->fn, (byte*)d->args, d->siz);
+ if(p->recovered) {
+ g->panic = p->link;
+ if(g->panic == nil) // must be done with signal
+ g->sig = 0;
+ runtime·free(p);
+ // put recovering defer back on list
+ // for scheduler to find.
+ d->link = g->defer;
+ g->defer = d;
+ runtime·mcall(recovery);
+ runtime·throw("recovery failed"); // mcall should not return
+ }
+ if(!d->nofree)
+ runtime·free(d);
+ }
+
+ // ran out of deferred calls - old-school panic now
+ runtime·startpanic();
+ printpanics(g->panic);
+ runtime·dopanic(0);
+}
+
+// Unwind the stack after a deferred function calls recover
+// after a panic. Then arrange to continue running as though
+// the caller of the deferred function returned normally.
+static void
+recovery(G *gp)
+{
+ Defer *d;
+
+ // Rewind gp's stack; we're running on m->g0's stack.
+ d = gp->defer;
+ gp->defer = d->link;
+
+ // Unwind to the stack frame with d's arguments in it.
+ runtime·unwindstack(gp, d->argp);
+
+ // Make the deferproc for this d return again,
+ // this time returning 1. The calling function will
+ // jump to the standard return epilogue.
+ // The -2*sizeof(uintptr) makes up for the
+ // two extra words that are on the stack at
+ // each call to deferproc.
+ // (The pc we're returning to does pop pop
+ // before it tests the return value.)
+ // On the arm there are 2 saved LRs mixed in too.
+ if(thechar == '5')
+ gp->sched.sp = (uintptr)d->argp - 4*sizeof(uintptr);
+ else
+ gp->sched.sp = (uintptr)d->argp - 2*sizeof(uintptr);
+ gp->sched.pc = d->pc;
+ if(!d->nofree)
+ runtime·free(d);
+ runtime·gogo(&gp->sched, 1);
+}
+
+// Free stack frames until we hit the last one
+// or until we find the one that contains the sp.
+void
+runtime·unwindstack(G *gp, byte *sp)
+{
+ Stktop *top;
+ byte *stk;
+
+ // Must be called from a different goroutine, usually m->g0.
+ if(g == gp)
+ runtime·throw("unwindstack on self");
+
+ while((top = (Stktop*)gp->stackbase) != nil && top->stackbase != nil) {
+ stk = (byte*)gp->stackguard - StackGuard;
+ if(stk <= sp && sp < (byte*)gp->stackbase)
+ break;
+ gp->stackbase = (uintptr)top->stackbase;
+ gp->stackguard = (uintptr)top->stackguard;
+ if(top->free != 0)
+ runtime·stackfree(stk, top->free);
+ }
+
+ if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) {
+ runtime·printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase);
+ runtime·throw("bad unwindstack");
+ }
+}
+
+// The implementation of the predeclared function recover.
+// Cannot split the stack because it needs to reliably
+// find the stack segment of its caller.
+#pragma textflag 7
+void
+runtime·recover(byte *argp, Eface ret)
+{
+ Stktop *top, *oldtop;
+ Panic *p;
+
+ // Must be a panic going on.
+ if((p = g->panic) == nil || p->recovered)
+ goto nomatch;
+
+ // Frame must be at the top of the stack segment,
+ // because each deferred call starts a new stack
+ // segment as a side effect of using reflect.call.
+ // (There has to be some way to remember the
+ // variable argument frame size, and the segment
+ // code already takes care of that for us, so we
+ // reuse it.)
+ //
+ // As usual closures complicate things: the fp that
+ // the closure implementation function claims to have
+ // is where the explicit arguments start, after the
+ // implicit pointer arguments and PC slot.
+ // If we're on the first new segment for a closure,
+ // then fp == top - top->args is correct, but if
+ // the closure has its own big argument frame and
+ // allocated a second segment (see below),
+ // the fp is slightly above top - top->args.
+ // That condition can't happen normally though
+ // (stack pointers go down, not up), so we can accept
+ // any fp between top and top - top->args as
+ // indicating the top of the segment.
+ top = (Stktop*)g->stackbase;
+ if(argp < (byte*)top - top->argsize || (byte*)top < argp)
+ goto nomatch;
+
+ // The deferred call makes a new segment big enough
+ // for the argument frame but not necessarily big
+ // enough for the function's local frame (size unknown
+ // at the time of the call), so the function might have
+ // made its own segment immediately. If that's the
+ // case, back top up to the older one, the one that
+ // reflect.call would have made for the panic.
+ //
+ // The fp comparison here checks that the argument
+ // frame that was copied during the split (the top->args
+ // bytes above top->fp) abuts the old top of stack.
+ // This is a correct test for both closure and non-closure code.
+ oldtop = (Stktop*)top->stackbase;
+ if(oldtop != nil && top->argp == (byte*)oldtop - top->argsize)
+ top = oldtop;
+
+ // Now we have the segment that was created to
+ // run this call. It must have been marked as a panic segment.
+ if(!top->panic)
+ goto nomatch;
+
+ // Okay, this is the top frame of a deferred call
+ // in response to a panic. It can see the panic argument.
+ p->recovered = 1;
+ ret = p->arg;
+ FLUSH(&ret);
+ return;
+
+nomatch:
+ ret.type = nil;
+ ret.data = nil;
+ FLUSH(&ret);
+}
+
+void
+runtime·startpanic(void)
+{
+ if(m->dying) {
+ runtime·printf("panic during panic\n");
+ runtime·exit(3);
+ }
+ m->dying = 1;
+ runtime·xadd(&runtime·panicking, 1);
+ runtime·lock(&paniclk);
+}
+
+void
+runtime·dopanic(int32 unused)
+{
+ static bool didothers;
+
+ if(g->sig != 0)
+ runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
+ g->sig, g->sigcode0, g->sigcode1, g->sigpc);
+
+ if(runtime·gotraceback()){
+ if(g != m->g0) {
+ runtime·printf("\n");
+ runtime·goroutineheader(g);
+ runtime·traceback(runtime·getcallerpc(&unused), runtime·getcallersp(&unused), 0, g);
+ }
+ if(!didothers) {
+ didothers = true;
+ runtime·tracebackothers(g);
+ }
+ }
+ runtime·unlock(&paniclk);
+ if(runtime·xadd(&runtime·panicking, -1) != 0) {
+ // Some other m is panicking too.
+ // Let it print what it needs to print.
+ // Wait forever without chewing up cpu.
+ // It will exit when it's done.
+ static Lock deadlock;
+ runtime·lock(&deadlock);
+ runtime·lock(&deadlock);
+ }
+
+ runtime·exit(2);
+}
+
+void
+runtime·panicindex(void)
+{
+ runtime·panicstring("index out of range");
+}
+
+void
+runtime·panicslice(void)
+{
+ runtime·panicstring("slice bounds out of range");
+}
+
+void
+runtime·throwreturn(void)
+{
+ // can only happen if compiler is broken
+ runtime·throw("no return at end of a typed function - compiler is broken");
+}
+
+void
+runtime·throwinit(void)
+{
+ // can only happen with linker skew
+ runtime·throw("recursive call during initialization - linker skew");
+}
+
+void
+runtime·throw(int8 *s)
+{
+ runtime·startpanic();
+ runtime·printf("throw: %s\n", s);
+ runtime·dopanic(0);
+ *(int32*)0 = 0; // not reached
+ runtime·exit(1); // even more not reached
+}
+
+void
+runtime·panicstring(int8 *s)
+{
+ Eface err;
+
+ if(m->gcing) {
+ runtime·printf("panic: %s\n", s);
+ runtime·throw("panic during gc");
+ }
+ runtime·newErrorString(runtime·gostringnocopy((byte*)s), &err);
+ runtime·panic(err);
+}
+
+void
+runtime·Goexit(void)
+{
+ rundefer();
+ runtime·goexit();
+}
bool runtime·iscgo;
-static void unwindstack(G*, byte*);
static void schedule(G*);
typedef struct Sched Sched;
m->lockedg = nil;
}
gp->idlem = nil;
- unwindstack(gp, nil);
+ runtime·unwindstack(gp, nil);
gfput(gp);
if(--runtime·sched.gcount == 0)
runtime·exit(0);
//printf(" goid=%d\n", newg->goid);
}
-// Create a new deferred function fn with siz bytes of arguments.
-// The compiler turns a defer statement into a call to this.
-// Cannot split the stack because it assumes that the arguments
-// are available sequentially after &fn; they would not be
-// copied if a stack split occurred. It's OK for this to call
-// functions that split the stack.
-#pragma textflag 7
-uintptr
-runtime·deferproc(int32 siz, byte* fn, ...)
-{
- Defer *d;
- int32 mallocsiz;
-
- mallocsiz = sizeof(*d);
- if(siz > sizeof(d->args))
- mallocsiz += siz - sizeof(d->args);
- d = runtime·malloc(mallocsiz);
- d->fn = fn;
- d->siz = siz;
- d->pc = runtime·getcallerpc(&siz);
- if(thechar == '5')
- d->argp = (byte*)(&fn+2); // skip caller's saved link register
- else
- d->argp = (byte*)(&fn+1);
- runtime·memmove(d->args, d->argp, d->siz);
-
- d->link = g->defer;
- g->defer = d;
-
- // deferproc returns 0 normally.
- // a deferred func that stops a panic
- // makes the deferproc return 1.
- // the code the compiler generates always
- // checks the return value and jumps to the
- // end of the function if deferproc returns != 0.
- return 0;
-}
-
-// Run a deferred function if there is one.
-// The compiler inserts a call to this at the end of any
-// function which calls defer.
-// If there is a deferred function, this will call runtime·jmpdefer,
-// which will jump to the deferred function such that it appears
-// to have been called by the caller of deferreturn at the point
-// just before deferreturn was called. The effect is that deferreturn
-// is called again and again until there are no more deferred functions.
-// Cannot split the stack because we reuse the caller's frame to
-// call the deferred function.
-#pragma textflag 7
-void
-runtime·deferreturn(uintptr arg0)
-{
- Defer *d;
- byte *argp, *fn;
-
- d = g->defer;
- if(d == nil)
- return;
- argp = (byte*)&arg0;
- if(d->argp != argp)
- return;
- runtime·memmove(argp, d->args, d->siz);
- g->defer = d->link;
- fn = d->fn;
- if(!d->nofree)
- runtime·free(d);
- runtime·jmpdefer(fn, argp);
-}
-
-// Run all deferred functions for the current goroutine.
-static void
-rundefer(void)
-{
- Defer *d;
-
- while((d = g->defer) != nil) {
- g->defer = d->link;
- reflect·call(d->fn, (byte*)d->args, d->siz);
- if(!d->nofree)
- runtime·free(d);
- }
-}
-
-// Free stack frames until we hit the last one
-// or until we find the one that contains the sp.
-static void
-unwindstack(G *gp, byte *sp)
-{
- Stktop *top;
- byte *stk;
-
- // Must be called from a different goroutine, usually m->g0.
- if(g == gp)
- runtime·throw("unwindstack on self");
-
- while((top = (Stktop*)gp->stackbase) != nil && top->stackbase != nil) {
- stk = (byte*)gp->stackguard - StackGuard;
- if(stk <= sp && sp < (byte*)gp->stackbase)
- break;
- gp->stackbase = (uintptr)top->stackbase;
- gp->stackguard = (uintptr)top->stackguard;
- if(top->free != 0)
- runtime·stackfree(stk, top->free);
- }
-
- if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) {
- runtime·printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase);
- runtime·throw("bad unwindstack");
- }
-}
-
-// Print all currently active panics. Used when crashing.
-static void
-printpanics(Panic *p)
-{
- if(p->link) {
- printpanics(p->link);
- runtime·printf("\t");
- }
- runtime·printf("panic: ");
- runtime·printany(p->arg);
- if(p->recovered)
- runtime·printf(" [recovered]");
- runtime·printf("\n");
-}
-
-static void recovery(G*);
-
-// The implementation of the predeclared function panic.
-void
-runtime·panic(Eface e)
-{
- Defer *d;
- Panic *p;
-
- p = runtime·mal(sizeof *p);
- p->arg = e;
- p->link = g->panic;
- p->stackbase = (byte*)g->stackbase;
- g->panic = p;
-
- for(;;) {
- d = g->defer;
- if(d == nil)
- break;
- // take defer off list in case of recursive panic
- g->defer = d->link;
- g->ispanic = true; // rock for newstack, where reflect.call ends up
- reflect·call(d->fn, (byte*)d->args, d->siz);
- if(p->recovered) {
- g->panic = p->link;
- if(g->panic == nil) // must be done with signal
- g->sig = 0;
- runtime·free(p);
- // put recovering defer back on list
- // for scheduler to find.
- d->link = g->defer;
- g->defer = d;
- runtime·mcall(recovery);
- runtime·throw("recovery failed"); // mcall should not return
- }
- if(!d->nofree)
- runtime·free(d);
- }
-
- // ran out of deferred calls - old-school panic now
- runtime·startpanic();
- printpanics(g->panic);
- runtime·dopanic(0);
-}
-
-// Unwind the stack after a deferred function calls recover
-// after a panic. Then arrange to continue running as though
-// the caller of the deferred function returned normally.
-static void
-recovery(G *gp)
-{
- Defer *d;
-
- // Rewind gp's stack; we're running on m->g0's stack.
- d = gp->defer;
- gp->defer = d->link;
-
- // Unwind to the stack frame with d's arguments in it.
- unwindstack(gp, d->argp);
-
- // Make the deferproc for this d return again,
- // this time returning 1. The calling function will
- // jump to the standard return epilogue.
- // The -2*sizeof(uintptr) makes up for the
- // two extra words that are on the stack at
- // each call to deferproc.
- // (The pc we're returning to does pop pop
- // before it tests the return value.)
- // On the arm there are 2 saved LRs mixed in too.
- if(thechar == '5')
- gp->sched.sp = (uintptr)d->argp - 4*sizeof(uintptr);
- else
- gp->sched.sp = (uintptr)d->argp - 2*sizeof(uintptr);
- gp->sched.pc = d->pc;
- if(!d->nofree)
- runtime·free(d);
- runtime·gogo(&gp->sched, 1);
-}
-
-// The implementation of the predeclared function recover.
-// Cannot split the stack because it needs to reliably
-// find the stack segment of its caller.
-#pragma textflag 7
-void
-runtime·recover(byte *argp, Eface ret)
-{
- Stktop *top, *oldtop;
- Panic *p;
-
- // Must be a panic going on.
- if((p = g->panic) == nil || p->recovered)
- goto nomatch;
-
- // Frame must be at the top of the stack segment,
- // because each deferred call starts a new stack
- // segment as a side effect of using reflect.call.
- // (There has to be some way to remember the
- // variable argument frame size, and the segment
- // code already takes care of that for us, so we
- // reuse it.)
- //
- // As usual closures complicate things: the fp that
- // the closure implementation function claims to have
- // is where the explicit arguments start, after the
- // implicit pointer arguments and PC slot.
- // If we're on the first new segment for a closure,
- // then fp == top - top->args is correct, but if
- // the closure has its own big argument frame and
- // allocated a second segment (see below),
- // the fp is slightly above top - top->args.
- // That condition can't happen normally though
- // (stack pointers go down, not up), so we can accept
- // any fp between top and top - top->args as
- // indicating the top of the segment.
- top = (Stktop*)g->stackbase;
- if(argp < (byte*)top - top->argsize || (byte*)top < argp)
- goto nomatch;
-
- // The deferred call makes a new segment big enough
- // for the argument frame but not necessarily big
- // enough for the function's local frame (size unknown
- // at the time of the call), so the function might have
- // made its own segment immediately. If that's the
- // case, back top up to the older one, the one that
- // reflect.call would have made for the panic.
- //
- // The fp comparison here checks that the argument
- // frame that was copied during the split (the top->args
- // bytes above top->fp) abuts the old top of stack.
- // This is a correct test for both closure and non-closure code.
- oldtop = (Stktop*)top->stackbase;
- if(oldtop != nil && top->argp == (byte*)oldtop - top->argsize)
- top = oldtop;
-
- // Now we have the segment that was created to
- // run this call. It must have been marked as a panic segment.
- if(!top->panic)
- goto nomatch;
-
- // Okay, this is the top frame of a deferred call
- // in response to a panic. It can see the panic argument.
- p->recovered = 1;
- ret = p->arg;
- FLUSH(&ret);
- return;
-
-nomatch:
- ret.type = nil;
- ret.data = nil;
- FLUSH(&ret);
-}
-
-
// Put on gfree list. Sched must be locked.
static void
gfput(G *gp)
runtime·breakpoint();
}
-void
-runtime·Goexit(void)
-{
- rundefer();
- runtime·goexit();
-}
-
void
runtime·Gosched(void)
{
if(hz != 0)
runtime·resetcpuprofiler(hz);
}
-
-void (*libcgo_setenv)(byte**);
-
-// Update the C environment if cgo is loaded.
-// Called from syscall.Setenv.
-void
-syscall·setenv_c(String k, String v)
-{
- byte *arg[2];
-
- if(libcgo_setenv == nil)
- return;
-
- arg[0] = runtime·malloc(k.len + 1);
- runtime·memmove(arg[0], k.str, k.len);
- arg[0][k.len] = 0;
-
- arg[1] = runtime·malloc(v.len + 1);
- runtime·memmove(arg[1], v.str, v.len);
- arg[1][v.len] = 0;
-
- runtime·asmcgocall((void*)libcgo_setenv, arg);
- runtime·free(arg[0]);
- runtime·free(arg[1]);
-}
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "stack.h"
#include "arch_GOARCH.h"
enum {
maxround = sizeof(uintptr),
};
-uint32 runtime·panicking;
-void (*runtime·destroylock)(Lock*);
-
/*
* We assume that all architectures turn faults and the like
* into apparent calls to runtime.sigpanic. If we see a "call"
return runtime·atoi(p);
}
-static Lock paniclk;
-
-void
-runtime·startpanic(void)
-{
- if(m->dying) {
- runtime·printf("panic during panic\n");
- runtime·exit(3);
- }
- m->dying = 1;
- runtime·xadd(&runtime·panicking, 1);
- runtime·lock(&paniclk);
-}
-
-void
-runtime·dopanic(int32 unused)
-{
- static bool didothers;
-
- if(g->sig != 0)
- runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
- g->sig, g->sigcode0, g->sigcode1, g->sigpc);
-
- if(runtime·gotraceback()){
- if(g != m->g0) {
- runtime·printf("\n");
- runtime·goroutineheader(g);
- runtime·traceback(runtime·getcallerpc(&unused), runtime·getcallersp(&unused), 0, g);
- }
- if(!didothers) {
- didothers = true;
- runtime·tracebackothers(g);
- }
- }
- runtime·unlock(&paniclk);
- if(runtime·xadd(&runtime·panicking, -1) != 0) {
- // Some other m is panicking too.
- // Let it print what it needs to print.
- // Wait forever without chewing up cpu.
- // It will exit when it's done.
- static Lock deadlock;
- runtime·lock(&deadlock);
- runtime·lock(&deadlock);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·panicindex(void)
-{
- runtime·panicstring("index out of range");
-}
-
-void
-runtime·panicslice(void)
-{
- runtime·panicstring("slice bounds out of range");
-}
-
-void
-runtime·throwreturn(void)
-{
- // can only happen if compiler is broken
- runtime·throw("no return at end of a typed function - compiler is broken");
-}
-
-void
-runtime·throwinit(void)
-{
- // can only happen with linker skew
- runtime·throw("recursive call during initialization - linker skew");
-}
-
-void
-runtime·throw(int8 *s)
-{
- runtime·startpanic();
- runtime·printf("throw: %s\n", s);
- runtime·dopanic(0);
- *(int32*)0 = 0; // not reached
- runtime·exit(1); // even more not reached
-}
-
-void
-runtime·panicstring(int8 *s)
-{
- Eface err;
-
- if(m->gcing) {
- runtime·printf("panic: %s\n", s);
- runtime·throw("panic during gc");
- }
- runtime·newErrorString(runtime·gostringnocopy((byte*)s), &err);
- runtime·panic(err);
-}
-
int32
runtime·mcmp(byte *s1, byte *s2, uint32 n)
{
return nil;
}
+void (*libcgo_setenv)(byte**);
+
+// Update the C environment if cgo is loaded.
+// Called from syscall.Setenv.
+void
+syscall·setenv_c(String k, String v)
+{
+ byte *arg[2];
+
+ if(libcgo_setenv == nil)
+ return;
+
+ arg[0] = runtime·malloc(k.len + 1);
+ runtime·memmove(arg[0], k.str, k.len);
+ arg[0][k.len] = 0;
+
+ arg[1] = runtime·malloc(v.len + 1);
+ runtime·memmove(arg[1], v.str, v.len);
+ arg[1][v.len] = 0;
+
+ runtime·asmcgocall((void*)libcgo_setenv, arg);
+ runtime·free(arg[0]);
+ runtime·free(arg[1]);
+}
+
void
runtime·getgoroot(String out)
{
int64 runtime·nanotime(void);
void runtime·dopanic(int32);
void runtime·startpanic(void);
+void runtime·unwindstack(G*, byte*);
void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp);
void runtime·resetcpuprofiler(int32);
void runtime·setcpuprofilerate(void(*)(uintptr*, int32), int32);