Skip to content

Commit

Permalink
syscall: implement syscalls on Darwin using libSystem
Browse files Browse the repository at this point in the history
There are still some references to the bare Syscall functions
in the stdlib. I will root those out in a following CL.
(This CL is big enough as it is.)
Most are in vendor directories:

cmd/vendor/golang.org/x/sys/unix/
vendor/golang_org/x/net/route/syscall.go
syscall/bpf_bsd.go
syscall/exec_unix.go
syscall/flock.go

Update #17490

Change-Id: I69ab707811530c26b652b291cadee92f5bf5c1a4
Reviewed-on: https://go-review.googlesource.com/c/141639
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Elias Naur <elias.naur@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
  • Loading branch information
randall77 committed Nov 7, 2018
1 parent 0fcd405 commit a3b0144
Show file tree
Hide file tree
Showing 42 changed files with 4,996 additions and 689 deletions.
4 changes: 3 additions & 1 deletion src/cmd/internal/obj/x86/asm6.go
Original file line number Diff line number Diff line change
Expand Up @@ -4704,7 +4704,9 @@ func (ab *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
r = obj.Addrel(cursym)
r.Off = int32(p.Pc + int64(ab.Len()))
r.Sym = p.To.Sym
r.Type = objabi.R_PCREL
// Note: R_CALL instead of R_PCREL. R_CALL is more permissive in that
// it can point to a trampoline instead of the destination itself.
r.Type = objabi.R_CALL
r.Siz = 4
ab.PutInt32(0)
break
Expand Down
16 changes: 10 additions & 6 deletions src/internal/poll/fd_fsync_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

package poll

import "syscall"
import (
"syscall"
_ "unsafe" // for go:linkname
)

// Fsync invokes SYS_FCNTL with SYS_FULLFSYNC because
// on OS X, SYS_FSYNC doesn't fully flush contents to disk.
Expand All @@ -15,9 +18,10 @@ func (fd *FD) Fsync() error {
}
defer fd.decref()

_, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd.Sysfd), syscall.F_FULLFSYNC, 0)
if e1 != 0 {
return e1
}
return nil
_, e1 := fcntl(fd.Sysfd, syscall.F_FULLFSYNC, 0)
return e1
}

// Implemented in syscall/syscall_darwin.go.
//go:linkname fcntl syscall.fcntl
func fcntl(fd int, cmd int, arg int) (int, error)
10 changes: 9 additions & 1 deletion src/internal/poll/fd_fsync_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build aix dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
// +build aix dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris

package poll

Expand All @@ -16,3 +16,11 @@ func (fd *FD) Fsync() error {
defer fd.decref()
return syscall.Fsync(fd.Sysfd)
}

func fcntl(fd int, cmd int, arg int) (int, error) {
r, _, e := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
if e != 0 {
return int(r), syscall.Errno(e)
}
return int(r), nil
}
16 changes: 16 additions & 0 deletions src/internal/poll/fd_fsync_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018 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 poll

import "syscall"

// Fsync wraps syscall.Fsync.
func (fd *FD) Fsync() error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Fsync(fd.Sysfd)
}
9 changes: 5 additions & 4 deletions src/internal/poll/fd_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,11 @@ var tryDupCloexec = int32(1)
// DupCloseOnExec dups fd and marks it close-on-exec.
func DupCloseOnExec(fd int) (int, string, error) {
if atomic.LoadInt32(&tryDupCloexec) == 1 {
r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
switch e1 {
case 0:
return int(r0), "", nil
r0, e1 := fcntl(fd, syscall.F_DUPFD_CLOEXEC, 0)
if e1 == nil {
return r0, "", nil
}
switch e1.(syscall.Errno) {
case syscall.EINVAL, syscall.ENOSYS:
// Old kernel, or js/wasm (which returns
// ENOSYS). Fall back to the portable way from
Expand Down
16 changes: 16 additions & 0 deletions src/internal/poll/fd_writev_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018 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.

// +build darwin

package poll

import (
"syscall"
_ "unsafe" // for go:linkname
)

// Implemented in syscall/syscall_darwin.go.
//go:linkname writev syscall.writev
func writev(fd int, iovecs []syscall.Iovec) (uintptr, error)
20 changes: 20 additions & 0 deletions src/internal/poll/fd_writev_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2018 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.

// +build dragonfly freebsd linux netbsd openbsd

package poll

import (
"syscall"
"unsafe"
)

func writev(fd int, iovecs []syscall.Iovec) (uintptr, error) {
r, _, e := syscall.Syscall(syscall.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs)))
if e != 0 {
return r, syscall.Errno(e)
}
return r, nil
}
19 changes: 7 additions & 12 deletions src/internal/poll/writev.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ package poll
import (
"io"
"syscall"
"unsafe"
)

// Writev wraps the writev system call.
Expand Down Expand Up @@ -54,24 +53,20 @@ func (fd *FD) Writev(v *[][]byte) (int64, error) {
}
fd.iovecs = &iovecs // cache

wrote, _, e0 := syscall.Syscall(syscall.SYS_WRITEV,
uintptr(fd.Sysfd),
uintptr(unsafe.Pointer(&iovecs[0])),
uintptr(len(iovecs)))
var wrote uintptr
wrote, err = writev(fd.Sysfd, iovecs)
if wrote == ^uintptr(0) {
wrote = 0
}
TestHookDidWritev(int(wrote))
n += int64(wrote)
consume(v, int64(wrote))
if e0 == syscall.EAGAIN {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
}
} else if e0 != 0 {
err = syscall.Errno(e0)
}
if err != nil {
if err.(syscall.Errno) == syscall.EAGAIN {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
}
}
break
}
if n == 0 {
Expand Down
5 changes: 5 additions & 0 deletions src/internal/syscall/unix/empty.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright 2018 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 exists solely so we can linkname in symbols from syscall.
2 changes: 1 addition & 1 deletion src/internal/syscall/unix/nonblocking.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
// +build aix dragonfly freebsd linux netbsd openbsd solaris

package unix

Expand Down
24 changes: 24 additions & 0 deletions src/internal/syscall/unix/nonblocking_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2018 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.

// +build darwin

package unix

import (
"syscall"
_ "unsafe" // for go:linkname
)

func IsNonblock(fd int) (nonblocking bool, err error) {
flag, e1 := fcntl(fd, syscall.F_GETFL, 0)
if e1 != nil {
return false, e1
}
return flag&syscall.O_NONBLOCK != 0, nil
}

// Implemented in syscall/syscall_darwin.go.
//go:linkname fcntl syscall.fcntl
func fcntl(fd int, cmd int, arg int) (int, error)
55 changes: 55 additions & 0 deletions src/runtime/sys_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,61 @@ func libcCall(fn, arg unsafe.Pointer) int32 {
return res
}

// The X versions of syscall expect the libc call to return a 64-bit result.
// Otherwise (the non-X version) expects a 32-bit result.
// This distinction is required because an error is indicated by returning -1,
// and we need to know whether to check 32 or 64 bits of the result.
// (Some libc functions that return 32 bits put junk in the upper 32 bits of AX.)

//go:linkname syscall_syscall syscall.syscall
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
entersyscallblock()
libcCall(unsafe.Pointer(funcPC(syscall)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscall()

//go:linkname syscall_syscall6 syscall.syscall6
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
entersyscallblock()
libcCall(unsafe.Pointer(funcPC(syscall6)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscall6()

//go:linkname syscall_syscall6X syscall.syscall6X
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
entersyscallblock()
libcCall(unsafe.Pointer(funcPC(syscall6X)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscall6X()

//go:linkname syscall_rawSyscall syscall.rawSyscall
//go:nosplit
//go:cgo_unsafe_args
func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
libcCall(unsafe.Pointer(funcPC(syscall)), unsafe.Pointer(&fn))
return
}

//go:linkname syscall_rawSyscall6 syscall.rawSyscall6
//go:nosplit
//go:cgo_unsafe_args
func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
libcCall(unsafe.Pointer(funcPC(syscall6)), unsafe.Pointer(&fn))
return
}

// The *_trampoline functions convert from the Go calling convention to the C calling convention
// and then call the underlying libc function. They are defined in sys_darwin_$ARCH.s.

Expand Down
21 changes: 21 additions & 0 deletions src/runtime/sys_darwin_32.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2018 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.

// +build darwin
// +build 386 arm

package runtime

import "unsafe"

//go:linkname syscall_syscall9 syscall.syscall9
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
entersyscallblock()
libcCall(unsafe.Pointer(funcPC(syscall9)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscall9()
Loading

0 comments on commit a3b0144

Please sign in to comment.