1
0
mirror of https://github.com/golang/go synced 2024-11-25 01:17:56 -07:00

runtime: Changes to the runtime to support NetBSD.

R=rsc
CC=golang-dev
https://golang.org/cl/5477052
This commit is contained in:
Christopher Nielsen 2011-12-12 18:10:11 -05:00 committed by Russ Cox
parent ecf4a9216e
commit 26089cfe25
13 changed files with 1758 additions and 0 deletions

View File

@ -0,0 +1,146 @@
// godefs -f -m32 defs.c
// MACHINE GENERATED - DO NOT EDIT.
// Constants
enum {
PROT_NONE = 0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
PROT_EXEC = 0x4,
MAP_ANON = 0x1000,
MAP_PRIVATE = 0x2,
MAP_FIXED = 0x10,
SA_SIGINFO = 0x40,
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
EINTR = 0x4,
SIGHUP = 0x1,
SIGINT = 0x2,
SIGQUIT = 0x3,
SIGILL = 0x4,
SIGTRAP = 0x5,
SIGABRT = 0x6,
SIGEMT = 0x7,
SIGFPE = 0x8,
SIGKILL = 0x9,
SIGBUS = 0xa,
SIGSEGV = 0xb,
SIGSYS = 0xc,
SIGPIPE = 0xd,
SIGALRM = 0xe,
SIGTERM = 0xf,
SIGURG = 0x10,
SIGSTOP = 0x11,
SIGTSTP = 0x12,
SIGCONT = 0x13,
SIGCHLD = 0x14,
SIGTTIN = 0x15,
SIGTTOU = 0x16,
SIGIO = 0x17,
SIGXCPU = 0x18,
SIGXFSZ = 0x19,
SIGVTALRM = 0x1a,
SIGPROF = 0x1b,
SIGWINCH = 0x1c,
SIGINFO = 0x1d,
SIGUSR1 = 0x1e,
SIGUSR2 = 0x1f,
FPE_INTDIV = 0x1,
FPE_INTOVF = 0x2,
FPE_FLTDIV = 0x3,
FPE_FLTOVF = 0x4,
FPE_FLTUND = 0x5,
FPE_FLTRES = 0x6,
FPE_FLTINV = 0x7,
FPE_FLTSUB = 0x8,
BUS_ADRALN = 0x1,
BUS_ADRERR = 0x2,
BUS_OBJERR = 0x3,
SEGV_MAPERR = 0x1,
SEGV_ACCERR = 0x2,
ITIMER_REAL = 0,
ITIMER_VIRTUAL = 0x1,
ITIMER_PROF = 0x2,
};
// Types
#pragma pack on
typedef struct Sigaltstack Sigaltstack;
struct Sigaltstack {
void *ss_sp;
uint32 ss_size;
int32 ss_flags;
};
typedef uint32 Sigset;
typedef struct Siginfo Siginfo;
struct Siginfo {
int32 si_signo;
int32 si_code;
int32 si_errno;
byte _data[116];
};
typedef union Sigval Sigval;
union Sigval {
int32 sival_int;
void *sival_ptr;
};
typedef struct StackT StackT;
struct StackT {
void *ss_sp;
uint32 ss_size;
int32 ss_flags;
};
typedef struct Timespec Timespec;
struct Timespec {
int32 tv_sec;
int32 tv_nsec;
};
typedef struct Timeval Timeval;
struct Timeval {
int32 tv_sec;
int32 tv_usec;
};
typedef struct Itimerval Itimerval;
struct Itimerval {
Timeval it_interval;
Timeval it_value;
};
typedef void sfxsave64;
typedef void usavefpu;
typedef struct Sigcontext Sigcontext;
struct Sigcontext {
int32 sc_gs;
int32 sc_fs;
int32 sc_es;
int32 sc_ds;
int32 sc_edi;
int32 sc_esi;
int32 sc_ebp;
int32 sc_ebx;
int32 sc_edx;
int32 sc_ecx;
int32 sc_eax;
int32 sc_eip;
int32 sc_cs;
int32 sc_eflags;
int32 sc_esp;
int32 sc_ss;
int32 sc_onstack;
int32 sc_mask;
int32 sc_trapno;
int32 sc_err;
usavefpu *sc_fpstate;
};
#pragma pack off

View File

@ -0,0 +1,6 @@
// 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.
TEXT _rt0_386_netbsd(SB),7,$0
JMP _rt0_386(SB)

View File

@ -0,0 +1,189 @@
// 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 "runtime.h"
#include "defs.h"
#include "signals.h"
#include "os.h"
extern void runtime·sigtramp(void);
typedef struct sigaction {
union {
void (*__sa_handler)(int32);
void (*__sa_sigaction)(int32, Siginfo*, void *);
} __sigaction_u; /* signal handler */
uint32 sa_mask; /* signal mask to apply */
int32 sa_flags; /* see signal options below */
} Sigaction;
void
runtime·dumpregs(Sigcontext *r)
{
runtime·printf("eax %x\n", r->sc_eax);
runtime·printf("ebx %x\n", r->sc_ebx);
runtime·printf("ecx %x\n", r->sc_ecx);
runtime·printf("edx %x\n", r->sc_edx);
runtime·printf("edi %x\n", r->sc_edi);
runtime·printf("esi %x\n", r->sc_esi);
runtime·printf("ebp %x\n", r->sc_ebp);
runtime·printf("esp %x\n", r->sc_esp);
runtime·printf("eip %x\n", r->sc_eip);
runtime·printf("eflags %x\n", r->sc_eflags);
runtime·printf("cs %x\n", r->sc_cs);
runtime·printf("fs %x\n", r->sc_fs);
runtime·printf("gs %x\n", r->sc_gs);
}
String
runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
return runtime·emptystring;
return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
Sigcontext *r = context;
uintptr *sp;
if(sig == SIGPROF) {
runtime·sigprof((uint8*)r->sc_eip, (uint8*)r->sc_esp, nil, gp);
return;
}
if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = sig;
gp->sigcode0 = info->si_code;
gp->sigcode1 = *(uintptr*)((byte*)info + 12); /* si_addr */
gp->sigpc = r->sc_eip;
// Only push runtime·sigpanic if r->sc_eip != 0.
// If r->sc_eip == 0, probably panicked because of a
// call to a nil func. Not pushing that onto sp will
// make the trace look like a call to runtime·sigpanic instead.
// (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->sc_eip != 0) {
sp = (uintptr*)r->sc_esp;
*--sp = r->sc_eip;
r->sc_esp = (uintptr)sp;
}
r->sc_eip = (uintptr)runtime·sigpanic;
return;
}
if(runtime·sigtab[sig].flags & SigQueue) {
if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
runtime·exit(2); // SIGINT, SIGTERM, etc
}
if(runtime·panicking) // traceback already printed
runtime·exit(2);
runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
runtime·printf("Signal %d\n", sig);
else
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", r->sc_eip);
runtime·printf("\n");
if(runtime·gotraceback()){
runtime·traceback((void*)r->sc_eip, (void*)r->sc_esp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}
runtime·exit(2);
}
// Called from kernel on signal stack, so no stack split.
#pragma textflag 7
void
runtime·sigignore(void)
{
}
void
runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = (int8*)p;
st.ss_size = n;
st.ss_flags = 0;
runtime·sigaltstack(&st, nil);
}
static void
sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
runtime·memclr((byte*)&sa, sizeof sa);
sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
if(restart)
sa.sa_flags |= SA_RESTART;
sa.sa_mask = ~0ULL;
if (fn == runtime·sighandler)
fn = (void*)runtime·sigtramp;
sa.__sigaction_u.__sa_sigaction = (void*)fn;
runtime·sigaction(i, &sa, nil);
}
void
runtime·initsig(int32 queue)
{
int32 i;
void *fn;
runtime·siginit();
for(i = 0; i<NSIG; i++) {
if(runtime·sigtab[i].flags) {
if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
fn = runtime·sighandler;
else
fn = runtime·sigignore;
sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
}
}
}
void
runtime·resetcpuprofiler(int32 hz)
{
Itimerval it;
runtime·memclr((byte*)&it, sizeof it);
if(hz == 0) {
runtime·setitimer(ITIMER_PROF, &it, nil);
sigaction(SIGPROF, SIG_IGN, true);
} else {
sigaction(SIGPROF, runtime·sighandler, true);
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 1000000 / hz;
it.it_value = it.it_interval;
runtime·setitimer(ITIMER_PROF, &it, nil);
}
m->profilehz = hz;
}
void
os·sigpipe(void)
{
sigaction(SIGPIPE, SIG_DFL, false);
runtime·raisesigpipe();
}

View File

@ -0,0 +1,324 @@
// 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.
//
// System calls and other sys.stuff for 386, NetBSD
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
#include "386/asm.h"
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),7,$-4
MOVL $1, AX
INT $0x80
CALL runtime·notok(SB)
RET
TEXT runtime·exit1(SB),7,$-4
MOVL $302, AX // sys_threxit
INT $0x80
JAE 2(PC)
CALL runtime·notok(SB)
RET
TEXT runtime·write(SB),7,$-4
MOVL $4, AX // sys_write
INT $0x80
RET
TEXT runtime·usleep(SB),7,$20
MOVL $0, DX
MOVL usec+0(FP), AX
MOVL $1000000, CX
DIVL CX
MOVL AX, 12(SP) // tv_sec
MOVL $1000, AX
MULL DX
MOVL AX, 16(SP) // tv_nsec
MOVL $0, 0(SP)
LEAL 12(SP), AX
MOVL AX, 4(SP) // arg 1 - rqtp
MOVL $0, 8(SP) // arg 2 - rmtp
MOVL $240, AX // sys_nanosleep
INT $0x80
RET
TEXT runtime·raisesigpipe(SB),7,$12
MOVL $299, AX // sys_getthrid
INT $0x80
MOVL $0, 0(SP)
MOVL AX, 4(SP) // arg 1 - pid
MOVL $13, 8(SP) // arg 2 - signum == SIGPIPE
MOVL $37, AX // sys_kill
INT $0x80
RET
TEXT runtime·notok(SB),7,$0
MOVL $0xf1, 0xf1
RET
TEXT runtime·mmap(SB),7,$36
LEAL arg0+0(FP), SI
LEAL 4(SP), DI
CLD
MOVSL // arg 1 - addr
MOVSL // arg 2 - len
MOVSL // arg 3 - prot
MOVSL // arg 4 - flags
MOVSL // arg 5 - fd
MOVL $0, AX
STOSL // arg 6 - pad
MOVSL // arg 7 - offset
MOVL $0, AX // top 64 bits of file offset
STOSL
MOVL $197, AX // sys_mmap
INT $0x80
JCC 2(PC)
NEGL AX
RET
TEXT runtime·munmap(SB),7,$-4
MOVL $73, AX // sys_munmap
INT $0x80
JAE 2(PC)
CALL runtime·notok(SB)
RET
TEXT runtime·setitimer(SB),7,$-4
MOVL $83, AX
INT $0x80
RET
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
MOVL $116, AX
LEAL 12(SP), BX
MOVL BX, 4(SP)
MOVL $0, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
MOVL 16(SP), BX // usec
// sec is in AX, usec in BX
MOVL AX, sec+0(FP)
MOVL $0, sec+4(FP)
IMULL $1000, BX
MOVL BX, nsec+8(FP)
RET
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB),7,$32
MOVL $116, AX
LEAL 12(SP), BX
MOVL BX, 4(SP)
MOVL $0, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
MOVL 16(SP), BX // usec
// sec is in AX, usec in BX
// convert to DX:AX nsec
MOVL $1000000000, CX
MULL CX
IMULL $1000, BX
ADDL BX, AX
ADCL $0, DX
MOVL ret+0(FP), DI
MOVL AX, 0(DI)
MOVL DX, 4(DI)
RET
TEXT runtime·sigaction(SB),7,$-4
MOVL $46, AX // sys_sigaction
INT $0x80
JAE 2(PC)
CALL runtime·notok(SB)
RET
TEXT runtime·sigtramp(SB),7,$44
get_tls(CX)
// save g
MOVL g(CX), DI
MOVL DI, 20(SP)
// g = m->gsignal
MOVL m(CX), BX
MOVL m_gsignal(BX), BX
MOVL BX, g(CX)
// copy arguments for call to sighandler
MOVL signo+0(FP), BX
MOVL BX, 0(SP)
MOVL info+4(FP), BX
MOVL BX, 4(SP)
MOVL context+8(FP), BX
MOVL BX, 8(SP)
MOVL DI, 12(SP)
CALL runtime·sighandler(SB)
// restore g
get_tls(CX)
MOVL 20(SP), BX
MOVL BX, g(CX)
// call sigreturn
MOVL context+8(FP), AX
MOVL $0, 0(SP) // syscall gap
MOVL AX, 4(SP) // arg 1 - sigcontext
MOVL $103, AX // sys_sigreturn
INT $0x80
CALL runtime·notok(SB)
RET
// int32 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
TEXT runtime·rfork_thread(SB),7,$8
MOVL flags+8(SP), AX
MOVL stack+12(SP), CX
// Copy m, g, fn off parent stack for use by child.
SUBL $16, CX
MOVL mm+16(SP), SI
MOVL SI, 0(CX)
MOVL gg+20(SP), SI
MOVL SI, 4(CX)
MOVL fn+24(SP), SI
MOVL SI, 8(CX)
MOVL $1234, 12(CX)
MOVL CX, SI
MOVL $0, 0(SP) // syscall gap
MOVL AX, 4(SP) // arg 1 - flags
MOVL $251, AX // sys_rfork
INT $0x80
// Return if rfork syscall failed
JCC 4(PC)
NEGL AX
MOVL AX, 48(SP)
RET
// In parent, return.
CMPL AX, $0
JEQ 3(PC)
MOVL AX, 48(SP)
RET
// In child, on new stack.
MOVL SI, SP
// Paranoia: check that SP is as we expect.
MOVL 12(SP), BP
CMPL BP, $1234
JEQ 2(PC)
INT $3
// Reload registers
MOVL 0(SP), BX // m
MOVL 4(SP), DX // g
MOVL 8(SP), SI // fn
// Initialize m->procid to thread ID
MOVL $299, AX // sys_getthrid
INT $0x80
MOVL AX, m_procid(BX)
// Set FS to point at m->tls
LEAL m_tls(BX), BP
PUSHAL // save registers
PUSHL BP
CALL runtime·settls(SB)
POPL AX
POPAL
// Now segment is established. Initialize m, g.
get_tls(AX)
MOVL DX, g(AX)
MOVL BX, m(AX)
CALL runtime·stackcheck(SB) // smashes AX, CX
MOVL 0(DX), DX // paranoia; check they are not nil
MOVL 0(BX), BX
// more paranoia; check that stack splitting code works
PUSHAL
CALL runtime·emptyfunc(SB)
POPAL
// Call fn
CALL SI
CALL runtime·exit1(SB)
MOVL $0x1234, 0x1005
RET
TEXT runtime·sigaltstack(SB),7,$-8
MOVL $288, AX // sys_sigaltstack
MOVL new+4(SP), BX
MOVL old+8(SP), CX
INT $0x80
CMPL AX, $0xfffff001
JLS 2(PC)
INT $3
RET
TEXT runtime·setldt(SB),7,$8
// Under NetBSD we set the GS base instead of messing with the LDT.
MOVL 16(SP), AX // tls0
MOVL AX, 0(SP)
CALL runtime·settls(SB)
RET
TEXT runtime·settls(SB),7,$16
// adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
MOVL 20(SP), CX
ADDL $8, CX
MOVL CX, 0(CX)
MOVL $0, 0(SP) // syscall gap
MOVL $9, 4(SP) // I386_SET_GSBASE (machine/sysarch.h)
MOVL CX, 8(SP) // pointer to base
MOVL $165, AX // sys_sysarch
INT $0x80
JCC 2(PC)
CALL runtime·notok(SB)
RET
TEXT runtime·osyield(SB),7,$-4
MOVL $298, AX // sys_sched_yield
INT $0x80
RET
TEXT runtime·thrsleep(SB),7,$-4
MOVL $300, AX // sys_thrsleep
INT $0x80
RET
TEXT runtime·thrwakeup(SB),7,$-4
MOVL $301, AX // sys_thrwakeup
INT $0x80
RET
TEXT runtime·sysctl(SB),7,$28
LEAL arg0+0(FP), SI
LEAL 4(SP), DI
CLD
MOVSL // arg 1 - name
MOVSL // arg 2 - namelen
MOVSL // arg 3 - oldp
MOVSL // arg 4 - oldlenp
MOVSL // arg 5 - newp
MOVSL // arg 6 - newlen
MOVL $202, AX // sys___sysctl
INT $0x80
JCC 3(PC)
NEGL AX
RET
MOVL $0, AX
RET
GLOBL runtime·tlsoffset(SB),$4

View File

@ -0,0 +1,158 @@
// godefs -f -m64 defs.c
// MACHINE GENERATED - DO NOT EDIT.
// Constants
enum {
PROT_NONE = 0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
PROT_EXEC = 0x4,
MAP_ANON = 0x1000,
MAP_PRIVATE = 0x2,
MAP_FIXED = 0x10,
SA_SIGINFO = 0x40,
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
EINTR = 0x4,
SIGHUP = 0x1,
SIGINT = 0x2,
SIGQUIT = 0x3,
SIGILL = 0x4,
SIGTRAP = 0x5,
SIGABRT = 0x6,
SIGEMT = 0x7,
SIGFPE = 0x8,
SIGKILL = 0x9,
SIGBUS = 0xa,
SIGSEGV = 0xb,
SIGSYS = 0xc,
SIGPIPE = 0xd,
SIGALRM = 0xe,
SIGTERM = 0xf,
SIGURG = 0x10,
SIGSTOP = 0x11,
SIGTSTP = 0x12,
SIGCONT = 0x13,
SIGCHLD = 0x14,
SIGTTIN = 0x15,
SIGTTOU = 0x16,
SIGIO = 0x17,
SIGXCPU = 0x18,
SIGXFSZ = 0x19,
SIGVTALRM = 0x1a,
SIGPROF = 0x1b,
SIGWINCH = 0x1c,
SIGINFO = 0x1d,
SIGUSR1 = 0x1e,
SIGUSR2 = 0x1f,
FPE_INTDIV = 0x1,
FPE_INTOVF = 0x2,
FPE_FLTDIV = 0x3,
FPE_FLTOVF = 0x4,
FPE_FLTUND = 0x5,
FPE_FLTRES = 0x6,
FPE_FLTINV = 0x7,
FPE_FLTSUB = 0x8,
BUS_ADRALN = 0x1,
BUS_ADRERR = 0x2,
BUS_OBJERR = 0x3,
SEGV_MAPERR = 0x1,
SEGV_ACCERR = 0x2,
ITIMER_REAL = 0,
ITIMER_VIRTUAL = 0x1,
ITIMER_PROF = 0x2,
};
// Types
#pragma pack on
typedef struct Sigaltstack Sigaltstack;
struct Sigaltstack {
void *ss_sp;
uint64 ss_size;
int32 ss_flags;
byte pad_godefs_0[4];
};
typedef uint32 Sigset;
typedef struct Siginfo Siginfo;
struct Siginfo {
int32 si_signo;
int32 si_code;
int32 si_errno;
byte pad_godefs_0[4];
byte _data[120];
};
typedef union Sigval Sigval;
union Sigval {
int32 sival_int;
void *sival_ptr;
};
typedef struct StackT StackT;
struct StackT {
void *ss_sp;
uint64 ss_size;
int32 ss_flags;
byte pad_godefs_0[4];
};
typedef struct Timespec Timespec;
struct Timespec {
int32 tv_sec;
byte pad_godefs_0[4];
int64 tv_nsec;
};
typedef struct Timeval Timeval;
struct Timeval {
int64 tv_sec;
int64 tv_usec;
};
typedef struct Itimerval Itimerval;
struct Itimerval {
Timeval it_interval;
Timeval it_value;
};
typedef void sfxsave64;
typedef void usavefpu;
typedef struct Sigcontext Sigcontext;
struct Sigcontext {
int64 sc_rdi;
int64 sc_rsi;
int64 sc_rdx;
int64 sc_rcx;
int64 sc_r8;
int64 sc_r9;
int64 sc_r10;
int64 sc_r11;
int64 sc_r12;
int64 sc_r13;
int64 sc_r14;
int64 sc_r15;
int64 sc_rbp;
int64 sc_rbx;
int64 sc_rax;
int64 sc_gs;
int64 sc_fs;
int64 sc_es;
int64 sc_ds;
int64 sc_trapno;
int64 sc_err;
int64 sc_rip;
int64 sc_cs;
int64 sc_rflags;
int64 sc_rsp;
int64 sc_ss;
sfxsave64 *sc_fpstate;
int32 sc_onstack;
int32 sc_mask;
};
#pragma pack off

View File

@ -0,0 +1,8 @@
// 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.
TEXT _rt0_amd64_netbsd(SB),7,$-8
MOVQ $_rt0_amd64(SB), DX
MOVQ SP, DI
JMP DX

View File

@ -0,0 +1,199 @@
// 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 "runtime.h"
#include "defs.h"
#include "signals.h"
#include "os.h"
extern void runtime·sigtramp(void);
typedef struct sigaction {
union {
void (*__sa_handler)(int32);
void (*__sa_sigaction)(int32, Siginfo*, void *);
} __sigaction_u; /* signal handler */
uint32 sa_mask; /* signal mask to apply */
int32 sa_flags; /* see signal options below */
} Sigaction;
void
runtime·dumpregs(Sigcontext *r)
{
runtime·printf("rax %X\n", r->sc_rax);
runtime·printf("rbx %X\n", r->sc_rbx);
runtime·printf("rcx %X\n", r->sc_rcx);
runtime·printf("rdx %X\n", r->sc_rdx);
runtime·printf("rdi %X\n", r->sc_rdi);
runtime·printf("rsi %X\n", r->sc_rsi);
runtime·printf("rbp %X\n", r->sc_rbp);
runtime·printf("rsp %X\n", r->sc_rsp);
runtime·printf("r8 %X\n", r->sc_r8);
runtime·printf("r9 %X\n", r->sc_r9);
runtime·printf("r10 %X\n", r->sc_r10);
runtime·printf("r11 %X\n", r->sc_r11);
runtime·printf("r12 %X\n", r->sc_r12);
runtime·printf("r13 %X\n", r->sc_r13);
runtime·printf("r14 %X\n", r->sc_r14);
runtime·printf("r15 %X\n", r->sc_r15);
runtime·printf("rip %X\n", r->sc_rip);
runtime·printf("rflags %X\n", r->sc_rflags);
runtime·printf("cs %X\n", r->sc_cs);
runtime·printf("fs %X\n", r->sc_fs);
runtime·printf("gs %X\n", r->sc_gs);
}
String
runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
return runtime·emptystring;
return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
Sigcontext *r = context;
uintptr *sp;
if(sig == SIGPROF) {
runtime·sigprof((uint8*)r->sc_rip,
(uint8*)r->sc_rsp, nil, gp);
return;
}
if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = sig;
gp->sigcode0 = info->si_code;
gp->sigcode1 = *(uintptr*)((byte*)info + 16); /* si_addr */
gp->sigpc = r->sc_rip;
// Only push runtime·sigpanic if r->mc_rip != 0.
// If r->mc_rip == 0, probably panicked because of a
// call to a nil func. Not pushing that onto sp will
// make the trace look like a call to runtime·sigpanic instead.
// (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->sc_rip != 0) {
sp = (uintptr*)r->sc_rsp;
*--sp = r->sc_rip;
r->sc_rsp = (uintptr)sp;
}
r->sc_rip = (uintptr)runtime·sigpanic;
return;
}
if(runtime·sigtab[sig].flags & SigQueue) {
if(runtime·sigsend(sig)
|| (runtime·sigtab[sig].flags & SigIgnore))
return;
runtime·exit(2); // SIGINT, SIGTERM, etc
}
if(runtime·panicking) // traceback already printed
runtime·exit(2);
runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
runtime·printf("Signal %d\n", sig);
else
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", r->sc_rip);
runtime·printf("\n");
if(runtime·gotraceback()){
runtime·traceback((void*)r->sc_rip, (void*)r->sc_rsp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}
runtime·exit(2);
}
// Called from kernel on signal stack, so no stack split.
#pragma textflag 7
void
runtime·sigignore(void)
{
}
void
runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = (int8*)p;
st.ss_size = n;
st.ss_flags = 0;
runtime·sigaltstack(&st, nil);
}
static void
sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
runtime·memclr((byte*)&sa, sizeof sa);
sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
if(restart)
sa.sa_flags |= SA_RESTART;
sa.sa_mask = ~0ULL;
if (fn == runtime·sighandler)
fn = (void*)runtime·sigtramp;
sa.__sigaction_u.__sa_sigaction = (void*)fn;
runtime·sigaction(i, &sa, nil);
}
void
runtime·initsig(int32 queue)
{
int32 i;
void *fn;
runtime·siginit();
for(i = 0; i<NSIG; i++) {
if(runtime·sigtab[i].flags) {
if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
fn = runtime·sighandler;
else
fn = runtime·sigignore;
sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
}
}
}
void
runtime·resetcpuprofiler(int32 hz)
{
Itimerval it;
runtime·memclr((byte*)&it, sizeof it);
if(hz == 0) {
runtime·setitimer(ITIMER_PROF, &it, nil);
sigaction(SIGPROF, SIG_IGN, true);
} else {
sigaction(SIGPROF, runtime·sighandler, true);
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 1000000 / hz;
it.it_value = it.it_interval;
runtime·setitimer(ITIMER_PROF, &it, nil);
}
m->profilehz = hz;
}
void
os·sigpipe(void)
{
sigaction(SIGPIPE, SIG_DFL, false);
runtime·raisesigpipe();
}

View File

@ -0,0 +1,268 @@
// 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.
//
// System calls and other sys.stuff for AMD64, NetBSD
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
#include "amd64/asm.h"
// int64 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
TEXT runtime·rfork_thread(SB),7,$0
MOVL flags+8(SP), DI
MOVQ stack+16(SP), SI
// Copy m, g, fn off parent stack for use by child.
MOVQ mm+24(SP), R8
MOVQ gg+32(SP), R9
MOVQ fn+40(SP), R12
MOVL $251, AX // sys_rfork
SYSCALL
// Return if rfork syscall failed
JCC 3(PC)
NEGL AX
RET
// In parent, return.
CMPL AX, $0
JEQ 2(PC)
RET
// In child, on new stack.
MOVQ SI, SP
// Initialize m->procid to thread ID
MOVL $299, AX // sys_getthrid
SYSCALL
MOVQ AX, m_procid(R8)
// Set FS to point at m->tls.
LEAQ m_tls(R8), DI
CALL runtime·settls(SB)
// In child, set up new stack
get_tls(CX)
MOVQ R8, m(CX)
MOVQ R9, g(CX)
CALL runtime·stackcheck(SB)
// Call fn
CALL R12
// It shouldn't return. If it does, exit
MOVL $302, AX // sys_threxit
SYSCALL
JMP -3(PC) // keep exiting
TEXT runtime·osyield(SB),7,$0
MOVL $298, AX // sys_sched_yield
SYSCALL
RET
TEXT runtime·thrsleep(SB),7,$0
MOVQ 8(SP), DI // arg 1 - ident
MOVL 16(SP), SI // arg 2 - clock_id
MOVQ 24(SP), DX // arg 3 - tp
MOVQ 32(SP), R10 // arg 4 - lock
MOVL $300, AX // sys_thrsleep
SYSCALL
RET
TEXT runtime·thrwakeup(SB),7,$0
MOVQ 8(SP), DI // arg 1 - ident
MOVL 16(SP), SI // arg 2 - n
MOVL $301, AX // sys_thrwakeup
SYSCALL
RET
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 - exit status
MOVL $1, AX // sys_exit
SYSCALL
CALL runtime·notok(SB)
RET
TEXT runtime·exit1(SB),7,$-8
MOVL $302, AX // sys_threxit
SYSCALL
CALL runtime·notok(SB)
RET
TEXT runtime·write(SB),7,$-8
MOVL 8(SP), DI // arg 1 - fd
MOVQ 16(SP), SI // arg 2 - buf
MOVL 24(SP), DX // arg 3 - nbyte
MOVL $4, AX // sys_write
SYSCALL
RET
TEXT runtime·usleep(SB),7,$16
MOVL $0, DX
MOVL usec+0(FP), AX
MOVL $1000000, CX
DIVL CX
MOVQ AX, 0(SP) // tv_sec
MOVL $1000, AX
MULL DX
MOVQ AX, 8(SP) // tv_nsec
MOVQ SP, DI // arg 1 - rqtp
MOVQ $0, SI // arg 2 - rmtp
MOVL $240, AX // sys_nanosleep
SYSCALL
RET
TEXT runtime·raisesigpipe(SB),7,$16
MOVL $299, AX // sys_getthrid
SYSCALL
MOVQ AX, DI // arg 1 - pid
MOVQ $13, SI // arg 2 - signum == SIGPIPE
MOVL $37, AX // sys_kill
SYSCALL
RET
TEXT runtime·setitimer(SB),7,$-8
MOVL 8(SP), DI // arg 1 - which
MOVQ 16(SP), SI // arg 2 - itv
MOVQ 24(SP), DX // arg 3 - oitv
MOVL $83, AX // sys_setitimer
SYSCALL
RET
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
LEAQ 8(SP), DI // arg 1 - tp
MOVQ $0, SI // arg 2 - tzp
MOVL $116, AX // sys_gettimeofday
SYSCALL
MOVQ 8(SP), AX // sec
MOVL 16(SP), DX // usec
// sec is in AX, usec in DX
MOVQ AX, sec+0(FP)
IMULQ $1000, DX
MOVL DX, nsec+8(FP)
RET
TEXT runtime·nanotime(SB),7,$32
LEAQ 8(SP), DI // arg 1 - tp
MOVQ $0, SI // arg 2 - tzp
MOVL $116, AX // sys_gettimeofday
SYSCALL
MOVQ 8(SP), AX // sec
MOVL 16(SP), DX // usec
// sec is in AX, usec in DX
// return nsec in AX
IMULQ $1000000000, AX
IMULQ $1000, DX
ADDQ DX, AX
RET
TEXT runtime·sigaction(SB),7,$-8
MOVL 8(SP), DI // arg 1 - signum
MOVQ 16(SP), SI // arg 2 - nsa
MOVQ 24(SP), DX // arg 3 - osa
MOVL $46, AX
SYSCALL
JCC 2(PC)
CALL runtime·notok(SB)
RET
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
// save g
MOVQ g(BX), R10
MOVQ R10, 40(SP)
// g = m->signal
MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
MOVQ DI, 0(SP)
MOVQ SI, 8(SP)
MOVQ DX, 16(SP)
MOVQ R10, 24(SP)
CALL runtime·sighandler(SB)
// restore g
get_tls(BX)
MOVQ 40(SP), R10
MOVQ R10, g(BX)
RET
TEXT runtime·mmap(SB),7,$0
MOVQ 8(SP), DI // arg 1 - addr
MOVQ 16(SP), SI // arg 2 - len
MOVL 24(SP), DX // arg 3 - prot
MOVL 28(SP), R10 // arg 4 - flags
MOVL 32(SP), R8 // arg 5 - fd
MOVQ 36(SP), R9
SUBQ $16, SP
MOVQ R9, 8(SP) // arg 7 - offset (passed on stack)
MOVQ $0, R9 // arg 6 - pad
MOVL $197, AX
SYSCALL
JCC 2(PC)
NEGL AX
ADDQ $16, SP
RET
TEXT runtime·munmap(SB),7,$0
MOVQ 8(SP), DI // arg 1 - addr
MOVQ 16(SP), SI // arg 2 - len
MOVL $73, AX // sys_munmap
SYSCALL
JCC 2(PC)
CALL runtime·notok(SB)
RET
TEXT runtime·notok(SB),7,$-8
MOVL $0xf1, BP
MOVQ BP, (BP)
RET
TEXT runtime·sigaltstack(SB),7,$-8
MOVQ new+8(SP), DI // arg 1 - nss
MOVQ old+16(SP), SI // arg 2 - oss
MOVQ $288, AX // sys_sigaltstack
SYSCALL
JCC 2(PC)
CALL runtime·notok(SB)
RET
// set tls base to DI
TEXT runtime·settls(SB),7,$8
// adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
ADDQ $16, DI
MOVQ DI, 0(SP)
MOVQ SP, SI
MOVQ $12, DI // AMD64_SET_FSBASE (machine/sysarch.h)
MOVQ $165, AX // sys_sysarch
SYSCALL
JCC 2(PC)
CALL runtime·notok(SB)
RET
TEXT runtime·sysctl(SB),7,$0
MOVQ 8(SP), DI // arg 1 - name
MOVL 16(SP), SI // arg 2 - namelen
MOVQ 24(SP), DX // arg 3 - oldp
MOVQ 32(SP), R10 // arg 4 - oldlenp
MOVQ 40(SP), R8 // arg 5 - newp
MOVQ 48(SP), R9 // arg 6 - newlen
MOVQ $202, AX // sys___sysctl
SYSCALL
JCC 3(PC)
NEGL AX
RET
MOVL $0, AX
RET

View File

@ -0,0 +1,109 @@
// 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.
/*
Input to cgo.
GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h
GOARCH=386 cgo -cdefs defs.go >386/defs.h
*/
package runtime
/*
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/unistd.h>
#include <sys/signal.h>
#include <errno.h>
#include <signal.h>
*/
import "C"
const (
PROT_NONE = C.PROT_NONE
PROT_READ = C.PROT_READ
PROT_WRITE = C.PROT_WRITE
PROT_EXEC = C.PROT_EXEC
MAP_ANON = C.MAP_ANON
MAP_PRIVATE = C.MAP_PRIVATE
MAP_FIXED = C.MAP_FIXED
SA_SIGINFO = C.SA_SIGINFO
SA_RESTART = C.SA_RESTART
SA_ONSTACK = C.SA_ONSTACK
EINTR = C.EINTR
SIGHUP = C.SIGHUP
SIGINT = C.SIGINT
SIGQUIT = C.SIGQUIT
SIGILL = C.SIGILL
SIGTRAP = C.SIGTRAP
SIGABRT = C.SIGABRT
SIGEMT = C.SIGEMT
SIGFPE = C.SIGFPE
SIGKILL = C.SIGKILL
SIGBUS = C.SIGBUS
SIGSEGV = C.SIGSEGV
SIGSYS = C.SIGSYS
SIGPIPE = C.SIGPIPE
SIGALRM = C.SIGALRM
SIGTERM = C.SIGTERM
SIGURG = C.SIGURG
SIGSTOP = C.SIGSTOP
SIGTSTP = C.SIGTSTP
SIGCONT = C.SIGCONT
SIGCHLD = C.SIGCHLD
SIGTTIN = C.SIGTTIN
SIGTTOU = C.SIGTTOU
SIGIO = C.SIGIO
SIGXCPU = C.SIGXCPU
SIGXFSZ = C.SIGXFSZ
SIGVTALRM = C.SIGVTALRM
SIGPROF = C.SIGPROF
SIGWINCH = C.SIGWINCH
SIGINFO = C.SIGINFO
SIGUSR1 = C.SIGUSR1
SIGUSR2 = C.SIGUSR2
FPE_INTDIV = C.FPE_INTDIV
FPE_INTOVF = C.FPE_INTOVF
FPE_FLTDIV = C.FPE_FLTDIV
FPE_FLTOVF = C.FPE_FLTOVF
FPE_FLTUND = C.FPE_FLTUND
FPE_FLTRES = C.FPE_FLTRES
FPE_FLTINV = C.FPE_FLTINV
FPE_FLTSUB = C.FPE_FLTSUB
BUS_ADRALN = C.BUS_ADRALN
BUS_ADRERR = C.BUS_ADRERR
BUS_OBJERR = C.BUS_OBJERR
SEGV_MAPERR = C.SEGV_MAPERR
SEGV_ACCERR = C.SEGV_ACCERR
ITIMER_REAL = C.ITIMER_REAL
ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
ITIMER_PROF = C.ITIMER_PROF
)
type Sigaltstack C.struct_sigaltstack
type Sigset C.sigset_t
type Siginfo C.siginfo_t
type Sigval C.union_sigval
type StackT C.stack_t
type Timespec C.struct_timespec
type Timeval C.struct_timeval
type Itimerval C.struct_itimerval
// This is a hack to avoid pulling in machine/fpu.h.
type sfxsave64 struct{}
type usavefpu struct{}
type Sigcontext C.struct_sigcontext

View File

@ -0,0 +1,85 @@
// Copyright 2010 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.h"
#include "defs.h"
#include "os.h"
#include "malloc.h"
enum
{
ENOMEM = 12,
};
void*
runtime·SysAlloc(uintptr n)
{
void *v;
mstats.sys += n;
v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
if(v < (void*)4096)
return nil;
return v;
}
void
runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
// TODO(rsc): call madvise MADV_DONTNEED
}
void
runtime·SysFree(void *v, uintptr n)
{
mstats.sys -= n;
runtime·munmap(v, n);
}
void*
runtime·SysReserve(void *v, uintptr n)
{
void *p;
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
if(sizeof(void*) == 8)
return v;
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if (p == ((void *)-ENOMEM))
return nil;
else
return p;
}
void
runtime·SysMap(void *v, uintptr n)
{
void *p;
mstats.sys += n;
// On 64-bit, we don't actually have v reserved, so tread carefully.
if(sizeof(void*) == 8) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p == (void*)-ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v) {
runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
runtime·throw("runtime: address space conflict");
}
return;
}
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
if(p == (void*)-ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v)
runtime·throw("runtime: cannot map pages in arena address space");
}

View File

@ -0,0 +1,17 @@
// Copyright 2010 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.
#define SIG_DFL ((void*)0)
#define SIG_IGN ((void*)1)
struct sigaction;
void runtime·sigpanic(void);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·setitimerval(int32, Itimerval*, Itimerval*);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
void runtime·raisesigpipe(void);

View File

@ -0,0 +1,52 @@
// 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.
#define C SigCatch
#define I SigIgnore
#define R SigRestart
#define Q SigQueue
#define P SigPanic
SigTab runtime·sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
/* 3 */ C, "SIGQUIT: quit",
/* 4 */ C, "SIGILL: illegal instruction",
/* 5 */ C, "SIGTRAP: trace trap",
/* 6 */ C, "SIGABRT: abort",
/* 7 */ C, "SIGEMT: EMT instruction",
/* 8 */ C+P, "SIGFPE: floating-point exception",
/* 9 */ 0, "SIGKILL: kill",
/* 10 */ C+P, "SIGBUS: bus error",
/* 11 */ C+P, "SIGSEGV: segmentation violation",
/* 12 */ C, "SIGSYS: bad system call",
/* 13 */ I, "SIGPIPE: write to broken pipe",
/* 14 */ Q+I+R, "SIGALRM: alarm clock",
/* 15 */ Q+R, "SIGTERM: termination",
/* 16 */ Q+I+R, "SIGURG: urgent condition on socket",
/* 17 */ 0, "SIGSTOP: stop, unblockable",
/* 18 */ Q+I+R, "SIGTSTP: stop from tty",
/* 19 */ 0, "SIGCONT: continue",
/* 20 */ Q+I+R, "SIGCHLD: child status has changed",
/* 21 */ Q+I+R, "SIGTTIN: background read from tty",
/* 22 */ Q+I+R, "SIGTTOU: background write to tty",
/* 23 */ Q+I+R, "SIGIO: i/o now possible",
/* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
/* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
/* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
/* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
/* 28 */ Q+I+R, "SIGWINCH: window size change",
/* 29 */ Q+I+R, "SIGINFO: information request",
/* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1",
/* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2",
/* 32 */ Q+I+R, "SIGTHR: reserved",
};
#undef C
#undef I
#undef R
#undef Q
#undef P
#define NSIG 33

View File

@ -0,0 +1,197 @@
// Use of this source file is governed by a BSD-style
// license that can be found in the LICENSE file.`
#include "runtime.h"
#include "defs.h"
#include "os.h"
#include "stack.h"
enum
{
ESRCH = 3,
ENOTSUP = 91,
// From NetBSD's sys/time.h
CLOCK_REALTIME = 0,
CLOCK_VIRTUAL = 1,
CLOCK_PROF = 2,
CLOCK_MONOTONIC = 3
};
extern SigTab runtime·sigtab[];
extern int64 runtime·rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock);
extern int32 runtime·thrwakeup(void *ident, int32 n);
// From NetBSD's <sys/sysctl.h>
#define CTL_HW 6
#define HW_NCPU 3
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;
}
uintptr
runtime·semacreate(void)
{
return 1;
}
int32
runtime·semasleep(int64 ns)
{
Timespec ts;
// spin-mutex lock
while(runtime·xchg(&m->waitsemalock, 1))
runtime·osyield();
for(;;) {
// lock held
if(m->waitsemacount == 0) {
// sleep until semaphore != 0 or timeout.
// thrsleep unlocks m->waitsemalock.
if(ns < 0)
runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock);
else {
ns += runtime·nanotime();
ts.tv_sec = ns/1000000000LL;
ts.tv_nsec = ns%1000000000LL;
runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock);
}
// reacquire lock
while(runtime·xchg(&m->waitsemalock, 1))
runtime·osyield();
}
// lock held (again)
if(m->waitsemacount != 0) {
// semaphore is available.
m->waitsemacount--;
// spin-mutex unlock
runtime·atomicstore(&m->waitsemalock, 0);
return 0; // semaphore acquired
}
// semaphore not available.
// if there is a timeout, stop now.
// otherwise keep trying.
if(ns >= 0)
break;
}
// lock held but giving up
// spin-mutex unlock
runtime·atomicstore(&m->waitsemalock, 0);
return -1;
}
void
runtime·semawakeup(M *mp)
{
uint32 ret;
// spin-mutex lock
while(runtime·xchg(&mp->waitsemalock, 1))
runtime·osyield();
mp->waitsemacount++;
ret = runtime·thrwakeup(&mp->waitsemacount, 1);
if(ret != 0 && ret != ESRCH)
runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
// spin-mutex unlock
runtime·atomicstore(&mp->waitsemalock, 0);
}
// From NetBSD's sys/param.h
#define RFPROC (1<<4) /* change child (else changes curproc) */
#define RFMEM (1<<5) /* share `address space' */
#define RFNOWAIT (1<<6) /* parent need not wait() on child */
#define RFTHREAD (1<<13) /* create a thread, not a process */
void
runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
int32 flags;
int32 ret;
flags = RFPROC | RFTHREAD | RFMEM | RFNOWAIT;
if (0) {
runtime·printf(
"newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
stk, m, g, fn, m->id, m->tls[0], &m);
}
m->tls[0] = m->id; // so 386 asm can find it
if((ret = runtime·rfork_thread(flags, stk, m, g, fn)) < 0) {
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
if (ret == -ENOTSUP)
runtime·printf("runtime: is kern.rthreads disabled?\n");
runtime·throw("runtime.newosproc");
}
}
void
runtime·osinit(void)
{
runtime·ncpu = getncpu();
}
void
runtime·goenvs(void)
{
runtime·goenvs_unix();
}
// Called to initialize a new m (including the bootstrap m).
void
runtime·minit(void)
{
// Initialize signal handling
m->gsignal = runtime·malg(32*1024);
runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
}
void
runtime·sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
runtime·panicstring("invalid memory address or nil pointer dereference");
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
runtime·panicstring("invalid memory address or nil pointer dereference");
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
runtime·panicstring("integer overflow");
}
runtime·panicstring("floating point error");
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}