diff --git a/unix/syscall_solaris.go b/unix/syscall_solaris.go index 77fcde7c1..4e54748e1 100644 --- a/unix/syscall_solaris.go +++ b/unix/syscall_solaris.go @@ -13,6 +13,8 @@ package unix import ( + "fmt" + "os" "runtime" "syscall" "unsafe" @@ -744,3 +746,85 @@ func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, e func Munmap(b []byte) (err error) { return mapper.Munmap(b) } + +// Event Ports + +/* +When using the port_associate wrappers it may be tempting to pass entire structs +into the user cookie. Experimentally, sometimes what you place there will be +garbage collected so it is not recommended. +*/ + +//sys port_create() (n int, err error) +//sys port_associate(port int, source int, object uintptr, events int, user *byte) (n int, err error) +//sys port_dissociate(port int, source int, object uintptr) (n int, err error) +//sys port_get(port int, pe *PortEvent, timeout *Timespec) (n int, err error) + +func PortCreate() (int, error) { + return port_create() +} + +func PortAssociateFileObj(port int, f *FileObj, events int, user *byte) (int, error) { + return port_associate(port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(f)), events, user) +} + +func PortDissociateFileObj(port int, f *FileObj) (int, error) { + return port_dissociate(port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(f))) +} + +func CreateFileObj(name string, stat os.FileInfo) (*FileObj, error) { + fobj := new(FileObj) + bs, err := ByteSliceFromString(name) + if err != nil { + return nil, err + } + fobj.Name = (*int8)(unsafe.Pointer(&bs[0])) + fobj.Atim.Sec = stat.Sys().(*syscall.Stat_t).Atim.Sec + fobj.Atim.Nsec = stat.Sys().(*syscall.Stat_t).Atim.Nsec + fobj.Mtim.Sec = stat.Sys().(*syscall.Stat_t).Mtim.Sec + fobj.Mtim.Nsec = stat.Sys().(*syscall.Stat_t).Mtim.Nsec + fobj.Ctim.Sec = stat.Sys().(*syscall.Stat_t).Ctim.Sec + fobj.Ctim.Nsec = stat.Sys().(*syscall.Stat_t).Ctim.Nsec + return fobj, nil +} + +func (f *FileObj) GetName() string { + return BytePtrToString((*byte)(unsafe.Pointer(f.Name))) +} + +func PortGet(port int, pe *PortEvent, t *Timespec) (n int, err error) { + return port_get(port, pe, t) +} + +func (pe *PortEvent) GetFileObj() (f *FileObj, err error) { + if pe.Source != PORT_SOURCE_FILE { + return nil, fmt.Errorf("Event source must be PORT_SOURCE_FILE for there to be a FileObj") + } + return (*FileObj)(unsafe.Pointer(uintptr(pe.Object))), nil +} + +func (pe *PortEvent) GetUser() *byte { + return (*byte)(unsafe.Pointer(pe.User)) +} + +/* +// While I found example code for fsnotify that used the functions above, +// I have not found any go/cgo code using event port and file descriptors +// so I have no test hardness for these functions + +func PortAssociateFd(port int, fd int, events int, user *byte) (n int, err error) { + return port_associate(port, PORT_SOURCE_FD, (uintptr)(fd), events, user) +} + +func PortDissociateFd(port int, fd int) (n int, err error) { + return port_dissociate(port, PORT_SOURCE_FD, (uintptr)(fd)) +} + +func (pe *PortEvent) GetFd() (fd int, err error) { + if pe.Source != PORT_SOURCE_FD { + return -1, fmt.Errorf("Event source must be PORT_SOURCE_FD for there to be a File Descriptor") + } + return (int)(uintptr(pe.Object)), nil +} + +*/ diff --git a/unix/syscall_solaris_test.go b/unix/syscall_solaris_test.go index 910bdf1c3..855dc44d0 100644 --- a/unix/syscall_solaris_test.go +++ b/unix/syscall_solaris_test.go @@ -8,8 +8,11 @@ package unix_test import ( + "os" "os/exec" + "runtime" "testing" + "unsafe" "golang.org/x/sys/unix" ) @@ -41,3 +44,44 @@ func TestSysconf(t *testing.T) { } t.Logf("Sysconf(SC_CLK_TCK) = %d", n) } + +// Event Ports + +func TestCreateFileObj(t *testing.T) { + _, path, _, _ := runtime.Caller(0) + stat, err := os.Stat(path) + if err != nil { + t.Errorf("Failed to stat %s: %v", path, err) + } + fobj, err := unix.CreateFileObj(path, stat) + name := fobj.GetName() + if path != name { + t.Errorf(`Can't get name back out: "%s" "%s"`, path, name) + } +} + +func TestBasicEventPort(t *testing.T) { + _, path, _, _ := runtime.Caller(0) + stat, err := os.Stat(path) + fmode := stat.Mode() + if err != nil { + t.Errorf("Failed to stat %s: %v", path, err) + } + port, err := unix.PortCreate() + if err != nil { + t.Errorf("PortCreate failed: %d - %v", port, err) + } + defer unix.Close(port) + fobj, err := unix.CreateFileObj(path, stat) + if err != nil { + t.Errorf("CreateFileObj failed: %v", err) + } + _, err = unix.PortAssociateFileObj(port, fobj, unix.FILE_MODIFIED, (*byte)(unsafe.Pointer(&fmode))) + if err != nil { + t.Errorf("PortAssociateFileObj failed: %v", err) + } + _, err = unix.PortDissociateFileObj(port, fobj) + if err != nil { + t.Errorf("PortDissociateFileObj failed: %v", err) + } +} diff --git a/unix/zsyscall_solaris_amd64.go b/unix/zsyscall_solaris_amd64.go index 4e18d5c99..627ef81a8 100644 --- a/unix/zsyscall_solaris_amd64.go +++ b/unix/zsyscall_solaris_amd64.go @@ -141,6 +141,10 @@ import ( //go:cgo_import_dynamic libc_getpeername getpeername "libsocket.so" //go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so" //go:cgo_import_dynamic libc_recvfrom recvfrom "libsocket.so" +//go:cgo_import_dynamic libc_port_create port_create "libc.so" +//go:cgo_import_dynamic libc_port_associate port_associate "libc.so" +//go:cgo_import_dynamic libc_port_dissociate port_dissociate "libc.so" +//go:cgo_import_dynamic libc_port_get port_get "libc.so" //go:linkname procpipe libc_pipe //go:linkname procpipe2 libc_pipe2 @@ -272,6 +276,10 @@ import ( //go:linkname procgetpeername libc_getpeername //go:linkname procsetsockopt libc_setsockopt //go:linkname procrecvfrom libc_recvfrom +//go:linkname procport_create libc_port_create +//go:linkname procport_associate libc_port_associate +//go:linkname procport_dissociate libc_port_dissociate +//go:linkname procport_get libc_port_get var ( procpipe, @@ -403,7 +411,11 @@ var ( proc__xnet_getsockopt, procgetpeername, procsetsockopt, - procrecvfrom syscallFunc + procrecvfrom, + procport_create, + procport_associate, + procport_dissociate, + procport_get syscallFunc ) // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -1981,3 +1993,47 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func port_create() (n int, err error) { + r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_create)), 0, 0, 0, 0, 0, 0, 0) + n = int(r0) + if e1 != 0 { + err = e1 + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func port_associate(port int, source int, object uintptr, events int, user *byte) (n int, err error) { + r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_associate)), 5, uintptr(port), uintptr(source), uintptr(object), uintptr(events), uintptr(unsafe.Pointer(user)), 0) + n = int(r0) + if e1 != 0 { + err = e1 + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func port_dissociate(port int, source int, object uintptr) (n int, err error) { + r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_dissociate)), 3, uintptr(port), uintptr(source), uintptr(object), 0, 0, 0) + n = int(r0) + if e1 != 0 { + err = e1 + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func port_get(port int, pe *PortEvent, timeout *Timespec) (n int, err error) { + r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_get)), 3, uintptr(port), uintptr(unsafe.Pointer(pe)), uintptr(unsafe.Pointer(timeout)), 0, 0, 0) + n = int(r0) + if e1 != 0 { + err = e1 + } + return +}