1
0
mirror of https://github.com/golang/go synced 2024-10-02 20:31:21 -06:00
go/src/runtime/os_dragonfly.c
Russ Cox 15b76ad94b runtime: assume precisestack, copystack, StackCopyAlways, ScanStackByFrames
Commit to stack copying for stack growth.

We're carrying around a surprising amount of cruft from older schemes.
I am confident that precise stack scans and stack copying are here to stay.

Delete fallback code for when precise stack info is disabled.
Delete fallback code for when copying stacks is disabled.
Delete fallback code for when StackCopyAlways is disabled.
Delete Stktop chain - there is only one stack segment now.
Delete M.moreargp, M.moreargsize, M.moreframesize, M.cret.
Delete G.writenbuf (unrelated, just dead).
Delete runtime.lessstack, runtime.oldstack.
Delete many amd64 morestack variants.
Delete initialization of morestack frame/arg sizes (shortens split prologue!).

Replace G's stackguard/stackbase/stack0/stacksize/
syscallstack/syscallguard/forkstackguard with simple stack
bounds (lo, hi).

Update liblink, runtime/cgo for adjustments to G.

LGTM=khr
R=khr, bradfitz
CC=golang-codereviews, iant, r
https://golang.org/cl/137410043
2014-09-09 13:39:57 -04:00

313 lines
6.4 KiB
C

// Copyright 2011 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 "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
#include "signal_unix.h"
#include "stack.h"
#include "textflag.h"
extern SigTab runtime·sigtab[];
extern int32 runtime·sys_umtx_sleep(uint32*, int32, int32);
extern int32 runtime·sys_umtx_wakeup(uint32*, int32);
// From DragonFly's <sys/sysctl.h>
#define CTL_HW 6
#define HW_NCPU 3
static Sigset sigset_none;
static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
static int32
getncpu(void)
{
uint32 mib[2];
uint32 out;
int32 ret;
uintptr nout;
// Fetch hw.ncpu via sysctl.
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
nout = sizeof out;
out = 0;
ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
if(ret >= 0)
return out;
else
return 1;
}
static void futexsleep(void);
#pragma textflag NOSPLIT
void
runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
{
void (*fn)(void);
g->m->ptrarg[0] = addr;
g->m->scalararg[0] = val;
g->m->ptrarg[1] = &ns;
fn = futexsleep;
runtime·onM(&fn);
}
static void
futexsleep(void)
{
uint32 *addr;
uint32 val;
int64 ns;
int32 timeout = 0;
int32 ret;
addr = g->m->ptrarg[0];
val = g->m->scalararg[0];
ns = *(int64*)g->m->ptrarg[1];
g->m->ptrarg[0] = nil;
g->m->scalararg[0] = 0;
g->m->ptrarg[1] = nil;
if(ns >= 0) {
// The timeout is specified in microseconds - ensure that we
// do not end up dividing to zero, which would put us to sleep
// indefinitely...
timeout = runtime·timediv(ns, 1000, nil);
if(timeout == 0)
timeout = 1;
}
// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
// expires or EBUSY if the mutex value does not match.
ret = runtime·sys_umtx_sleep(addr, val, timeout);
if(ret >= 0 || ret == -EINTR || ret == -EAGAIN || ret == -EBUSY)
return;
runtime·prints("umtx_wait addr=");
runtime·printpointer(addr);
runtime·prints(" val=");
runtime·printint(val);
runtime·prints(" ret=");
runtime·printint(ret);
runtime·prints("\n");
*(int32*)0x1005 = 0x1005;
}
static void badfutexwakeup(void);
#pragma textflag NOSPLIT
void
runtime·futexwakeup(uint32 *addr, uint32 cnt)
{
int32 ret;
void (*fn)(void);
ret = runtime·sys_umtx_wakeup(addr, cnt);
if(ret >= 0)
return;
g->m->ptrarg[0] = addr;
g->m->scalararg[0] = ret;
fn = badfutexwakeup;
if(g == g->m->gsignal)
fn();
else
runtime·onM(&fn);
*(int32*)0x1006 = 0x1006;
}
static void
badfutexwakeup(void)
{
void *addr;
int32 ret;
addr = g->m->ptrarg[0];
ret = g->m->scalararg[0];
runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
}
void runtime·lwp_start(void*);
void
runtime·newosproc(M *mp, void *stk)
{
Lwpparams params;
Sigset oset;
if(0){
runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
}
runtime·sigprocmask(&sigset_all, &oset);
runtime·memclr((byte*)&params, sizeof params);
params.func = runtime·lwp_start;
params.arg = (byte*)mp;
params.stack = (byte*)stk;
params.tid1 = (int32*)&mp->procid;
params.tid2 = nil;
mp->tls[0] = mp->id; // so 386 asm can find it
runtime·lwp_create(&params);
runtime·sigprocmask(&oset, nil);
}
void
runtime·osinit(void)
{
runtime·ncpu = getncpu();
}
#pragma textflag NOSPLIT
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
#pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
*rnd = urandom_data;
*rnd_len = HashRandomBytes;
} else {
*rnd = nil;
*rnd_len = 0;
}
runtime·close(fd);
}
void
runtime·goenvs(void)
{
runtime·goenvs_unix();
}
// Called to initialize a new m (including the bootstrap m).
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
void
runtime·mpreinit(M *mp)
{
mp->gsignal = runtime·malg(32*1024);
mp->gsignal->m = mp;
}
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
void
runtime·minit(void)
{
// Initialize signal handling
runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
runtime·sigprocmask(&sigset_none, nil);
}
// Called from dropm to undo the effect of an minit.
void
runtime·unminit(void)
{
runtime·signalstack(nil, 0);
}
uintptr
runtime·memlimit(void)
{
Rlimit rl;
extern byte runtime·text[], runtime·end[];
uintptr used;
if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
return 0;
if(rl.rlim_cur >= 0x7fffffff)
return 0;
// Estimate our VM footprint excluding the heap.
// Not an exact science: use size of binary plus
// some room for thread stacks.
used = runtime·end - runtime·text + (64<<20);
if(used >= rl.rlim_cur)
return 0;
// If there's not at least 16 MB left, we're probably
// not going to be able to do much. Treat as no limit.
rl.rlim_cur -= used;
if(rl.rlim_cur < (16<<20))
return 0;
return rl.rlim_cur - used;
}
extern void runtime·sigtramp(void);
typedef struct sigaction {
union {
void (*__sa_handler)(int32);
void (*__sa_sigaction)(int32, Siginfo*, void *);
} __sigaction_u; /* signal handler */
int32 sa_flags; /* see signal options below */
Sigset sa_mask; /* signal mask to apply */
} SigactionT;
void
runtime·setsig(int32 i, GoSighandler *fn, bool restart)
{
SigactionT sa;
runtime·memclr((byte*)&sa, sizeof sa);
sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
if(restart)
sa.sa_flags |= SA_RESTART;
sa.sa_mask.__bits[0] = ~(uint32)0;
sa.sa_mask.__bits[1] = ~(uint32)0;
sa.sa_mask.__bits[2] = ~(uint32)0;
sa.sa_mask.__bits[3] = ~(uint32)0;
if(fn == runtime·sighandler)
fn = (void*)runtime·sigtramp;
sa.__sigaction_u.__sa_sigaction = (void*)fn;
runtime·sigaction(i, &sa, nil);
}
GoSighandler*
runtime·getsig(int32 i)
{
SigactionT sa;
runtime·memclr((byte*)&sa, sizeof sa);
runtime·sigaction(i, nil, &sa);
if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
return runtime·sighandler;
return (void*)sa.__sigaction_u.__sa_sigaction;
}
void
runtime·signalstack(byte *p, int32 n)
{
StackT st;
st.ss_sp = (void*)p;
st.ss_size = n;
st.ss_flags = 0;
if(p == nil)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
void
runtime·unblocksignals(void)
{
runtime·sigprocmask(&sigset_none, nil);
}
#pragma textflag NOSPLIT
int8*
runtime·signame(int32 sig)
{
return runtime·sigtab[sig].name;
}