-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
This is to document a design decision within a series of commits I will be submitting for review, but I want to lay out the rationale behind the approach for posterity. See golang/sys#102 / https://golang.org/cl/302310 for additional context.
Summary: In order to link to libc function calls more than once in syscall_{solaris,illumos} we need to prevent duplication in the resulting cgo import directives, linkname directives, and variable declarations.
Details:
unix/sycall_solaris.go already contains the following line:
//sys ioctl(fd int, req uint, arg uintptr) (err error)so the ioctl wrapper for the libc ioctl function is currently written to only return an error, however the C function signature is (from the man page) is:
int ioctl(int fildes, int request, /* arg */ ...);I am working on WireGuard/wireguard-go#39 and have the need to perform some ioctls where the return value is needed.
If I attempt to add the following line to the file:
//sys ioctlRet(fd int, req uint, arg uintptr) (ret int, err error) = libc.ioctlAnd then rerun the regeneration command for unix/zsyscall_solaris_amd64.go I end up with, among other bits of the diff, these hunks (using -U1 to be concise):
diff --git a/unix/zsyscall_solaris_amd64.go b/unix/zsyscall_solaris_amd64.go
index 7099f55..0d7beab 100644
--- a/unix/zsyscall_solaris_amd64.go
+++ b/unix/zsyscall_solaris_amd64.go
@@ -33,2 +33,3 @@ import (
//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
+//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
//go:cgo_import_dynamic libc_poll poll "libc.so"
@@ -164,2 +165,3 @@ import (
//go:linkname procioctl libc_ioctl
+//go:linkname procioctl libc_ioctl
//go:linkname procpoll libc_poll
@@ -296,2 +298,3 @@ var (
procioctl,
+ procioctl,
procpoll,Note the doubling. The compiler certainly does:
$ go build
# golang.org/x/sys/unix
./zsyscall_solaris_amd64.go:299:2: procioctl redeclared in this block
previous declaration at ./zsyscall_solaris_amd64.go:279:2
If we accept that wanting to create this second wrapper for ioctl is reasonable, then we need mksyscall_solaris.go to keep track and not create duplication. Originally I wrote a version that does a very naive tracking of the previously seen values so that consecutive lines could be processed correctly, but a reviewer suggested that using maps would make it safe to do this anywhere in the file.
Possible alternatives:
Replace
//sys ioctl(fd int, req uint, arg uintptr) (err error)with e.g.
//sys ioctl_ret(fd int, req uint, arg uintptr) (ret int, err error) = libc.ioctl
func ioctl(fd int, req uint, arg uintptr) error {
_, err := ioctl_ret(fd, req, arg)
return err
}This on its face is nice and simple, but it means that all existing codepaths dependent on ioctl suddenly have an extra function call through ioctl_ret (or whatever we name it, this is verbatim from an older attempt). This seems like not a nice thing to do to existing code.
Another alternative would be to hardcode the generated code for ioctlRet into unix/syscall_illumos.go alongside its consumers. Probably fine, but feels inelegant.
One final note:
None of this solves the problem that moving
//sys ioctlRet(fd int, req uint, arg uintptr) (ret int, err error) = libc.ioctlinto unix/syscall_illumos.go will cause a similar redeclaration problem because the code generating unix/zsyscall_illumos.go has no insight into the content of unix/{,z}syscall_solaris.go
Thank you, dear reader, for joining me down here in this sadness.