Commit 602a446b authored by Russ Cox's avatar Russ Cox

new syscall package: manually maintained files and scripts.

auto-generated files and deletions are in another CL.

goals for new syscall:
	* automate as much as possible
	* do not let clients do unsafe things
	* use simple types (int not int64)
	* fewer files

the files are renamed from foo_amd64_linux to foo_linux_amd64,
both because it reads better (all the linux are related, all the amd64 less so)
and because it made it easier to replace the existing ones.

R=r
DELTA=2336  (2260 added, 6 deleted, 70 changed)
OCL=29709
CL=29723
parent 9e0fec9c
#!/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.
# The syscall package provides access to the raw system call
# interface of the underlying operating system. Porting Go to
# a new architecture/operating system combination requires
# some manual effort, though there are tools that automate
# much of the process. The auto-generated files have names
# beginning with z.
#
# This script prints suggested commands to generate z files
# for the current system. Running those commands is not automatic.
# This script is documentation more than anything else.
#
# * asm_${GOOS}_${GOARCH}.s
#
# This hand-written assembly file implements system call dispatch.
# There are three entry points:
#
# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
#
# The first and second are the standard ones; they differ only in
# how many arguments can be passed to the kernel.
# The third is for low-level use by the ForkExec wrapper;
# unlike the first two, it does not call into the scheduler to
# let it know that a system call is running.
#
# * syscall_${GOOS}.go
#
# This hand-written Go file implements system calls that need
# special handling and lists "//sys" comments giving prototypes
# for ones that can be auto-generated. Mksyscall reads those
# comments to generate the stubs.
#
# * syscall_${GOOS}_${GOARCH}.go
#
# Same as syscall_${GOOS}.go except that it contains code specific
# to ${GOOS} on one particular architecture.
#
# * types_${GOOS}.c
#
# This hand-written C file includes standard C headers and then
# creates typedef or enum names beginning with a dollar sign
# (use of $ in variable names is a gcc extension). The hardest
# part about preparing this file is figuring out which headers to
# include and which symbols need to be #defined to get the
# actual data structures that pass through to the kernel system calls.
# Some C libraries present alternate versions for binary compatibility
# and translate them on the way in and out of system calls, but
# there is almost always a #define that can get the real ones.
# See types_darwin.c and types_linux.c for examples.
#
# * types_${GOOS}_${GOARCH}.c
#
# Same as types_${GOOS}_${GOARCH}.go except that it contains
# definitions specific to ${GOOS} one one particular architecture.
#
# * zerror_${GOOS}_${GOARCH}.go
#
# This machine-generated file defines the system's error numbers,
# error strings, and signal numbers. The generator is "mkerrors".
# Usually no arguments are needed, but mkerrors will pass its
# arguments on to godefs.
#
# * zsyscall_${GOOS}_${GOARCH}.go
#
# Generated by mksyscall; see syscall_${GOOS}.go above.
#
# * zsysnum_${GOOS}_${GOARCH}.go
#
# Generated by mksysnum_${GOOS}.
#
# * ztypes_${GOOS}_${GOARCH}.go
#
# Generated by godefs; see types_${GOOS}.c above.
GOOSARCH="${GOOS}_${GOARCH}"
# defaults
mksyscall="mksyscall"
mkerrors="mkerrors"
case "$GOOSARCH" in
_* | *_ | _)
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
exit 1
;;
darwin_386)
mksyscall="mksyscall -l32"
mksysnum="mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master"
mktypes="godefs -gsyscall -f-m32"
;;
darwin_amd64)
mksysnum="mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master"
mktypes="godefs -gsyscall -f-m64"
mkerrors="mkerrors"
;;
linux_amd64)
mksysnum="mksysnum_linux /usr/include/asm/unistd_64.h"
mktypes="godefs -gsyscall -f-m64"
;;
*)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
exit 1
;;
esac
echo "$mkerrors >zerrors_$GOOSARCH.go"
echo "$mksyscall syscall_$GOOS.go syscall_$GOOSARCH.go >zsyscall_$GOOSARCH.go"
echo "$mksysnum >zsysnum_$GOOSARCH.go"
echo "$mktypes types_$GOOS.c types_$GOOSARCH.c >ztypes_$GOOSARCH.go"
port=$(ls *.go | grep -v _)
arch=$(ls *_$GOOSARCH.s *_$GOOSARCH.go *_$GOOS.go)
all=$(ls $port $arch) # sort them
echo gobuild $all
// 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
import "syscall"
func str(val int) string { // do it here rather than with fmt to avoid dependency
if val < 0 {
return "-" + str(-val);
}
var buf [32]byte; // big enough for int64
i := len(buf)-1;
for val >= 10 {
buf[i] = byte(val%10 + '0');
i--;
val /= 10;
}
buf[i] = byte(val + '0');
return string(buf[i:len(buf)]);
}
func Errstr(errno int) string {
if errno < 0 || errno >= int(len(errors)) {
return "error " + str(errno)
}
return errors[errno]
}
...@@ -61,10 +61,6 @@ import ( ...@@ -61,10 +61,6 @@ import (
var ForkLock sync.RWMutex var ForkLock sync.RWMutex
func CloseOnExec(fd int64) {
Fcntl(fd, F_SETFD, FD_CLOEXEC);
}
// Convert array of string to array // Convert array of string to array
// of NUL-terminated byte pointer. // of NUL-terminated byte pointer.
func StringArrayPtr(ss []string) []*byte { func StringArrayPtr(ss []string) []*byte {
...@@ -76,36 +72,40 @@ func StringArrayPtr(ss []string) []*byte { ...@@ -76,36 +72,40 @@ func StringArrayPtr(ss []string) []*byte {
return bb; return bb;
} }
func Wait4(pid int64, wstatus *WaitStatus, options int64, rusage *Rusage) func CloseOnExec(fd int) {
(wpid, err int64) fcntl(fd, F_SETFD, FD_CLOEXEC);
{ }
var s WaitStatus;
r1, r2, err1 := Syscall6(SYS_WAIT4, func SetNonblock(fd int, nonblocking bool) (errno int) {
pid, flag, err := fcntl(fd, F_GETFL, 0);
int64(uintptr(unsafe.Pointer(&s))), if err != 0 {
options, return err;
int64(uintptr(unsafe.Pointer(rusage))), 0, 0);
if wstatus != nil {
*wstatus = s;
} }
return r1, err1; if nonblocking {
flag |= O_NONBLOCK;
} else {
flag &= ^O_NONBLOCK;
}
flag, err = fcntl(fd, F_SETFL, flag);
return err;
} }
// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
// If a dup or exec fails, write the errno int64 to pipe. // If a dup or exec fails, write the errno int to pipe.
// (Pipe is close-on-exec so if exec succeeds, it will be closed.) // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
// In the child, this function must not acquire any locks, because // In the child, this function must not acquire any locks, because
// they might have been locked at the time of the fork. This means // they might have been locked at the time of the fork. This means
// no rescheduling, no malloc calls, and no new stack segments. // no rescheduling, no malloc calls, and no new stack segments.
// The calls to RawSyscall are okay because they are assembly // The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack. // functions that do not grow the stack.
func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd []int64, pipe int64) func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd []int, pipe int)
(pid int64, err int64) (pid int, err int)
{ {
// Declare all variables at top in case any // Declare all variables at top in case any
// declarations require heap allocation (e.g., err1). // declarations require heap allocation (e.g., err1).
var r1, r2, err1 int64; var r1, r2, err1 uintptr;
var nextfd int64; var nextfd int;
var i int; var i int;
darwin := OS == "darwin"; darwin := OS == "darwin";
...@@ -114,7 +114,7 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd [ ...@@ -114,7 +114,7 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd [
// No more allocation or calls of non-assembly functions. // No more allocation or calls of non-assembly functions.
r1, r2, err1 = RawSyscall(SYS_FORK, 0, 0, 0); r1, r2, err1 = RawSyscall(SYS_FORK, 0, 0, 0);
if err1 != 0 { if err1 != 0 {
return 0, err1 return 0, int(err1)
} }
// On Darwin: // On Darwin:
...@@ -127,38 +127,38 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd [ ...@@ -127,38 +127,38 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd [
if r1 != 0 { if r1 != 0 {
// parent; return PID // parent; return PID
return r1, 0 return int(r1), 0
} }
// Fork succeeded, now in child. // Fork succeeded, now in child.
// Chdir // Chdir
if dir != nil { if dir != nil {
r1, r2, err = RawSyscall(SYS_CHDIR, int64(uintptr(unsafe.Pointer(dir))), 0, 0); r1, r2, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0);
if err != 0 { if err1 != 0 {
goto childerror; goto childerror;
} }
} }
// Pass 1: look for fd[i] < i and move those up above len(fd) // 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. // so that pass 2 won't stomp on an fd it needs later.
nextfd = int64(len(fd)); nextfd = int(len(fd));
if pipe < nextfd { if pipe < nextfd {
r1, r2, err = RawSyscall(SYS_DUP2, pipe, nextfd, 0); r1, r2, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0);
if err != 0 { if err1 != 0 {
goto childerror; goto childerror;
} }
RawSyscall(SYS_FCNTL, nextfd, F_SETFD, FD_CLOEXEC); RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC);
pipe = nextfd; pipe = nextfd;
nextfd++; nextfd++;
} }
for i = 0; i < len(fd); i++ { for i = 0; i < len(fd); i++ {
if fd[i] >= 0 && fd[i] < int64(i) { if fd[i] >= 0 && fd[i] < int(i) {
r1, r2, err = RawSyscall(SYS_DUP2, fd[i], nextfd, 0); r1, r2, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0);
if err != 0 { if err1 != 0 {
goto childerror; goto childerror;
} }
RawSyscall(SYS_FCNTL, nextfd, F_SETFD, FD_CLOEXEC); RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC);
fd[i] = nextfd; fd[i] = nextfd;
nextfd++; nextfd++;
if nextfd == pipe { // don't stomp on pipe if nextfd == pipe { // don't stomp on pipe
...@@ -170,22 +170,22 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd [ ...@@ -170,22 +170,22 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd [
// Pass 2: dup fd[i] down onto i. // Pass 2: dup fd[i] down onto i.
for i = 0; i < len(fd); i++ { for i = 0; i < len(fd); i++ {
if fd[i] == -1 { if fd[i] == -1 {
RawSyscall(SYS_CLOSE, int64(i), 0, 0); RawSyscall(SYS_CLOSE, uintptr(i), 0, 0);
continue; continue;
} }
if fd[i] == int64(i) { if fd[i] == int(i) {
// dup2(i, i) won't clear close-on-exec flag on Linux, // dup2(i, i) won't clear close-on-exec flag on Linux,
// probably not elsewhere either. // probably not elsewhere either.
r1, r2, err = RawSyscall(SYS_FCNTL, fd[i], F_SETFD, 0); r1, r2, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0);
if err != 0 { if err1 != 0 {
goto childerror; goto childerror;
} }
continue; continue;
} }
// The new fd is created NOT close-on-exec, // The new fd is created NOT close-on-exec,
// which is exactly what we want. // which is exactly what we want.
r1, r2, err = RawSyscall(SYS_DUP2, fd[i], int64(i), 0); r1, r2, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0);
if err != 0 { if err1 != 0 {
goto childerror; goto childerror;
} }
} }
...@@ -195,18 +195,18 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd [ ...@@ -195,18 +195,18 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd [
// Programs that know they inherit fds >= 3 will need // Programs that know they inherit fds >= 3 will need
// to set them close-on-exec. // to set them close-on-exec.
for i = len(fd); i < 3; i++ { for i = len(fd); i < 3; i++ {
RawSyscall(SYS_CLOSE, int64(i), 0, 0); RawSyscall(SYS_CLOSE, uintptr(i), 0, 0);
} }
// Time to exec. // Time to exec.
r1, r2, err1 = RawSyscall(SYS_EXECVE, r1, r2, err1 = RawSyscall(SYS_EXECVE,
int64(uintptr(unsafe.Pointer(argv0))), uintptr(unsafe.Pointer(argv0)),
int64(uintptr(unsafe.Pointer(&argv[0]))), uintptr(unsafe.Pointer(&argv[0])),
int64(uintptr(unsafe.Pointer(&envv[0])))); uintptr(unsafe.Pointer(&envv[0])));
childerror: childerror:
// send error code on pipe // send error code on pipe
RawSyscall(SYS_WRITE, pipe, int64(uintptr(unsafe.Pointer(&err1))), 8); RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), uintptr(unsafe.Sizeof(err1)));
for { for {
RawSyscall(SYS_EXIT, 253, 0, 0); RawSyscall(SYS_EXIT, 253, 0, 0);
} }
...@@ -218,12 +218,13 @@ childerror: ...@@ -218,12 +218,13 @@ childerror:
} }
// Combination of fork and exec, careful to be thread safe. // Combination of fork and exec, careful to be thread safe.
func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int64) func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int)
(pid int64, err int64) (pid int, err int)
{ {
var p [2]int64; var p [2]int;
var r1 int64; var r1 int;
var n, err1 int64; var n int;
var err1 uintptr;
var wstatus WaitStatus; var wstatus WaitStatus;
p[0] = -1; p[0] = -1;
...@@ -244,13 +245,14 @@ func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int64 ...@@ -244,13 +245,14 @@ func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int64
ForkLock.Lock(); ForkLock.Lock();
// Allocate child status pipe close on exec. // Allocate child status pipe close on exec.
if r1, err = Pipe(&p); err != 0 { if err = Pipe(&p); err != 0 {
goto error; goto error;
} }
if r1, err = Fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 { var val int;
if val, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 {
goto error; goto error;
} }
if r1, err = Fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 { if val, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 {
goto error; goto error;
} }
...@@ -269,11 +271,11 @@ func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int64 ...@@ -269,11 +271,11 @@ func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int64
// Read child error status from pipe. // Read child error status from pipe.
Close(p[1]); Close(p[1]);
n, r1, err = Syscall(SYS_READ, p[0], int64(uintptr(unsafe.Pointer(&err1))), 8); n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), unsafe.Sizeof(err1));
Close(p[0]); Close(p[0]);
if err != 0 || n != 0 { if err != 0 || n != 0 {
if n == 8 { if n == unsafe.Sizeof(err1) {
err = err1; err = int(err1);
} }
if err == 0 { if err == 0 {
err = EPIPE; err = EPIPE;
...@@ -293,11 +295,11 @@ func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int64 ...@@ -293,11 +295,11 @@ func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int64
} }
// Ordinary exec. // Ordinary exec.
func Exec(argv0 string, argv []string, envv []string) (err int64) { func Exec(argv0 string, argv []string, envv []string) (err int) {
r1, r2, err1 := RawSyscall(SYS_EXECVE, r1, r2, err1 := RawSyscall(SYS_EXECVE,
int64(uintptr(unsafe.Pointer(StringBytePtr(argv0)))), uintptr(unsafe.Pointer(StringBytePtr(argv0))),
int64(uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0]))), uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])),
int64(uintptr(unsafe.Pointer(&StringArrayPtr(envv)[0])))); uintptr(unsafe.Pointer(&StringArrayPtr(envv)[0])));
return err1; return int(err1);
} }
#!/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.
# Generate Go code listing error values (ENAMETOOLONG etc)
# and signal values (SIGALRM etc). They're unrelated except
# that we use the same method for finding them.
errors=$(
echo '#include <errno.h>' |
# The gcc command line prints all the #defines
# it encounters while processing the input
gcc -x c - -E -dM |
egrep -h '#define E[A-Z0-9_]+ ' $files |
sed 's/#define //; s/ .*//'
)
signals=$(
echo '#include <sys/signal.h>' |
gcc -x c - -E -dM |
egrep -h '#define SIG[^_]' |
egrep -v '#define (SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))' |
sed 's/#define //; s/ .*//'
)
# Write godefs input.
(
echo '#include <errno.h>'
echo '#include <signal.h>'
echo 'enum {'
for i in $errors $signals
do
echo '$'"$i = $i,"
done
echo '};'
) >_errors.c
echo '// mkerrors' "$@"
echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
echo
godefs -gsyscall "$@" _errors.c
# Run C program to print error strings.
(
echo "
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
int errors[] = {
"
for i in $errors
do
echo ' '$i,
done
echo '
};
int
main(void)
{
int i, j, e;
char buf[1024];
printf("\n\n// Error table\n");
printf("var errors = [...]string {\n");
for(i=0; i<nelem(errors); i++) {
e = errors[i];
for(j=0; j<i; j++)
if(errors[j] == e) // duplicate value
goto next;
strcpy(buf, strerror(e));
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
buf[0] += a - A;
printf("\t%d: \"%s\",\n", e, buf);
next:;
}
printf("}\n\n");
}
'
) >_errors.c
gcc -o _errors _errors.c && ./_errors
rm -f _errors.c _errors
#!/usr/bin/perl
# 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.
# This program reads a file containing function prototypes
# (like syscall_darwin.go) and generates system call bodies.
# The prototypes are marked by lines beginning with "//sys"
# and read like func declarations if //sys is replaced by func, but:
# * The parameter lists must give a name for each argument.
# This includes return parameters.
# * The parameter lists must give a type for each argument:
# the (x, y, z int) shorthand is not allowed.
# * If the return parameter is an error number, it must be named errno.
$cmdline = "mksyscall " . join(' ', @ARGV);
$errors = 0;
$_32bit = 0;
if($ARGV[0] eq "-b32") {
$_32bit = "big-endian";
shift;
} elsif($ARGV[0] eq "-l32") {
$_32bit = "little-endian";
shift;
}
if($ARGV[0] =~ /^-/) {
print STDERR "usage: mksyscall [-b32 | -l32] [file ...]\n";
exit 1;
}
sub parseparamlist($) {
my ($list) = @_;
$list =~ s/^\s*//;
$list =~ s/\s*$//;
if($list eq "") {
return ();
}
return split(/\s*,\s*/, $list);
}
sub parseparam($) {
my ($p) = @_;
if($p !~ /^(\S*) (\S*)$/) {
print STDERR "$ARGV:$.: malformed parameter: $p\n";
$errors = 1;
return ("xx", "int");
}
return ($1, $2);
}
$text = "";
while(<>) {
chomp;
s/\s+/ /g;
s/^\s+//;
s/\s+$//;
next if !/^\/\/sys /;
# Line must be of the form
# func Open(path string, mode int, perm int) (fd int, errno int)
# Split into name, in params, out params.
if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(SYS_[A-Z0-9_]+))?$/) {
print STDERR "$ARGV:$.: malformed //sys declaration\n";
$errors = 1;
next;
}
my ($func, $in, $out, $sysname) = ($1, $2, $3, $4);
# Split argument lists on comma.
my @in = parseparamlist($in);
my @out = parseparamlist($out);
# Go function header.
$text .= sprintf "func %s(%s) (%s) {\n", $func, join(', ', @in), join(', ', @out);
# Prepare arguments to Syscall.
my @args = ();
my $n = 0;
foreach my $p (@in) {
my ($name, $type) = parseparam($p);
if($type =~ /^\*/) {
push @args, "uintptr(unsafe.Pointer($name))";
} elsif($type eq "string") {
push @args, "uintptr(unsafe.Pointer(StringBytePtr($name)))";
} elsif($type =~ /^\[\](.*)/) {
# Convert slice into pointer, length.
# Have to be careful not to take address of &a[0] if len == 0:
# pass nil in that case.
$text .= "\tvar _p$n *$1;\n";
$text .= "\tif len($name) > 0 { _p$n = \&${name}[0]; }\n";
push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))";
$n++;
} elsif($type eq "int64" && $_32bit ne "") {
if($_32bit eq "big-endian") {
push @args, "uintptr($name >> 32)", "uintptr($name)";
} else {
push @args, "uintptr($name)", "uintptr($name >> 32)";
}
} else {
push @args, "uintptr($name)";
}
}
# Determine which form to use; pad args with zeros.
my $asm = "Syscall";
if(@args <= 3) {
while(@args < 3) {
push @args, "0";
}
} elsif(@args <= 6) {
$asm = "Syscall6";
while(@args < 6) {
push @args, "0";
}
} else {
print STDERR "$ARGV:$.: too many arguments to system call\n";
}
# System call number.
if($sysname eq "") {
$sysname = "SYS_$func";
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
$sysname =~ y/a-z/A-Z/;
}
# Actual call.
my $args = join(', ', @args);
$text .= "\tr0, r1, e1 := $asm($sysname, $args);\n";
# Assign return values.
for(my $i=0; $i<@out; $i++) {
my $p = $out[$i];
my ($name, $type) = parseparam($p);
my $reg = "";
if($name eq "errno") {
$reg = "e1";
} else {
$reg = sprintf("r%d", $i);
}
if($type eq "bool") {
$reg = "$reg != 0";
}
$text .= "\t$name = $type($reg);\n";
}
$text .= "\treturn;\n";
$text .= "}\n\n";
}
if($errors) {
exit 1;
}
print <<EOF;
// $cmdline
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
import (
"syscall";
"unsafe";
)
$text
EOF
exit 0;
#!/usr/bin/perl
# 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.
#
# Generate system call table for Darwin from master list
# (for example, xnu-1228/bsd/kern/syscalls.master).
my $command = "mksysnum_darwin " . join(' ', @ARGV);
print <<EOF;
// $command
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package syscall
const (
EOF
while(<>){
if(/^([0-9]+)\s+ALL\s+({ \S+\s+(\w+).*})/){
my $num = $1;
my $proto = $2;
my $name = "SYS_$3";
$name =~ y/a-z/A-Z/;
# There are multiple entries for enosys and nosys, so comment them out.
if($name =~ /^SYS_E?NOSYS$/){
$name = "// $name";
}
print " $name = $num; // $proto\n";
}
}
print <<EOF;
)
EOF
...@@ -11,22 +11,27 @@ ...@@ -11,22 +11,27 @@
// the manuals for the appropriate operating system. // the manuals for the appropriate operating system.
package syscall package syscall
/* import (
* Foundation of system call interface. "syscall";
*/ "unsafe";
)
func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64); func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64); func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func RawSyscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64); func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
/* // StringByteSlice returns a NUL-terminated slice of bytes
* Used to convert file names to byte arrays for passing to kernel, // containing the text of s.
* but useful elsewhere too. func StringByteSlice(s string) []byte {
*/
func StringBytePtr(s string) *byte {
a := make([]byte, len(s)+1); a := make([]byte, len(s)+1);
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
a[i] = s[i]; a[i] = s[i];
} }
return &a[0]; return a;
}
// StringBytePtr returns a pointer to a NUL-terminated array of bytes
// containing the text of s.
func StringBytePtr(s string) *byte {
return &StringByteSlice(s)[0];
} }
This diff is collapsed.
// 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
import "syscall"
func TimespecToNsec(ts Timespec) int64 {
return int64(ts.Sec)*1e9 + int64(ts.Nsec);
}
func NsecToTimespec(nsec int64) (ts Timespec) {
ts.Sec = nsec / 1e9;
ts.Nsec = nsec % 1e9;
return;
}
func TimevalToNsec(tv Timeval) int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3;
}
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999; // round up to microsecond
tv.Usec = int32(nsec%1e9 / 1e3);
tv.Sec = int64(nsec/1e9);
return;
}
This diff is collapsed.
// 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
import "syscall"
func TimespecToNsec(ts Timespec) int64 {
return int64(ts.Sec)*1e9 + int64(ts.Nsec);
}
func NsecToTimespec(nsec int64) (ts Timespec) {
ts.Sec = nsec / 1e9;
ts.Nsec = nsec % 1e9;
return;
}
func TimevalToNsec(tv Timeval) int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3;
}
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999; // round up to microsecond
tv.Sec = nsec/1e9;
tv.Usec = nsec%1e9 / 1e3;
return;
}
// 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 PORT.
*/
#define __DARWIN_UNIX03 0
#define KERNEL
#define _DARWIN_USE_64_BIT_INODE
#include <dirent.h>
#include <fcntl.h>
#include <mach/mach.h>
#include <mach/message.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <stdio.h>
#include <sys/event.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/select.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
// Machine characteristics; for internal use.
enum
{
$sizeofPtr = sizeof(void*),
$sizeofShort = sizeof(short),
$sizeofInt = sizeof(int),
$sizeofLong = sizeof(long),
$sizeofLongLong = sizeof(long long),
};
// Time
typedef struct timespec $Timespec;
typedef struct timeval $Timeval;
// Processes
typedef struct rusage $Rusage;
typedef struct rlimit $Rlimit;
typedef int $_C_int;
typedef gid_t $_Gid_t;
// Files
enum
{
$O_RDONLY = O_RDONLY,
$O_WRONLY = O_WRONLY,
$O_RDWR = O_RDWR,
$O_APPEND = O_APPEND,
$O_ASYNC = O_ASYNC,
$O_CREAT = O_CREAT,
$O_NOCTTY = O_NOCTTY,
$O_NONBLOCK = O_NONBLOCK,
$O_SYNC = O_SYNC,
$O_TRUNC = O_TRUNC,
$O_CLOEXEC = 0, // not supported
$F_GETFD = F_GETFD,
$F_SETFD = F_SETFD,
$F_GETFL = F_GETFL,
$F_SETFL = F_SETFL,
$FD_CLOEXEC = FD_CLOEXEC,
$NAME_MAX = NAME_MAX
};
enum
{ // Directory mode bits
$S_IFMT = S_IFMT,
$S_IFIFO = S_IFIFO,
$S_IFCHR = S_IFCHR,
$S_IFDIR = S_IFDIR,
$S_IFBLK = S_IFBLK,
$S_IFREG = S_IFREG,
$S_IFLNK = S_IFLNK,
$S_IFSOCK = S_IFSOCK,
$S_IFWHT = S_IFWHT,
$S_ISUID = S_ISUID,
$S_ISGID = S_ISGID,
$S_ISVTX = S_ISVTX,
$S_IRUSR = S_IRUSR,
$S_IWUSR = S_IWUSR,
$S_IXUSR = S_IXUSR,
};
typedef struct stat64 $Stat_t;
typedef struct statfs64 $Statfs_t;
typedef struct dirent $Dirent;
// Wait status.
enum
{
$WNOHANG = WNOHANG,
$WUNTRACED = WUNTRACED,
$WEXITED = WEXITED,
$WSTOPPED = WSTOPPED,
$WCONTINUED = WCONTINUED,
$WNOWAIT = WNOWAIT,
};
// Sockets
enum
{
$AF_UNIX = AF_UNIX,
$AF_INET = AF_INET,
$AF_DATAKIT = AF_DATAKIT,
$AF_INET6 = AF_INET6,
$SOCK_STREAM = SOCK_STREAM,
$SOCK_DGRAM = SOCK_DGRAM,
$SOCK_RAW = SOCK_RAW,
$SOCK_SEQPACKET = SOCK_SEQPACKET,
$SOL_SOCKET = SOL_SOCKET,
$SO_REUSEADDR = SO_REUSEADDR,
$SO_KEEPALIVE = SO_KEEPALIVE,
$SO_DONTROUTE = SO_DONTROUTE,
$SO_BROADCAST = SO_BROADCAST,
$SO_USELOOPBACK = SO_USELOOPBACK,
$SO_LINGER = SO_LINGER,
$SO_REUSEPORT = SO_REUSEPORT,
$SO_SNDBUF = SO_SNDBUF,
$SO_RCVBUF = SO_RCVBUF,
$SO_SNDTIMEO = SO_SNDTIMEO,
$SO_RCVTIMEO = SO_RCVTIMEO,
$SO_NOSIGPIPE = SO_NOSIGPIPE,
$IPPROTO_TCP = IPPROTO_TCP,
$IPPROTO_UDP = IPPROTO_UDP,
$TCP_NODELAY = TCP_NODELAY,
$SOMAXCONN = SOMAXCONN
};
typedef struct sockaddr_in $RawSockaddrInet4;
typedef struct sockaddr_in6 $RawSockaddrInet6;
typedef struct sockaddr_un $RawSockaddrUnix;
typedef struct sockaddr $RawSockaddr;
union sockaddr_all {
struct sockaddr s1; // this one gets used for fields
struct sockaddr_in s2; // these pad it out
struct sockaddr_in6 s3;
};
struct sockaddr_any {
struct sockaddr addr;
char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
};
enum {
$SizeofSockaddrInet4 = sizeof(struct sockaddr_in),
$SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
$SizeofSockaddrAny = sizeof(struct sockaddr_any),
$SizeofSockaddrUnix = sizeof(struct sockaddr_un),
};
typedef struct sockaddr_any $RawSockaddrAny;
typedef socklen_t $_Socklen;
typedef struct linger $Linger;
// Events (kqueue, kevent)
enum {
// filters
$EVFILT_READ = EVFILT_READ,
$EVFILT_WRITE = EVFILT_WRITE,
$EVFILT_AIO = EVFILT_AIO,
$EVFILT_VNODE = EVFILT_VNODE,
$EVFILT_PROC = EVFILT_PROC,
$EVFILT_SIGNAL = EVFILT_SIGNAL,
$EVFILT_TIMER = EVFILT_TIMER,
$EVFILT_MACHPORT = EVFILT_MACHPORT,
$EVFILT_FS = EVFILT_FS,
$EVFILT_SYSCOUNT = EVFILT_SYSCOUNT,
// actions
$EV_ADD = EV_ADD,
$EV_DELETE = EV_DELETE,
$EV_DISABLE = EV_DISABLE,
$EV_RECEIPT = EV_RECEIPT,
// flags
$EV_ONESHOT = EV_ONESHOT,
$EV_CLEAR = EV_CLEAR,
$EV_SYSFLAGS = EV_SYSFLAGS,
$EV_FLAG0 = EV_FLAG0,
$EV_FLAG1 = EV_FLAG1,
// returned values
$EV_EOF = EV_EOF,
$EV_ERROR = EV_ERROR,
};
typedef struct kevent $Kevent_t;
// Select
typedef fd_set $FdSet;
// 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.
// Nothing to see here.
// 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 PORT.
*/
#define __DARWIN_UNIX03 0
#define KERNEL
#include <dirent.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <stdio.h>
#include <sys/epoll.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/select.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/timex.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <ustat.h>
#include <utime.h>
// Machine characteristics; for internal use.
enum
{
$sizeofPtr = sizeof(void*),
$sizeofShort = sizeof(short),
$sizeofInt = sizeof(int),
$sizeofLong = sizeof(long),
$sizeofLongLong = sizeof(long long),
$PathMax = PATH_MAX,
};
// Time
typedef struct timespec $Timespec;
typedef struct timeval $Timeval;
typedef struct timex $Timex;
typedef time_t $Time_t;
typedef struct tms $Tms;
typedef struct utimbuf $Utimbuf;
// Processes
typedef struct rusage $Rusage;
typedef struct rlimit $Rlimit;
typedef int $_C_int;
typedef gid_t $_Gid_t;
// Files
enum
{
$O_RDONLY = O_RDONLY,
$O_WRONLY = O_WRONLY,
$O_RDWR = O_RDWR,
$O_APPEND = O_APPEND,
$O_ASYNC = O_ASYNC,
$O_CREAT = O_CREAT,
$O_NOCTTY = O_NOCTTY,
$O_NONBLOCK = O_NONBLOCK,
$O_SYNC = O_SYNC,
$O_TRUNC = O_TRUNC,
$O_CLOEXEC = 0, // not supported
$F_GETFD = F_GETFD,
$F_SETFD = F_SETFD,
$F_GETFL = F_GETFL,
$F_SETFL = F_SETFL,
$FD_CLOEXEC = FD_CLOEXEC,
$NAME_MAX = NAME_MAX
};
enum
{ // Directory mode bits
$S_IFMT = S_IFMT,
$S_IFIFO = S_IFIFO,
$S_IFCHR = S_IFCHR,
$S_IFDIR = S_IFDIR,
$S_IFBLK = S_IFBLK,
$S_IFREG = S_IFREG,
$S_IFLNK = S_IFLNK,
$S_IFSOCK = S_IFSOCK,
$S_ISUID = S_ISUID,
$S_ISGID = S_ISGID,
$S_ISVTX = S_ISVTX,
$S_IRUSR = S_IRUSR,
$S_IWUSR = S_IWUSR,
$S_IXUSR = S_IXUSR,
};
typedef struct stat $Stat_t;
typedef struct statfs $Statfs_t;
typedef struct dirent $Dirent;
// Wait status.
enum
{
$WNOHANG = WNOHANG,
$WUNTRACED = WUNTRACED,
$WEXITED = WEXITED,
$WSTOPPED = WSTOPPED,
$WCONTINUED = WCONTINUED,
$WNOWAIT = WNOWAIT,
};
// Sockets
enum
{
$AF_UNIX = AF_UNIX,
$AF_INET = AF_INET,
$AF_INET6 = AF_INET6,
$SOCK_STREAM = SOCK_STREAM,
$SOCK_DGRAM = SOCK_DGRAM,
$SOCK_RAW = SOCK_RAW,
$SOCK_SEQPACKET = SOCK_SEQPACKET,
$SOL_SOCKET = SOL_SOCKET,
$SO_REUSEADDR = SO_REUSEADDR,
$SO_KEEPALIVE = SO_KEEPALIVE,
$SO_DONTROUTE = SO_DONTROUTE,
$SO_BROADCAST = SO_BROADCAST,
$SO_LINGER = SO_LINGER,
$SO_SNDBUF = SO_SNDBUF,
$SO_RCVBUF = SO_RCVBUF,
$SO_SNDTIMEO = SO_SNDTIMEO,
$SO_RCVTIMEO = SO_RCVTIMEO,
$IPPROTO_TCP = IPPROTO_TCP,
$IPPROTO_UDP = IPPROTO_UDP,
$TCP_NODELAY = TCP_NODELAY,
$SOMAXCONN = SOMAXCONN
};
typedef struct sockaddr_in $RawSockaddrInet4;
typedef struct sockaddr_in6 $RawSockaddrInet6;
typedef struct sockaddr_un $RawSockaddrUnix;
typedef struct sockaddr $RawSockaddr;
union sockaddr_all {
struct sockaddr s1; // this one gets used for fields
struct sockaddr_in s2; // these pad it out
struct sockaddr_in6 s3;
};
struct sockaddr_any {
struct sockaddr addr;
char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
};
enum {
$SizeofSockaddrInet4 = sizeof(struct sockaddr_in),
$SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
$SizeofSockaddrAny = sizeof(struct sockaddr_any),
$SizeofSockaddrUnix = sizeof(struct sockaddr_un),
};
typedef struct sockaddr_any $RawSockaddrAny;
typedef socklen_t $_Socklen;
typedef struct linger $Linger;
// Misc
enum {
$EPOLLIN = EPOLLIN,
$EPOLLRDHUP = EPOLLRDHUP,
$EPOLLOUT = EPOLLOUT,
$EPOLLONESHOT = EPOLLONESHOT,
$EPOLL_CTL_MOD = EPOLL_CTL_MOD,
$EPOLL_CTL_ADD = EPOLL_CTL_ADD,
$EPOLL_CTL_DEL = EPOLL_CTL_DEL,
};
typedef fd_set $FdSet;
typedef struct sysinfo $Sysinfo_t;
typedef struct utsname $Utsname;
typedef struct ustat $Ustat_t;
// The real epoll_event is a union, and godefs doesn't handle it well.
struct my_epoll_event {
uint32_t events;
int32_t fd;
int32_t pad;
};
typedef struct my_epoll_event $EpollEvent;
// 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.
// Nothing to see here
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment