platform: adds notes about darwin and CGO (#1212)

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2023-03-08 09:47:10 +08:00
committed by GitHub
parent b16f74a86b
commit 89f918105a
4 changed files with 59 additions and 10 deletions

View File

@@ -25,6 +25,26 @@ At some point, we may allow extensions to supply their own platform-specific
hooks. Until then, one end user impact/tradeoff is some glitches trying
untested platforms (with the Compiler runtime).
### Why do we use CGO to implement system calls on darwin?
wazero is dependency and CGO free by design. In some cases, we have code that
can optionally use CGO, but retain a fallback for when that's disabled. The only
operating system (`GOOS`) we use CGO by default in is `darwin`.
Unlike other operating systems, regardless of `CGO_ENABLED`, Go always uses
"CGO" mechanisms in the runtime layer of `darwin`. This is explained in
[Statically linked binaries on Mac OS X](https://developer.apple.com/library/archive/qa/qa1118/_index.html#//apple_ref/doc/uid/DTS10001666):
> Apple does not support statically linked binaries on Mac OS X. A statically
> linked binary assumes binary compatibility at the kernel system call
> interface, and we do not make any guarantees on that front. Rather, we strive
> to ensure binary compatibility in each dynamically linked system library and
> framework.
This plays to our advantage for system calls that aren't yet exposed in the Go
standard library, notably `futimens` for nanosecond-precision timestamp
manipulation.
### Why not x/sys
Going beyond Go's SDK limitations can be accomplished with their [x/sys library](https://pkg.go.dev/golang.org/x/sys/unix).

View File

@@ -2,6 +2,7 @@ package platform
import (
"os"
"path"
"testing"
)
@@ -10,3 +11,19 @@ func Benchmark_IsTerminal(b *testing.B) {
IsTerminal(os.Stdout.Fd())
}
}
func Benchmark_UtimesNano(b *testing.B) {
tmpDir := b.TempDir()
f, err := os.Create(path.Join(tmpDir, "file"))
if err != nil {
b.Fatal(err)
}
defer f.Close()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := UtimesNanoFile(f, 1, 1); err != nil {
b.Fatal(err)
}
}
}

View File

@@ -19,16 +19,21 @@ func futimens(fd uintptr, atimeNsec, mtimeNsec int64) error {
return nil
}
// libc_futimens_trampoline_addr is the address of the libc_futimens_trampoline symbol, defined in utimes_darwin.s
// we use this value to invoke the syscall through syscall_syscall6 imported below
// libc_futimens_trampoline_addr is the address of the
// `libc_futimens_trampoline` symbol, defined in `utimes_darwin.s`.
//
// We use this to invoke the syscall through syscall_syscall6 imported below.
var libc_futimens_trampoline_addr uintptr
// Imports the futimens symbol from libc as libc_futimens
// Imports the futimens symbol from libc as `libc_futimens`.
//
// Note: CGO mechanisms are used in darwin regardless of the CGO_ENABLED value
// or the "cgo" build flag. See /RATIONALE.md for why.
//go:cgo_import_dynamic libc_futimens futimens "/usr/lib/libSystem.B.dylib"
// syscall_syscall6 is a private symbol that we link below. We need to use this instead of syscall.Syscall6
// because the public syscall.Syscall6 won't work when fn is an address
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
// Import syscall.syscall6 as syscall_syscall6.
// syscall_syscall6 is a private symbol that we link below. We need to use this
// instead of syscall.Syscall6 because the public syscall.Syscall6 won't work
// when fn is an address.
//
//go:linkname syscall_syscall6 syscall.syscall6
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)

View File

@@ -73,8 +73,15 @@ func TestUtimesNano(t *testing.T) {
}
func TestUtimesNanoFile(t *testing.T) {
if !IsGo120 {
t.Skip("TODO: implement futimens on darwin, freebsd, linux w/o CGO")
switch runtime.GOOS {
case "linux", "darwin": // supported
case "freebsd": // TODO: support freebsd w/o CGO
case "windows":
if !IsGo120 {
t.Skip("windows only works after Go 1.20") // TODO: possibly 1.19 ;)
}
default: // expect ENOSYS and callers need to fall back to UtimesNano
t.Skip("unsupported GOOS", runtime.GOOS)
}
tmpDir := t.TempDir()