mirror of
https://github.com/golang/go.git
synced 2024-10-01 07:17:21 +00:00
R=rsc, brainman, ality, r2, r
CC=golang-dev https://golang.org/cl/3816043
This commit is contained in:
parent
c42b3e21c3
commit
1cc4a5cd94
@ -32,6 +32,9 @@ GOFILES_linux=\
|
||||
|
||||
GOFILES_windows=\
|
||||
exec_windows.go
|
||||
|
||||
GOFILES_plan9=\
|
||||
exec_plan9.go
|
||||
|
||||
OFILES=\
|
||||
asm_$(GOOS)_$(GOARCH).$O\
|
||||
|
151
src/pkg/syscall/asm_plan9_386.s
Normal file
151
src/pkg/syscall/asm_plan9_386.s
Normal file
@ -0,0 +1,151 @@
|
||||
// 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 call support for 386, Plan 9
|
||||
//
|
||||
|
||||
//func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err string)
|
||||
//func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err string)
|
||||
//func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
|
||||
//func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
|
||||
|
||||
// Trap # in AX, args on stack above caller pc.
|
||||
TEXT ·Syscall(SB),7,$0
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $64
|
||||
MOVL AX, r1+20(SP)
|
||||
MOVL $0, r2+24(SP)
|
||||
CMPL AX, $-1
|
||||
JNE ok3
|
||||
|
||||
SUBL $8, SP
|
||||
CALL syscall·errstr(SB)
|
||||
MOVL SP, SI
|
||||
ADDL $8, SP
|
||||
JMP copyresult3
|
||||
|
||||
ok3:
|
||||
LEAL runtime·emptystring(SB), SI
|
||||
|
||||
copyresult3:
|
||||
LEAL err+28(SP), DI
|
||||
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·Syscall6(SB),7,$0
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $64
|
||||
MOVL AX, r1+32(SP)
|
||||
MOVL $0, r2+36(SP)
|
||||
CMPL AX, $-1
|
||||
JNE ok4
|
||||
|
||||
SUBL $8, SP
|
||||
CALL syscall·errstr(SB)
|
||||
MOVL SP, SI
|
||||
ADDL $8, SP
|
||||
JMP copyresult4
|
||||
|
||||
ok4:
|
||||
LEAL runtime·emptystring(SB), SI
|
||||
|
||||
copyresult4:
|
||||
LEAL err+40(SP), DI
|
||||
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),7,$0
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $64
|
||||
MOVL AX, r1+20(SP)
|
||||
MOVL AX, r2+24(SP)
|
||||
MOVL AX, err+28(SP)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall6(SB),7,$0
|
||||
MOVL 4(SP), AX // syscall entry
|
||||
// slide args down on top of system call number
|
||||
LEAL 8(SP), SI
|
||||
LEAL 4(SP), DI
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
MOVSL
|
||||
INT $64
|
||||
MOVL AX, r1+32(SP)
|
||||
MOVL AX, r2+36(SP)
|
||||
MOVL AX, err+40(SP)
|
||||
RET
|
||||
|
||||
#define SYS_SEEK 39 /* from zsysnum_plan9_386.go */
|
||||
|
||||
//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
|
||||
TEXT ·seek(SB),7,$0
|
||||
LEAL newoffset+24(SP), AX
|
||||
MOVL AX, placeholder+4(SP)
|
||||
|
||||
MOVL $SYS_SEEK, AX // syscall entry
|
||||
INT $64
|
||||
|
||||
CMPL AX, $-1
|
||||
JNE ok6
|
||||
MOVL AX, 24(SP) // newoffset low
|
||||
MOVL AX, 28(SP) // newoffset high
|
||||
|
||||
SUBL $8, SP
|
||||
CALL syscall·errstr(SB)
|
||||
MOVL SP, SI
|
||||
ADDL $8, SP
|
||||
JMP copyresult6
|
||||
|
||||
ok6:
|
||||
LEAL runtime·emptystring(SB), SI
|
||||
|
||||
copyresult6:
|
||||
LEAL err+32(SP), DI
|
||||
|
||||
CLD
|
||||
MOVSL
|
||||
MOVSL
|
||||
RET
|
521
src/pkg/syscall/exec_plan9.go
Normal file
521
src/pkg/syscall/exec_plan9.go
Normal file
@ -0,0 +1,521 @@
|
||||
// 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.
|
||||
|
||||
// Fork, exec, wait, etc.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Lock synchronizing creation of new file descriptors with fork.
|
||||
//
|
||||
// We want the child in a fork/exec sequence to inherit only the
|
||||
// file descriptors we intend. To do that, we mark all file
|
||||
// descriptors close-on-exec and then, in the child, explicitly
|
||||
// unmark the ones we want the exec'ed program to keep.
|
||||
// Unix doesn't make this easy: there is, in general, no way to
|
||||
// allocate a new file descriptor close-on-exec. Instead you
|
||||
// have to allocate the descriptor and then mark it close-on-exec.
|
||||
// If a fork happens between those two events, the child's exec
|
||||
// will inherit an unwanted file descriptor.
|
||||
//
|
||||
// This lock solves that race: the create new fd/mark close-on-exec
|
||||
// operation is done holding ForkLock for reading, and the fork itself
|
||||
// is done holding ForkLock for writing. At least, that's the idea.
|
||||
// There are some complications.
|
||||
//
|
||||
// Some system calls that create new file descriptors can block
|
||||
// for arbitrarily long times: open on a hung NFS server or named
|
||||
// pipe, accept on a socket, and so on. We can't reasonably grab
|
||||
// the lock across those operations.
|
||||
//
|
||||
// It is worse to inherit some file descriptors than others.
|
||||
// If a non-malicious child accidentally inherits an open ordinary file,
|
||||
// that's not a big deal. On the other hand, if a long-lived child
|
||||
// accidentally inherits the write end of a pipe, then the reader
|
||||
// of that pipe will not see EOF until that child exits, potentially
|
||||
// causing the parent program to hang. This is a common problem
|
||||
// in threaded C programs that use popen.
|
||||
//
|
||||
// Luckily, the file descriptors that are most important not to
|
||||
// inherit are not the ones that can take an arbitrarily long time
|
||||
// to create: pipe returns instantly, and the net package uses
|
||||
// non-blocking I/O to accept on a listening socket.
|
||||
// The rules for which file descriptor-creating operations use the
|
||||
// ForkLock are as follows:
|
||||
//
|
||||
// 1) Pipe. Does not block. Use the ForkLock.
|
||||
// 2) Socket. Does not block. Use the ForkLock.
|
||||
// 3) Accept. If using non-blocking mode, use the ForkLock.
|
||||
// Otherwise, live with the race.
|
||||
// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
|
||||
// Otherwise, live with the race.
|
||||
// 5) Dup. Does not block. Use the ForkLock.
|
||||
// On Linux, could use fcntl F_DUPFD_CLOEXEC
|
||||
// instead of the ForkLock, but only for dup(fd, -1).
|
||||
|
||||
var ForkLock sync.RWMutex
|
||||
|
||||
// Convert array of string to array
|
||||
// of NUL-terminated byte pointer.
|
||||
func StringArrayPtr(ss []string) []*byte {
|
||||
bb := make([]*byte, len(ss)+1)
|
||||
for i := 0; i < len(ss); i++ {
|
||||
bb[i] = StringBytePtr(ss[i])
|
||||
}
|
||||
bb[len(ss)] = nil
|
||||
return bb
|
||||
}
|
||||
|
||||
// gbit16 reads a 16-bit numeric value from a 9P protocol message strored in b,
|
||||
// returning the value and the remaining slice of b.
|
||||
func gbit16(b []byte) (uint16, []byte) {
|
||||
return uint16(b[0]) | uint16(b[1])<<8, b[2:]
|
||||
}
|
||||
|
||||
// gstring reads a string from a 9P protocol message strored in b,
|
||||
// returning the value as a Go string and the remaining slice of b.
|
||||
func gstring(b []byte) (string, []byte) {
|
||||
n, b := gbit16(b)
|
||||
return string(b[0:n]), b[n:]
|
||||
}
|
||||
|
||||
// readdirnames returns the names of files inside the directory represented by dirfd.
|
||||
func readdirnames(dirfd int) (names []string, err Error) {
|
||||
result := make([]string, 0, 100)
|
||||
var buf [STATMAX]byte
|
||||
|
||||
for {
|
||||
n, e := Read(dirfd, buf[:])
|
||||
if e != nil {
|
||||
return []string{}, e
|
||||
}
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
for i := 0; i < n; {
|
||||
m, _ := gbit16(buf[i:])
|
||||
m += 2
|
||||
|
||||
if m < STATFIXLEN {
|
||||
return []string{}, NewError("malformed stat buffer")
|
||||
}
|
||||
|
||||
name, _ := gstring(buf[i+41:])
|
||||
result = append(result, name)
|
||||
|
||||
i += int(m)
|
||||
}
|
||||
}
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
// readdupdevice returns a list of currently opened fds (excluding stdin, stdout, stderr) from the dup device #d.
|
||||
// ForkLock should be write locked before calling, so that no new fds would be created while the fd list is being read.
|
||||
func readdupdevice() (fds []int, err Error) {
|
||||
dupdevfd, err := Open("#d", O_RDONLY)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer Close(dupdevfd)
|
||||
|
||||
fileNames, err := readdirnames(dupdevfd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fds = make([]int, 0, len(fileNames)>>1)
|
||||
for _, fdstr := range fileNames {
|
||||
if l := len(fdstr); l > 2 && fdstr[l-3] == 'c' && fdstr[l-2] == 't' && fdstr[l-1] == 'l' {
|
||||
continue
|
||||
}
|
||||
|
||||
fd := int(atoi([]byte(fdstr)))
|
||||
|
||||
if fd == 0 || fd == 1 || fd == 2 || fd == dupdevfd {
|
||||
continue
|
||||
}
|
||||
|
||||
fds = append(fds, fd)
|
||||
}
|
||||
|
||||
return fds[0:len(fds)], nil
|
||||
}
|
||||
|
||||
var startupFds []int
|
||||
|
||||
// Plan 9 does not allow clearing the OCEXEC flag
|
||||
// from the underlying channel backing an open file descriptor,
|
||||
// therefore we store a list of already opened file descriptors
|
||||
// inside startupFds and skip them when manually closing descriptors
|
||||
// not meant to be passed to a child exec.
|
||||
func init() {
|
||||
startupFds, _ = readdupdevice()
|
||||
}
|
||||
|
||||
// forkAndExecInChild forks the process, calling dup onto 0..len(fd)
|
||||
// and finally invoking exec(argv0, argvv, envv) in the child.
|
||||
// If a dup or exec fails, it writes the error string to pipe.
|
||||
// (The pipe write end is close-on-exec so if exec succeeds, it will be closed.)
|
||||
//
|
||||
// In the child, this function must not acquire any locks, because
|
||||
// they might have been locked at the time of the fork. This means
|
||||
// no rescheduling, no malloc calls, and no new stack segments.
|
||||
// The calls to RawSyscall are okay because they are assembly
|
||||
// functions that do not grow the stack.
|
||||
func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, chroot, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int) (pid int, err Error) {
|
||||
// Declare all variables at top in case any
|
||||
// declarations require heap allocation (e.g., errbuf).
|
||||
var (
|
||||
r1 uintptr
|
||||
nextfd int
|
||||
i int
|
||||
clearenv int
|
||||
envfd int
|
||||
errbuf [ERRMAX]byte
|
||||
)
|
||||
|
||||
// guard against side effects of shuffling fds below.
|
||||
fd := append([]int(nil), attr.Files...)
|
||||
|
||||
if envv != nil {
|
||||
clearenv = RFCENVG
|
||||
}
|
||||
|
||||
// About to call fork.
|
||||
// No more allocation or calls of non-assembly functions.
|
||||
r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv), 0, 0)
|
||||
|
||||
if r1 != 0 {
|
||||
if int(r1) == -1 {
|
||||
return 0, NewError(errstr())
|
||||
}
|
||||
// parent; return PID
|
||||
return int(r1), nil
|
||||
}
|
||||
|
||||
// Fork succeeded, now in child.
|
||||
|
||||
// Close fds we don't need.
|
||||
for i = 0; i < len(fdsToClose); i++ {
|
||||
r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(fdsToClose[i]), 0, 0)
|
||||
if int(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
if envv != nil {
|
||||
// Write new environment variables.
|
||||
for i = 0; i < len(envv); i++ {
|
||||
r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666))
|
||||
|
||||
if int(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
|
||||
envfd = int(r1)
|
||||
|
||||
r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintptr(unsafe.Pointer(envv[i].value)), uintptr(envv[i].nvalue),
|
||||
^uintptr(0), ^uintptr(0), 0)
|
||||
|
||||
if int(r1) == -1 || int(r1) != envv[i].nvalue {
|
||||
goto childerror
|
||||
}
|
||||
|
||||
r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0)
|
||||
|
||||
if int(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Chdir
|
||||
if dir != nil {
|
||||
r1, _, _ = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
|
||||
if int(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 1: look for fd[i] < i and move those up above len(fd)
|
||||
// so that pass 2 won't stomp on an fd it needs later.
|
||||
nextfd = int(len(fd))
|
||||
if pipe < nextfd {
|
||||
r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0)
|
||||
if int(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
pipe = nextfd
|
||||
nextfd++
|
||||
}
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] >= 0 && fd[i] < int(i) {
|
||||
r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(nextfd), 0)
|
||||
if int(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
|
||||
fd[i] = nextfd
|
||||
nextfd++
|
||||
if nextfd == pipe { // don't stomp on pipe
|
||||
nextfd++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: dup fd[i] down onto i.
|
||||
for i = 0; i < len(fd); i++ {
|
||||
if fd[i] == -1 {
|
||||
RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
|
||||
continue
|
||||
}
|
||||
if fd[i] == int(i) {
|
||||
continue
|
||||
}
|
||||
|
||||
r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(i), 0)
|
||||
if int(r1) == -1 {
|
||||
goto childerror
|
||||
}
|
||||
RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0)
|
||||
}
|
||||
|
||||
// Time to exec.
|
||||
r1, _, _ = RawSyscall(SYS_EXEC,
|
||||
uintptr(unsafe.Pointer(argv0)),
|
||||
uintptr(unsafe.Pointer(&argv[0])), 0)
|
||||
|
||||
childerror:
|
||||
// send error string on pipe
|
||||
RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0)
|
||||
errbuf[len(errbuf)-1] = 0
|
||||
i = 0
|
||||
for i < len(errbuf) && errbuf[i] != 0 {
|
||||
i++
|
||||
}
|
||||
|
||||
RawSyscall6(SYS_PWRITE, uintptr(pipe), uintptr(unsafe.Pointer(&errbuf[0])), uintptr(i),
|
||||
^uintptr(0), ^uintptr(0), 0)
|
||||
|
||||
for {
|
||||
RawSyscall(SYS_EXITS, 0, 0, 0)
|
||||
}
|
||||
|
||||
// Calling panic is not actually safe,
|
||||
// but the for loop above won't break
|
||||
// and this shuts up the compiler.
|
||||
panic("unreached")
|
||||
}
|
||||
|
||||
func cexecPipe(p []int) Error {
|
||||
e := Pipe(p)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
fd, e := Open("#d/"+itoa(p[1]), O_CLOEXEC)
|
||||
if e != nil {
|
||||
Close(p[0])
|
||||
Close(p[1])
|
||||
return e
|
||||
}
|
||||
|
||||
Close(fd)
|
||||
return nil
|
||||
}
|
||||
|
||||
type envItem struct {
|
||||
name *byte
|
||||
value *byte
|
||||
nvalue int
|
||||
}
|
||||
|
||||
type ProcAttr struct {
|
||||
Dir string // Current working directory.
|
||||
Env []string // Environment.
|
||||
Files []int // File descriptors.
|
||||
Chroot string // Chroot.
|
||||
}
|
||||
|
||||
var zeroAttributes ProcAttr
|
||||
|
||||
|
||||
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
|
||||
var (
|
||||
p [2]int
|
||||
n int
|
||||
errbuf [ERRMAX]byte
|
||||
wmsg Waitmsg
|
||||
)
|
||||
|
||||
if attr == nil {
|
||||
attr = &zeroAttributes
|
||||
}
|
||||
|
||||
p[0] = -1
|
||||
p[1] = -1
|
||||
|
||||
// Convert args to C form.
|
||||
argv0p := StringBytePtr(argv[0])
|
||||
argvp := StringArrayPtr(argv)
|
||||
|
||||
var chroot *byte
|
||||
if attr.Chroot != "" {
|
||||
chroot = StringBytePtr(attr.Chroot)
|
||||
}
|
||||
var dir *byte
|
||||
if attr.Dir != "" {
|
||||
dir = StringBytePtr(attr.Dir)
|
||||
}
|
||||
var envvParsed []envItem
|
||||
if attr.Env != nil {
|
||||
envvParsed = make([]envItem, 0, len(attr.Env))
|
||||
for _, v := range attr.Env {
|
||||
i := 0
|
||||
for i < len(v) && v[i] != '=' {
|
||||
i++
|
||||
}
|
||||
|
||||
envvParsed = append(envvParsed, envItem{StringBytePtr("/env/" + v[:i]), StringBytePtr(v[i+1:]), len(v) - i})
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire the fork lock to prevent other threads from creating new fds before we fork.
|
||||
ForkLock.Lock()
|
||||
|
||||
// get a list of open fds, excluding stdin,stdout and stderr that need to be closed in the child.
|
||||
// no new fds can be created while we hold the ForkLock for writing.
|
||||
openFds, e := readdupdevice()
|
||||
|
||||
if e != nil {
|
||||
ForkLock.Unlock()
|
||||
return 0, e
|
||||
}
|
||||
|
||||
fdsToClose := make([]int, 0, len(openFds))
|
||||
// exclude fds opened from startup from the list of fds to be closed.
|
||||
for _, fd := range openFds {
|
||||
isReserved := false
|
||||
for _, reservedFd := range startupFds {
|
||||
if fd == reservedFd {
|
||||
isReserved = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !isReserved {
|
||||
fdsToClose = append(fdsToClose, fd)
|
||||
}
|
||||
}
|
||||
|
||||
// exclude fds requested by the caller from the list of fds to be closed.
|
||||
for _, fd := range openFds {
|
||||
isReserved := false
|
||||
for _, reservedFd := range attr.Files {
|
||||
if fd == reservedFd {
|
||||
isReserved = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !isReserved {
|
||||
fdsToClose = append(fdsToClose, fd)
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate child status pipe close on exec.
|
||||
e = cexecPipe(p[:])
|
||||
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
fdsToClose = append(fdsToClose, p[0])
|
||||
|
||||
// Kick off child.
|
||||
pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, chroot, dir, attr, fdsToClose, p[1])
|
||||
|
||||
if err != nil {
|
||||
if p[0] >= 0 {
|
||||
Close(p[0])
|
||||
Close(p[1])
|
||||
}
|
||||
ForkLock.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
ForkLock.Unlock()
|
||||
|
||||
// Read child error status from pipe.
|
||||
Close(p[1])
|
||||
n, err = Read(p[0], errbuf[:])
|
||||
Close(p[0])
|
||||
|
||||
if err != nil || n != 0 {
|
||||
if n != 0 {
|
||||
err = NewError(string(errbuf[:]))
|
||||
}
|
||||
|
||||
// Child failed; wait for it to exit, to make sure
|
||||
// the zombies don't accumulate.
|
||||
for wmsg.Pid != pid {
|
||||
Await(&wmsg)
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Read got EOF, so pipe closed on exec, so exec succeeded.
|
||||
return pid, nil
|
||||
}
|
||||
|
||||
// Combination of fork and exec, careful to be thread safe.
|
||||
func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
|
||||
return forkExec(argv0, argv, attr)
|
||||
}
|
||||
|
||||
// StartProcess wraps ForkExec for package os.
|
||||
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err Error) {
|
||||
pid, err = forkExec(argv0, argv, attr)
|
||||
return pid, 0, err
|
||||
}
|
||||
|
||||
// Ordinary exec.
|
||||
func Exec(argv0 string, argv []string, envv []string) (err Error) {
|
||||
if envv != nil {
|
||||
r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
|
||||
if int(r1) == -1 {
|
||||
return NewError(errstr())
|
||||
}
|
||||
|
||||
for _, v := range envv {
|
||||
i := 0
|
||||
for i < len(v) && v[i] != '=' {
|
||||
i++
|
||||
}
|
||||
|
||||
fd, e := Create("/env/"+v[:i], O_WRONLY, 0666)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
_, e = Write(fd, []byte(v[i+1:]))
|
||||
if e != nil {
|
||||
Close(fd)
|
||||
return e
|
||||
}
|
||||
Close(fd)
|
||||
}
|
||||
}
|
||||
|
||||
_, _, e := Syscall(SYS_EXEC,
|
||||
uintptr(unsafe.Pointer(StringBytePtr(argv0))),
|
||||
uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])),
|
||||
0)
|
||||
|
||||
return NewError(e)
|
||||
}
|
@ -145,6 +145,12 @@ windows_386)
|
||||
mktypes=
|
||||
mkerrors="./mkerrors_windows.sh -f -m32"
|
||||
;;
|
||||
plan9_386)
|
||||
mkerrors=
|
||||
mksyscall="./mksyscall.pl -l32 -plan9"
|
||||
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
|
||||
mktypes="godefs -gsyscall -f -m32"
|
||||
;;
|
||||
*)
|
||||
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
|
||||
exit 1
|
||||
|
@ -23,6 +23,7 @@ $cmdline = "mksyscall.pl " . join(' ', @ARGV);
|
||||
$errors = 0;
|
||||
$_32bit = "";
|
||||
$nacl = 0;
|
||||
$plan9 = 0;
|
||||
|
||||
if($ARGV[0] eq "-b32") {
|
||||
$_32bit = "big-endian";
|
||||
@ -35,6 +36,10 @@ if($ARGV[0] eq "-nacl") {
|
||||
$nacl = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-plan9") {
|
||||
$plan9 = 1;
|
||||
shift;
|
||||
}
|
||||
|
||||
if($ARGV[0] =~ /^-/) {
|
||||
print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n";
|
||||
@ -160,9 +165,13 @@ while(<>) {
|
||||
my $p = $out[$i];
|
||||
my ($name, $type) = parseparam($p);
|
||||
my $reg = "";
|
||||
if($name eq "errno") {
|
||||
if($name eq "errno" && !$plan9) {
|
||||
$reg = "e1";
|
||||
$ret[2] = $reg;
|
||||
} elsif ($name eq "err" && $plan9) {
|
||||
$ret[0] = "r0";
|
||||
$ret[2] = "e1";
|
||||
next;
|
||||
} else {
|
||||
$reg = sprintf("r%d", $i);
|
||||
$ret[$i] = $reg;
|
||||
@ -191,6 +200,13 @@ while(<>) {
|
||||
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
|
||||
}
|
||||
$text .= $body;
|
||||
|
||||
if ($plan9 && $ret[2] eq "e1") {
|
||||
$text .= "\terr = nil\n";
|
||||
$text .= "\tif int(r0) == -1 {\n";
|
||||
$text .= "\t\t err = NewError(e1)\n";
|
||||
$text .= "\t}\n";
|
||||
}
|
||||
|
||||
$text .= "\treturn\n";
|
||||
$text .= "}\n\n";
|
||||
|
25
src/pkg/syscall/mksysnum_plan9.sh
Executable file
25
src/pkg/syscall/mksysnum_plan9.sh
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
# 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.# 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.
|
||||
|
||||
COMMAND="mksysnum_plan9.sh $@"
|
||||
|
||||
cat <<EOF
|
||||
// $COMMAND
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const(
|
||||
EOF
|
||||
|
||||
SP='[ ]' # space or tab
|
||||
sed "s/^#define${SP}\\([A-Z0-9_][A-Z0-9_]*\\)${SP}${SP}*\\([0-9][0-9]*\\)/SYS_\\1=\\2/g" \
|
||||
< $1 | grep -v SYS__
|
||||
|
||||
cat <<EOF
|
||||
)
|
||||
EOF
|
@ -4,9 +4,9 @@
|
||||
|
||||
package syscall
|
||||
|
||||
func str(val int) string { // do it here rather than with fmt to avoid dependency
|
||||
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
||||
if val < 0 {
|
||||
return "-" + str(-val)
|
||||
return "-" + itoa(-val)
|
||||
}
|
||||
var buf [32]byte // big enough for int64
|
||||
i := len(buf) - 1
|
||||
|
@ -60,7 +60,7 @@ func Futimesat(dirfd int, path string, tv []Timeval) (errno int) {
|
||||
func Futimes(fd int, tv []Timeval) (errno int) {
|
||||
// Believe it or not, this is the best we can do on Linux
|
||||
// (and is what glibc does).
|
||||
return Utimes("/proc/self/fd/"+str(fd), tv)
|
||||
return Utimes("/proc/self/fd/"+itoa(fd), tv)
|
||||
}
|
||||
|
||||
const ImplementsGetwd = true
|
||||
|
343
src/pkg/syscall/syscall_plan9.go
Normal file
343
src/pkg/syscall/syscall_plan9.go
Normal file
@ -0,0 +1,343 @@
|
||||
// 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.
|
||||
|
||||
// Plan 9 system calls.
|
||||
// This file is compiled as ordinary Go code,
|
||||
// but it is also input to mksyscall,
|
||||
// which parses the //sys lines and generates system call stubs.
|
||||
// Note that sometimes we use a lowercase //sys name and
|
||||
// wrap it in our own nicer implementation.
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
const OS = "plan9"
|
||||
|
||||
const ImplementsGetwd = true
|
||||
|
||||
// An Error can represent any printable error condition.
|
||||
type Error interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// ErrorString implements Error's String method by returning itself.
|
||||
type ErrorString string
|
||||
|
||||
func (e ErrorString) String() string { return string(e) }
|
||||
|
||||
// NewError converts s to an ErrorString, which satisfies the Error interface.
|
||||
func NewError(s string) Error { return ErrorString(s) }
|
||||
|
||||
var (
|
||||
Stdin = 0
|
||||
Stdout = 1
|
||||
Stderr = 2
|
||||
|
||||
EISDIR Error = NewError("file is a directory")
|
||||
)
|
||||
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err string)
|
||||
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err string)
|
||||
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
|
||||
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
|
||||
|
||||
func atoi(b []byte) (n uint) {
|
||||
n = 0
|
||||
for i := 0; i < len(b); i++ {
|
||||
n = n*10 + uint(b[i]-'0')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func cstring(s []byte) string {
|
||||
for i, _ := range s {
|
||||
if s[i] == 0 {
|
||||
return string(s[0:i])
|
||||
}
|
||||
}
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func errstr() string {
|
||||
var buf [ERRMAX]byte
|
||||
|
||||
RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
|
||||
|
||||
buf[len(buf)-1] = 0
|
||||
return cstring(buf[:])
|
||||
}
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
//sys exits(msg *byte)
|
||||
func Exits(msg *string) {
|
||||
if msg == nil {
|
||||
exits(nil)
|
||||
}
|
||||
|
||||
exits(StringBytePtr(*msg))
|
||||
}
|
||||
|
||||
func Exit(code int) {
|
||||
if code == 0 {
|
||||
Exits(nil)
|
||||
}
|
||||
|
||||
msg := itoa(code)
|
||||
Exits(&msg)
|
||||
}
|
||||
|
||||
func readnum(path string) (uint, Error) {
|
||||
var b [12]byte
|
||||
|
||||
fd, e := Open(path, O_RDONLY)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
defer Close(fd)
|
||||
|
||||
n, e := Pread(fd, b[:], 0)
|
||||
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
|
||||
m := 0
|
||||
for ; m < n && b[m] == ' '; m++ {
|
||||
}
|
||||
|
||||
return atoi(b[m : n-1]), nil
|
||||
}
|
||||
|
||||
func Getpid() (pid int) {
|
||||
n, _ := readnum("#c/pid")
|
||||
return int(n)
|
||||
}
|
||||
|
||||
func Getppid() (ppid int) {
|
||||
n, _ := readnum("#c/ppid")
|
||||
return int(n)
|
||||
}
|
||||
|
||||
|
||||
func Read(fd int, p []byte) (n int, err Error) {
|
||||
return Pread(fd, p, -1)
|
||||
}
|
||||
|
||||
func Write(fd int, p []byte) (n int, err Error) {
|
||||
return Pwrite(fd, p, -1)
|
||||
}
|
||||
|
||||
func Getwd() (wd string, err Error) {
|
||||
fd, e := Open(".", O_RDONLY)
|
||||
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
defer Close(fd)
|
||||
|
||||
return Fd2path(fd)
|
||||
}
|
||||
|
||||
//sys fd2path(fd int, buf []byte) (err Error)
|
||||
func Fd2path(fd int) (path string, err Error) {
|
||||
var buf [512]byte
|
||||
|
||||
e := fd2path(fd, buf[:])
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
return cstring(buf[:]), nil
|
||||
}
|
||||
|
||||
//sys pipe(p *[2]_C_int) (err Error)
|
||||
func Pipe(p []int) (err Error) {
|
||||
if len(p) != 2 {
|
||||
return NewError("bad arg in system call")
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe(&pp)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//sys sleep(millisecs int32) (err Error)
|
||||
func Sleep(nsec int64) (err Error) {
|
||||
return sleep(int32((nsec + 999) / 1e6)) // round up to microsecond
|
||||
}
|
||||
|
||||
// Underlying system call writes to newoffset via pointer.
|
||||
// Implemented in assembly to avoid allocation.
|
||||
func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
|
||||
|
||||
func Seek(fd int, offset int64, whence int) (newoffset int64, err Error) {
|
||||
newoffset, e := seek(0, fd, offset, whence)
|
||||
|
||||
err = nil
|
||||
if newoffset == -1 {
|
||||
err = NewError(e)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Mkdir(path string, mode uint32) (err Error) {
|
||||
fd, err := Create(path, O_RDONLY, DMDIR|mode)
|
||||
|
||||
if fd != -1 {
|
||||
Close(fd)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type Waitmsg struct {
|
||||
Pid int
|
||||
Time [3]uint32
|
||||
Msg string
|
||||
}
|
||||
|
||||
//sys await(s []byte) (n int, err Error)
|
||||
func Await(w *Waitmsg) (err Error) {
|
||||
var buf [512]byte
|
||||
var f [5][]byte
|
||||
|
||||
n, err := await(buf[:])
|
||||
|
||||
if err != nil || w == nil {
|
||||
return
|
||||
}
|
||||
|
||||
nf := 0
|
||||
p := 0
|
||||
for i := 0; i < n && nf < len(f)-1; i++ {
|
||||
if buf[i] == ' ' {
|
||||
f[nf] = buf[p:i]
|
||||
p = i + 1
|
||||
nf++
|
||||
}
|
||||
}
|
||||
f[nf] = buf[p:]
|
||||
nf++
|
||||
|
||||
if nf != len(f) {
|
||||
return NewError("invalid wait message")
|
||||
}
|
||||
w.Pid = int(atoi(f[0]))
|
||||
w.Time[0] = uint32(atoi(f[1]))
|
||||
w.Time[1] = uint32(atoi(f[2]))
|
||||
w.Time[2] = uint32(atoi(f[3]))
|
||||
w.Msg = string(f[4])
|
||||
return
|
||||
}
|
||||
|
||||
func Unmount(name, old string) (err Error) {
|
||||
oldp := uintptr(unsafe.Pointer(StringBytePtr(old)))
|
||||
|
||||
var r0 uintptr
|
||||
var e string
|
||||
|
||||
// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
|
||||
if name == "" {
|
||||
r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldp, 0)
|
||||
} else {
|
||||
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(name))), oldp, 0)
|
||||
}
|
||||
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Fchdir(fd int) (err Error) {
|
||||
path, err := Fd2path(fd)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return Chdir(path)
|
||||
}
|
||||
|
||||
type Timeval struct {
|
||||
Sec int32
|
||||
Usec int32
|
||||
}
|
||||
|
||||
func NsecToTimeval(nsec int64) (tv Timeval) {
|
||||
nsec += 999 // round up to microsecond
|
||||
tv.Usec = int32(nsec % 1e9 / 1e3)
|
||||
tv.Sec = int32(nsec / 1e9)
|
||||
return
|
||||
}
|
||||
|
||||
func DecodeBintime(b []byte) (nsec int64, err Error) {
|
||||
if len(b) != 8 {
|
||||
return -1, NewError("bad /dev/bintime format")
|
||||
}
|
||||
err = nil
|
||||
nsec = int64(b[0])<<56 |
|
||||
int64(b[1])<<48 |
|
||||
int64(b[2])<<40 |
|
||||
int64(b[3])<<32 |
|
||||
int64(b[4])<<24 |
|
||||
int64(b[5])<<16 |
|
||||
int64(b[6])<<8 |
|
||||
int64(b[7])
|
||||
return
|
||||
}
|
||||
|
||||
func Gettimeofday(tv *Timeval) (err Error) {
|
||||
// TODO(paulzhol):
|
||||
// avoid reopening a file descriptor for /dev/bintime on each call,
|
||||
// use lower-level calls to avoid allocation.
|
||||
|
||||
var b [8]byte
|
||||
var nsec int64
|
||||
|
||||
fd, e := Open("/dev/bintime", O_RDONLY)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer Close(fd)
|
||||
|
||||
if _, e = Pread(fd, b[:], 0); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if nsec, e = DecodeBintime(b[:]); e != nil {
|
||||
return e
|
||||
}
|
||||
*tv = NsecToTimeval(nsec)
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func Getegid() (egid int) { return -1 }
|
||||
func Geteuid() (euid int) { return -1 }
|
||||
func Getgid() (gid int) { return -1 }
|
||||
func Getuid() (uid int) { return -1 }
|
||||
|
||||
func Getgroups() (gids []int, err Error) {
|
||||
return make([]int, 0), nil
|
||||
}
|
||||
|
||||
//sys Dup(oldfd int, newfd int) (fd int, err Error)
|
||||
//sys Open(path string, mode int) (fd int, err Error)
|
||||
//sys Create(path string, mode int, perm uint32) (fd int, err Error)
|
||||
//sys Remove(path string) (err Error)
|
||||
//sys Pread(fd int, p []byte, offset int64) (n int, err Error)
|
||||
//sys Pwrite(fd int, p []byte, offset int64) (n int, err Error)
|
||||
//sys Close(fd int) (err Error)
|
||||
//sys Chdir(path string) (err Error)
|
||||
//sys Bind(name string, old string, flag int) (err Error)
|
||||
//sys Mount(fd int, afd int, old string, flag int, aname string) (err Error)
|
||||
//sys Stat(path string, edir []byte) (n int, err Error)
|
||||
//sys Fstat(fd int, edir []byte) (n int, err Error)
|
||||
//sys Wstat(path string, edir []byte) (err Error)
|
||||
//sys Fwstat(fd int, edir []byte) (err Error)
|
5
src/pkg/syscall/syscall_plan9_386.go
Normal file
5
src/pkg/syscall/syscall_plan9_386.go
Normal file
@ -0,0 +1,5 @@
|
||||
// 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 syscall
|
@ -17,7 +17,7 @@ func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
|
||||
|
||||
func Errstr(errno int) string {
|
||||
if errno < 0 || errno >= int(len(errors)) {
|
||||
return "error " + str(errno)
|
||||
return "error " + itoa(errno)
|
||||
}
|
||||
return errors[errno]
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ func Errstr(errno int) string {
|
||||
b := make([]uint16, 300)
|
||||
n, err := FormatMessage(flags, 0, uint32(errno), 0, b, nil)
|
||||
if err != 0 {
|
||||
return "error " + str(errno) + " (FormatMessage failed with err=" + str(err) + ")"
|
||||
return "error " + itoa(errno) + " (FormatMessage failed with err=" + itoa(err) + ")"
|
||||
}
|
||||
// trim terminating \r and \n
|
||||
for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- {
|
||||
|
115
src/pkg/syscall/types_plan9.c
Normal file
115
src/pkg/syscall/types_plan9.c
Normal file
@ -0,0 +1,115 @@
|
||||
// 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 godefs. See also mkerrors.sh and mkall.sh
|
||||
*/
|
||||
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned int uint;
|
||||
typedef long long vlong;
|
||||
typedef unsigned long long uvlong;
|
||||
|
||||
typedef int $_C_int;
|
||||
|
||||
enum {
|
||||
OREAD = 0, // open for read
|
||||
OWRITE = 1, // write
|
||||
ORDWR = 2, // read and write
|
||||
|
||||
$O_RDONLY = OREAD,
|
||||
$O_WRONLY = OWRITE,
|
||||
$O_RDWR = ORDWR,
|
||||
|
||||
OEXEC = 3, // execute, == read but check execute permission
|
||||
OTRUNC = 16, // or'ed in (except for exec), truncate file first
|
||||
OCEXEC = 32, // or'ed in, close on exec
|
||||
|
||||
$O_CLOEXEC = OCEXEC,
|
||||
|
||||
ORCLOSE = 64, // or'ed in, remove on close
|
||||
OEXCL = 0x1000, // or'ed in, exclusive use (create only)
|
||||
$O_EXCL = OEXCL,
|
||||
|
||||
$STATMAX = 65535U,
|
||||
$ERRMAX = 128,
|
||||
|
||||
$MORDER = 0x0003, // mask for bits defining order of mounting
|
||||
$MREPL = 0x0000, // mount replaces object
|
||||
$MBEFORE = 0x0001, // mount goes before others in union directory
|
||||
$MAFTER = 0x0002, // mount goes after others in union directory
|
||||
$MCREATE = 0x0004, // permit creation in mounted directory
|
||||
$MCACHE = 0x0010, // cache some data
|
||||
$MMASK = 0x0017, // all bits on
|
||||
|
||||
$RFNAMEG = (1<<0),
|
||||
$RFENVG = (1<<1),
|
||||
$RFFDG = (1<<2),
|
||||
$RFNOTEG = (1<<3),
|
||||
$RFPROC = (1<<4),
|
||||
$RFMEM = (1<<5),
|
||||
$RFNOWAIT = (1<<6),
|
||||
$RFCNAMEG = (1<<10),
|
||||
$RFCENVG = (1<<11),
|
||||
$RFCFDG = (1<<12),
|
||||
$RFREND = (1<<13),
|
||||
$RFNOMNT = (1<<14),
|
||||
|
||||
// bits in Qid.type
|
||||
$QTDIR = 0x80, // type bit for directories
|
||||
$QTAPPEND = 0x40, // type bit for append only files
|
||||
$QTEXCL = 0x20, // type bit for exclusive use files
|
||||
$QTMOUNT = 0x10, // type bit for mounted channel
|
||||
$QTAUTH = 0x08, // type bit for authentication file
|
||||
$QTTMP = 0x04, // type bit for not-backed-up file
|
||||
$QTFILE = 0x00, // plain file
|
||||
|
||||
|
||||
// bits in Dir.mode
|
||||
$DMDIR = 0x80000000, // mode bit for directories
|
||||
$DMAPPEND = 0x40000000, // mode bit for append only files
|
||||
$DMEXCL = 0x20000000, // mode bit for exclusive use files
|
||||
$DMMOUNT = 0x10000000, // mode bit for mounted channel
|
||||
$DMAUTH = 0x08000000, // mode bit for authentication file
|
||||
$DMTMP = 0x04000000, // mode bit for non-backed-up files
|
||||
$DMREAD = 0x4, // mode bit for read permission
|
||||
$DMWRITE = 0x2, // mode bit for write permission
|
||||
$DMEXEC = 0x1, // mode bit for execute permission
|
||||
|
||||
BIT8SZ = 1,
|
||||
BIT16SZ = 2,
|
||||
BIT32SZ = 4,
|
||||
BIT64SZ = 8,
|
||||
QIDSZ = BIT8SZ+BIT32SZ+BIT64SZ,
|
||||
|
||||
// STATFIXLEN includes leading 16-bit count
|
||||
// The count, however, excludes itself; total size is BIT16SZ+count
|
||||
$STATFIXLEN = BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ, // amount of fixed length data in a stat buffer
|
||||
};
|
||||
|
||||
|
||||
struct Prof // Per process profiling
|
||||
{
|
||||
struct Plink *pp; // known to be 0(ptr)
|
||||
struct Plink *next; // known to be 4(ptr)
|
||||
struct Plink *last;
|
||||
struct Plink *first;
|
||||
ulong pid;
|
||||
ulong what;
|
||||
};
|
||||
|
||||
struct Tos {
|
||||
struct Prof prof;
|
||||
uvlong cyclefreq; // cycle clock frequency if there is one, 0 otherwise
|
||||
vlong kcycles; // cycles spent in kernel
|
||||
vlong pcycles; // cycles spent in process (kernel + user)
|
||||
ulong pid; // might as well put the pid here
|
||||
ulong clock;
|
||||
// top of stack is here
|
||||
};
|
||||
|
||||
typedef struct Prof $Prof;
|
||||
typedef struct Tos $Tos;
|
25
src/pkg/syscall/zerrors_plan9_386.go
Normal file
25
src/pkg/syscall/zerrors_plan9_386.go
Normal file
@ -0,0 +1,25 @@
|
||||
package syscall
|
||||
|
||||
// Constants
|
||||
const (
|
||||
// Invented values to support what package os expects.
|
||||
O_CREAT = 0x02000
|
||||
O_NOCTTY = 0x00000
|
||||
O_TRUNC = 0x00000
|
||||
O_NONBLOCK = 0x00000
|
||||
O_APPEND = 0x00000
|
||||
O_SYNC = 0x00000
|
||||
O_ASYNC = 0x00000
|
||||
|
||||
|
||||
S_IFMT = 0x1f000
|
||||
S_IFIFO = 0x1000
|
||||
S_IFCHR = 0x2000
|
||||
S_IFDIR = 0x4000
|
||||
S_IFBLK = 0x6000
|
||||
S_IFREG = 0x8000
|
||||
S_IFLNK = 0xa000
|
||||
S_IFSOCK = 0xc000
|
||||
)
|
||||
|
||||
// Error table
|
267
src/pkg/syscall/zsyscall_plan9_386.go
Normal file
267
src/pkg/syscall/zsyscall_plan9_386.go
Normal file
@ -0,0 +1,267 @@
|
||||
// mksyscall.pl -l32 -plan9 syscall_plan9.go syscall_plan9_386.go
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func exits(msg *byte) {
|
||||
Syscall(SYS_EXITS, uintptr(unsafe.Pointer(msg)), 0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func fd2path(fd int, buf []byte) (err Error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(buf) > 0 {
|
||||
_p0 = unsafe.Pointer(&buf[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func pipe(p *[2]_C_int) (err Error) {
|
||||
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func sleep(millisecs int32) (err Error) {
|
||||
r0, _, e1 := Syscall(SYS_SLEEP, uintptr(millisecs), 0, 0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func await(s []byte) (n int, err Error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(s) > 0 {
|
||||
_p0 = unsafe.Pointer(&s[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
|
||||
n = int(r0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Dup(oldfd int, newfd int) (fd int, err Error) {
|
||||
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
|
||||
fd = int(r0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Open(path string, mode int) (fd int, err Error) {
|
||||
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
|
||||
fd = int(r0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Create(path string, mode int, perm uint32) (fd int, err Error) {
|
||||
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
|
||||
fd = int(r0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Remove(path string) (err Error) {
|
||||
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Pread(fd int, p []byte, offset int64) (n int, err Error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(p) > 0 {
|
||||
_p0 = unsafe.Pointer(&p[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
|
||||
n = int(r0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Pwrite(fd int, p []byte, offset int64) (n int, err Error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(p) > 0 {
|
||||
_p0 = unsafe.Pointer(&p[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
|
||||
n = int(r0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Close(fd int) (err Error) {
|
||||
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Chdir(path string) (err Error) {
|
||||
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Bind(name string, old string, flag int) (err Error) {
|
||||
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag))
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Mount(fd int, afd int, old string, flag int, aname string) (err Error) {
|
||||
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag), uintptr(unsafe.Pointer(StringBytePtr(aname))), 0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Stat(path string, edir []byte) (n int, err Error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p0 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir)))
|
||||
n = int(r0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fstat(fd int, edir []byte) (n int, err Error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p0 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
|
||||
n = int(r0)
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Wstat(path string, edir []byte) (err Error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p0 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir)))
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fwstat(fd int, edir []byte) (err Error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(edir) > 0 {
|
||||
_p0 = unsafe.Pointer(&edir[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
|
||||
err = nil
|
||||
if int(r0) == -1 {
|
||||
err = NewError(e1)
|
||||
}
|
||||
return
|
||||
}
|
47
src/pkg/syscall/zsysnum_plan9_386.go
Normal file
47
src/pkg/syscall/zsysnum_plan9_386.go
Normal file
@ -0,0 +1,47 @@
|
||||
// mksysnum_plan9.sh /media/sys/src/libc/9syscall/sys.h
|
||||
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||
|
||||
package syscall
|
||||
|
||||
const (
|
||||
SYS_SYSR1 = 0
|
||||
SYS_BIND = 2
|
||||
SYS_CHDIR = 3
|
||||
SYS_CLOSE = 4
|
||||
SYS_DUP = 5
|
||||
SYS_ALARM = 6
|
||||
SYS_EXEC = 7
|
||||
SYS_EXITS = 8
|
||||
SYS_FAUTH = 10
|
||||
SYS_SEGBRK = 12
|
||||
SYS_OPEN = 14
|
||||
SYS_OSEEK = 16
|
||||
SYS_SLEEP = 17
|
||||
SYS_RFORK = 19
|
||||
SYS_PIPE = 21
|
||||
SYS_CREATE = 22
|
||||
SYS_FD2PATH = 23
|
||||
SYS_BRK_ = 24
|
||||
SYS_REMOVE = 25
|
||||
SYS_NOTIFY = 28
|
||||
SYS_NOTED = 29
|
||||
SYS_SEGATTACH = 30
|
||||
SYS_SEGDETACH = 31
|
||||
SYS_SEGFREE = 32
|
||||
SYS_SEGFLUSH = 33
|
||||
SYS_RENDEZVOUS = 34
|
||||
SYS_UNMOUNT = 35
|
||||
SYS_SEMACQUIRE = 37
|
||||
SYS_SEMRELEASE = 38
|
||||
SYS_SEEK = 39
|
||||
SYS_FVERSION = 40
|
||||
SYS_ERRSTR = 41
|
||||
SYS_STAT = 42
|
||||
SYS_FSTAT = 43
|
||||
SYS_WSTAT = 44
|
||||
SYS_FWSTAT = 45
|
||||
SYS_MOUNT = 46
|
||||
SYS_AWAIT = 47
|
||||
SYS_PREAD = 50
|
||||
SYS_PWRITE = 51
|
||||
)
|
74
src/pkg/syscall/ztypes_plan9_386.go
Normal file
74
src/pkg/syscall/ztypes_plan9_386.go
Normal file
@ -0,0 +1,74 @@
|
||||
// godefs -gsyscall -f -m32 types_plan9.c
|
||||
|
||||
// MACHINE GENERATED - DO NOT EDIT.
|
||||
|
||||
package syscall
|
||||
|
||||
// Constants
|
||||
const (
|
||||
O_RDONLY = 0
|
||||
O_WRONLY = 0x1
|
||||
O_RDWR = 0x2
|
||||
O_CLOEXEC = 0x20
|
||||
O_EXCL = 0x1000
|
||||
STATMAX = 0xffff
|
||||
ERRMAX = 0x80
|
||||
MORDER = 0x3
|
||||
MREPL = 0
|
||||
MBEFORE = 0x1
|
||||
MAFTER = 0x2
|
||||
MCREATE = 0x4
|
||||
MCACHE = 0x10
|
||||
MMASK = 0x17
|
||||
RFNAMEG = 0x1
|
||||
RFENVG = 0x2
|
||||
RFFDG = 0x4
|
||||
RFNOTEG = 0x8
|
||||
RFPROC = 0x10
|
||||
RFMEM = 0x20
|
||||
RFNOWAIT = 0x40
|
||||
RFCNAMEG = 0x400
|
||||
RFCENVG = 0x800
|
||||
RFCFDG = 0x1000
|
||||
RFREND = 0x2000
|
||||
RFNOMNT = 0x4000
|
||||
QTDIR = 0x80
|
||||
QTAPPEND = 0x40
|
||||
QTEXCL = 0x20
|
||||
QTMOUNT = 0x10
|
||||
QTAUTH = 0x8
|
||||
QTTMP = 0x4
|
||||
QTFILE = 0
|
||||
DMDIR = 0x80000000
|
||||
DMAPPEND = 0x40000000
|
||||
DMEXCL = 0x20000000
|
||||
DMMOUNT = 0x10000000
|
||||
DMAUTH = 0x8000000
|
||||
DMTMP = 0x4000000
|
||||
DMREAD = 0x4
|
||||
DMWRITE = 0x2
|
||||
DMEXEC = 0x1
|
||||
STATFIXLEN = 0x31
|
||||
)
|
||||
|
||||
// Types
|
||||
|
||||
type _C_int int32
|
||||
|
||||
type Prof struct {
|
||||
Pp *[0]byte /* sPlink */
|
||||
Next *[0]byte /* sPlink */
|
||||
Last *[0]byte /* sPlink */
|
||||
First *[0]byte /* sPlink */
|
||||
Pid uint32
|
||||
What uint32
|
||||
}
|
||||
|
||||
type Tos struct {
|
||||
Prof Prof
|
||||
Cyclefreq uint64
|
||||
Kcycles int64
|
||||
Pcycles int64
|
||||
Pid uint32
|
||||
Clock uint32
|
||||
}
|
Loading…
Reference in New Issue
Block a user