preparation for exec.

* syscall:
	add syscall.RawSyscall, which doesn't use sys.entersyscall/sys.exitsyscall
	add syscall.dup2
	add syscall.BytePtrPtr
	add syscall.Rusage, RusagePtr
	add syscall.F_GETFD, F_SETFD, FD_CLOEXEC

* runtime:
	clean up, correct signal handling.
	can now survive (continue running after) a signal.

R=r
DELTA=394  (286 added, 51 deleted, 57 changed)
OCL=20351
CL=20369
This commit is contained in:
Russ Cox 2008-12-03 14:21:28 -08:00
parent 2b39165f1e
commit dfa5893d4f
19 changed files with 348 additions and 105 deletions

View file

@ -5,7 +5,7 @@
# DO NOT EDIT. Automatically generated by gobuild.
# gobuild -m errstr_darwin.go file_darwin.go socket_darwin.go\
# syscall_amd64_darwin.go time_amd64_darwin.go types_amd64_darwin.go\
# asm_amd64_darwin.s cast_amd64.s syscall.go >Makefile
# asm_amd64_darwin.s cast_amd64.s syscall.go signal_amd64_darwin.go >Makefile
O=6
GC=$(O)g
CC=$(O)c -w
@ -40,6 +40,7 @@ O1=\
asm_$(GOARCH)_$(GOOS).$O\
cast_$(GOARCH).$O\
syscall.$O\
signal_$(GOARCH)_$(GOOS).$O\
O2=\
file_$(GOOS).$O\
@ -49,7 +50,7 @@ O2=\
syscall.a: a1 a2
a1: $(O1)
$(AR) grc syscall.a errstr_$(GOOS).$O syscall_$(GOARCH)_$(GOOS).$O types_$(GOARCH)_$(GOOS).$O asm_$(GOARCH)_$(GOOS).$O cast_$(GOARCH).$O syscall.$O
$(AR) grc syscall.a errstr_$(GOOS).$O syscall_$(GOARCH)_$(GOOS).$O types_$(GOARCH)_$(GOOS).$O asm_$(GOARCH)_$(GOOS).$O cast_$(GOARCH).$O syscall.$O signal_$(GOARCH)_$(GOOS).$O
rm -f $(O1)
a2: $(O2)

View file

@ -54,3 +54,21 @@ ok6:
MOVQ $0, 80(SP) // errno
CALL sys·exitsyscall(SB)
RET
TEXT syscall·RawSyscall(SB),7,$0
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
MOVQ 8(SP), AX // syscall entry
ADDQ $0x2000000, AX
SYSCALL
JCC ok1
MOVQ $-1, 40(SP) // r1
MOVQ $0, 48(SP) // r2
MOVQ AX, 56(SP) // errno
RET
ok1:
MOVQ AX, 40(SP) // r1
MOVQ DX, 48(SP) // r2
MOVQ $0, 56(SP) // errno
RET

View file

@ -57,3 +57,22 @@ ok6:
MOVQ $0, 80(SP) // errno
CALL sys·exitsyscall(SB)
RET
TEXT syscall·RawSyscall(SB),7,$0
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
MOVQ 8(SP), AX // syscall entry
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS ok1
MOVQ $-1, 40(SP) // r1
MOVQ $0, 48(SP) // r2
NEGQ AX
MOVQ AX, 56(SP) // errno
RET
ok1:
MOVQ AX, 40(SP) // r1
MOVQ DX, 48(SP) // r2
MOVQ $0, 56(SP) // errno
RET

View file

@ -8,6 +8,11 @@ TEXT syscall·BytePtr(SB),7,$-8
MOVQ AX, 16(SP)
RET
TEXT syscall·BytePtrPtr(SB),7,$-8
MOVQ 8(SP), AX
MOVQ AX, 16(SP)
RET
TEXT syscall·Int32Ptr(SB),7,$-8
MOVQ 8(SP), AX
MOVQ AX, 16(SP)
@ -53,6 +58,11 @@ TEXT syscall·TimevalPtr(SB),7,$-8
MOVQ AX, 16(SP)
RET
TEXT syscall·RusagePtr(SB),7,$-8
MOVQ 8(SP), AX
MOVQ AX, 16(SP)
RET
TEXT syscall·SockaddrToSockaddrInet4(SB),7,$-8
MOVQ 8(SP), AX
MOVQ AX, 16(SP)

View file

@ -94,3 +94,9 @@ export func mkdir(name string, perm int64) (ret int64, errno int64) {
r1, r2, err := Syscall(SYS_MKDIR, BytePtr(&namebuf[0]), perm, 0);
return r1, err;
}
export func dup2(fd1, fd2 int64) (ret int64, errno int64) {
r1, r2, err := Syscall(SYS_DUP2, fd1, fd2, 0);
return r1, err;
}

View file

@ -95,3 +95,9 @@ export func mkdir(name string, perm int64) (ret int64, errno int64) {
r1, r2, err := Syscall(SYS_MKDIR, BytePtr(&namebuf[0]), perm, 0);
return r1, err;
}
export func dup2(fd1, fd2 int64) (ret int64, errno int64) {
r1, r2, err := Syscall(SYS_DUP2, fd1, fd2, 0);
return r1, err;
}

View file

@ -10,10 +10,12 @@ package syscall
export func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
export func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
export func RawSyscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
export func BytePtr(b *byte) int64;
export func Int32Ptr(p *int32) int64;
export func Int64Ptr(p *int64) int64;
export func BytePtrPtr(b **byte) int64;
/*
* Used to convert file names to byte arrays for passing to kernel,

View file

@ -23,6 +23,29 @@ export type Timeval struct {
export func TimevalPtr(t *Timeval) int64;
// Processes
export type Rusage struct {
utime Timeval;
stime Timeval;
maxrss int64;
ixrss int64;
idrss int64;
isrss int64;
minflt int64;
majflt int64;
nswap int64;
inblock int64;
oublock int64;
msgsnd int64;
msgrcv int64;
nsignals int64;
nvcsw int64;
nivcsw int64;
}
export func RusagePtr(r *Rusage) int64;
// Files
export const (
@ -38,8 +61,13 @@ export const (
O_SYNC = 0x80;
O_TRUNC = 0x400;
F_GETFD = 1;
F_SETFD = 2;
F_GETFL = 3;
F_SETFL = 4;
FD_CLOEXEC = 1;
)
export type Stat struct {

View file

@ -23,6 +23,29 @@ export type Timeval struct {
export func TimevalPtr(t *Timeval) int64;
// Processes
export type Rusage struct {
utime Timeval;
stime Timeval;
maxrss int64;
ixrss int64;
idrss int64;
isrss int64;
minflt int64;
majflt int64;
nswap int64;
inblock int64;
oublock int64;
msgsnd int64;
msgrcv int64;
nsignals int64;
nvcsw int64;
nivcsw int64;
}
export func RusagePtr(r *Rusage) int64;
// Files
export const (
@ -38,8 +61,13 @@ export const (
O_SYNC = 0x1000;
O_TRUNC = 0x200;
F_GETFD = 1;
F_SETFD = 2;
F_GETFL = 3;
F_SETFL = 4;
FD_CLOEXEC = 1;
)
export type Stat struct {

View file

@ -4,7 +4,7 @@
#include "runtime.h"
#include "amd64_darwin.h"
#include "signals.h"
#include "signals_darwin.h"
typedef uint64 __uint64_t;
@ -100,15 +100,14 @@ static _STRUCT_X86_FLOAT_STATE64 *get___fs(_STRUCT_MCONTEXT64 *ptr) {
/*
* This assembler routine takes the args from registers, puts them on the stack,
* and calls sighandler().
* and calls the registered handler.
*/
extern void sigtramp();
extern void sigtramp(void);
/*
* Rudimentary reverse-engineered definition of signal interface.
* You'd think it would be documented.
*/
typedef struct siginfo {
struct siginfo {
int32 si_signo; /* signal number */
int32 si_errno; /* errno association */
int32 si_code; /* signal code */
@ -117,21 +116,17 @@ typedef struct siginfo {
int32 si_status; /* exit value */
void *si_addr; /* faulting address */
/* more stuff here */
} siginfo;
};
typedef struct sigaction {
union {
void (*sa_handler)(int32);
void (*sa_sigaction)(int32, siginfo *, void *);
} u; /* signal handler */
void (*sa_trampoline)(void); /* kernel callback point; calls sighandler() */
uint8 sa_mask[4]; /* signal mask to apply */
int32 sa_flags; /* see signal options below */
} sigaction;
struct sigaction {
void (*sa_handler)(int32, struct siginfo*, void*); // actual handler
void (*sa_trampoline)(void); // assembly trampoline
uint32 sa_mask; // signal mask during handler
int32 sa_flags; // flags below
};
void
sighandler(int32 sig, siginfo *info, void *context)
sighandler(int32 sig, struct siginfo *info, void *context)
{
if(panicking) // traceback already printed
sys·exit(2);
@ -159,15 +154,17 @@ sighandler(int32 sig, siginfo *info, void *context)
sys·exit(2);
}
void
sigignore(int32, struct siginfo*, void*)
{
}
struct stack_t {
byte *sp;
int64 size;
int32 flags;
};
sigaction a;
extern void sigtramp(void);
void
signalstack(byte *p, int32 n)
{
@ -179,21 +176,39 @@ signalstack(byte *p, int32 n)
sigaltstack(&st, nil);
}
void sigaction(int64, void*, void*);
enum {
SA_SIGINFO = 0x40,
SA_RESTART = 0x02,
SA_ONSTACK = 0x01,
SA_USERTRAMP = 0x100,
SA_64REGSET = 0x200,
};
void
initsig(void)
{
int32 i;
static struct sigaction sa;
a.u.sa_sigaction = (void*)sigtramp;
a.sa_flags |= 0x41; /* SA_SIGINFO, SA_ONSTACK */
for(i=0; i<sizeof(a.sa_mask); i++)
a.sa_mask[i] = 0xFF;
a.sa_trampoline = sigtramp;
for(i = 0; i <NSIG; i++)
if(sigtab[i].catch){
sys·sigaction(i, &a, (void*)0);
sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
sa.sa_mask = 0; // 0xFFFFFFFFU;
sa.sa_trampoline = sigtramp;
for(i = 0; i<NSIG; i++) {
if(sigtab[i].flags) {
if(sigtab[i].flags & SigCatch) {
sa.sa_handler = sighandler;
} else {
sa.sa_handler = sigignore;
}
if(sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
sigaction(i, &sa, nil);
}
}
}
static void

View file

@ -4,7 +4,7 @@
#include "runtime.h"
#include "amd64_linux.h"
#include "signals.h"
#include "signals_linux.h"
/* From /usr/include/asm-x86_64/sigcontext.h */
struct _fpstate {
@ -105,37 +105,34 @@ print_sigcontext(struct sigcontext *sc)
* This assembler routine takes the args from registers, puts them on the stack,
* and calls sighandler().
*/
extern void sigtramp();
extern void sigtramp(void);
extern void sigignore(void); // just returns
extern void sigreturn(void); // calls sigreturn
/*
* Rudimentary reverse-engineered definition of signal interface.
* You'd think it would be documented.
*/
/* From /usr/include/bits/siginfo.h */
typedef struct siginfo {
struct siginfo {
int32 si_signo; /* signal number */
int32 si_errno; /* errno association */
int32 si_code; /* signal code */
int32 si_status; /* exit value */
void *si_addr; /* faulting address */
/* more stuff here */
} siginfo;
};
/* From /usr/include/bits/sigaction.h */
/* (gri) Is this correct? See e.g. /usr/include/asm-x86_64/signal.h */
typedef struct sigaction {
union {
void (*sa_handler)(int32);
void (*sa_sigaction)(int32, siginfo *, void *);
} u; /* signal handler */
uint8 sa_mask[128]; /* signal mask to apply. 128? are they KIDDING? */
int32 sa_flags; /* see signal options below */
void (*sa_restorer) (void); /* unused here; needed to return from trap? */
} sigaction;
// This is a struct sigaction from /usr/include/asm/signal.h
struct sigaction {
void (*sa_handler)(int32, struct siginfo*, void*);
uint64 sa_flags;
void (*sa_restorer)(void);
uint64 sa_mask;
};
void
sighandler(int32 sig, siginfo* info, void** context)
sighandler(int32 sig, struct siginfo* info, void** context)
{
if(panicking) // traceback already printed
sys·exit(2);
@ -182,21 +179,37 @@ signalstack(byte *p, int32 n)
sigaltstack(&st, nil);
}
static sigaction a;
void rt_sigaction(int64, void*, void*, uint64);
enum {
SA_RESTART = 0x10000000,
SA_ONSTACK = 0x08000000,
SA_RESTORER = 0x04000000,
SA_SIGINFO = 0x00000004,
};
void
initsig(void)
{
int32 i;
a.u.sa_sigaction = (void*)sigtramp;
a.sa_flags = 0x08000004; /* SA_ONSTACK, SA_SIGINFO */
for(i=0; i<sizeof(a.sa_mask); i++)
a.sa_mask[i] = 0xFF;
static struct sigaction sa;
for(i = 0; i<NSIG; i++)
if(sigtab[i].catch){
sys·rt_sigaction(i, &a, (void*)0, 8);
int32 i;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
sa.sa_restorer = (void*)sigreturn;
for(i = 0; i<NSIG; i++) {
if(sigtab[i].flags) {
if(sigtab[i].flags & SigCatch)
sa.sa_handler = (void*)sigtramp;
else
sa.sa_handler = (void*)sigignore;
if(sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
rt_sigaction(i, &sa, nil, 8);
}
}
}

View file

@ -48,6 +48,7 @@ typedef union Note Note;
typedef struct Stktop Stktop;
typedef struct String *string;
typedef struct Usema Usema;
typedef struct SigTab SigTab;
/*
* per cpu declaration
@ -179,9 +180,15 @@ struct Alg
};
struct SigTab
{
int32 catch;
int32 flags;
int8 *name;
};
enum
{
SigCatch = 1<<0,
SigIgnore = 1<<1,
SigRestart = 1<<2,
};
// (will be) shared with go; edit ../cmd/6g/sys.go too.
// should move out of sys.go eventually.
@ -305,8 +312,6 @@ uint8* sys·mmap(byte*, uint32, int32, int32, int32, uint32);
void sys·memclr(byte*, uint32);
void sys·setcallerpc(void*, void*);
void* sys·getcallerpc(void*);
void sys·sigaction(int64, void*, void*);
void sys·rt_sigaction(int64, void*, void*, uint64);
/*
* runtime go-called

View file

@ -1,40 +0,0 @@
// 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.
static struct SigTab sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ 0, "SIGHUP: terminal line hangup",
/* 2 */ 0, "SIGINT: interrupt program",
/* 3 */ 1, "SIGQUIT: quit program",
/* 4 */ 1, "SIGILL: illegal instruction",
/* 5 */ 1, "SIGTRAP: trace trap", /* used by panic and array out of bounds, etc. */
/* 6 */ 1, "SIGABRT: abort program",
/* 7 */ 1, "SIGEMT: emulate instruction executed",
/* 8 */ 1, "SIGFPE: floating-point exception",
/* 9 */ 0, "SIGKILL: kill program",
/* 10 */ 1, "SIGBUS: bus error",
/* 11 */ 1, "SIGSEGV: segmentation violation",
/* 12 */ 1, "SIGSYS: non-existent system call invoked",
/* 13 */ 0, "SIGPIPE: write on a pipe with no reader",
/* 14 */ 0, "SIGALRM: real-time timer expired",
/* 15 */ 0, "SIGTERM: software termination signal",
/* 16 */ 0, "SIGURG: urgent condition present on socket",
/* 17 */ 0, "SIGSTOP: stop",
/* 18 */ 0, "SIGTSTP: stop signal generated from keyboard",
/* 19 */ 0, "SIGCONT: continue after stop",
/* 20 */ 0, "SIGCHLD: child status has changed",
/* 21 */ 0, "SIGTTIN: background read attempted from control terminal",
/* 22 */ 0, "SIGTTOU: background write attempted to control terminal",
/* 23 */ 0, "SIGIO: I/O is possible on a descriptor",
/* 24 */ 0, "SIGXCPU: cpu time limit exceeded",
/* 25 */ 0, "SIGXFSZ: file size limit exceeded",
/* 26 */ 0, "SIGVTALRM: virtual time alarm",
/* 27 */ 0, "SIGPROF: profiling timer alarm",
/* 28 */ 0, "SIGWINCH: Window size change",
/* 29 */ 0, "SIGINFO: status request from keyboard",
/* 30 */ 0, "SIGUSR1: User defined signal 1",
/* 31 */ 0, "SIGUSR2: User defined signal 2",
};
#define NSIG 32

View file

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

View file

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

View file

@ -73,7 +73,7 @@ TEXT write(SB),7,$-8
SYSCALL
RET
TEXT sys·sigaction(SB),7,$-8
TEXT sigaction(SB),7,$-8
MOVL 8(SP), DI // arg 1 sig
MOVQ 16(SP), SI // arg 2 act
MOVQ 24(SP), DX // arg 3 oact
@ -85,13 +85,19 @@ TEXT sys·sigaction(SB),7,$-8
CALL notok(SB)
RET
TEXT sigtramp(SB),7,$24
TEXT sigtramp(SB),7,$40
MOVQ 32(R14), R15 // g = m->gsignal
MOVL DX,0(SP)
MOVQ CX,8(SP)
MOVQ R8,16(SP)
CALL sighandler(SB)
RET
MOVQ R8, 24(SP) // save ucontext
MOVQ SI, 32(SP) // save infostyle
CALL DI
MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle)
MOVQ 24(SP), DI // saved ucontext
MOVQ 32(SP), SI // saved infostyle
SYSCALL
INT $3 // not reached
TEXT sys·mmap(SB),7,$-8
MOVQ 8(SP), DI // arg 1 addr

View file

@ -63,7 +63,7 @@ TEXT sys·write(SB),7,$0-24
SYSCALL
RET
TEXT sys·rt_sigaction(SB),7,$0-32
TEXT rt_sigaction(SB),7,$0-32
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVQ 24(SP), DX
@ -80,6 +80,14 @@ TEXT sigtramp(SB),7,$24-16
CALL sighandler(SB)
RET
TEXT sigignore(SB),7,$0
RET
TEXT sigreturn(SB),7,$0
MOVL $15, AX // rt_sigreturn
SYSCALL
INT $3 // not reached
TEXT sys·mmap(SB),7,$0-32
MOVQ 8(SP), DI
MOVQ $0, SI

View file

@ -56,6 +56,9 @@ BUG: errchk: command succeeded unexpectedly: 6g ./method2.go
-9223372036854775808
9223372036854775807
=========== ./sigchld.go
survived SIGCHLD
=========== ./turing.go
Hello World!

19
test/sigchld.go Normal file
View file

@ -0,0 +1,19 @@
// $G $D/$F.go && $L $F.$A && ./$A.out
// 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.
package main
import "syscall"
func getpid() int64 {
r1, r2, err := syscall.Syscall(syscall.SYS_GETPID, 0, 0, 0);
return r1;
}
func main() {
syscall.Syscall(syscall.SYS_KILL, getpid(), syscall.SIGCHLD, 0);
println("survived SIGCHLD");
}