Skip to content

Commit

Permalink
unix: create wrappers solaris/illumos Event Ports
Browse files Browse the repository at this point in the history
This work is in support of a cleanup of fsnotify/fsnotify#263

Change-Id: Ibd7500d20322765bfd50aa18333eb43ee7b659d7
  • Loading branch information
nshalman committed Jun 3, 2021
1 parent 832ab58 commit a87345d
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 1 deletion.
84 changes: 84 additions & 0 deletions unix/syscall_solaris.go
Expand Up @@ -13,6 +13,8 @@
package unix

import (
"fmt"
"os"
"runtime"
"syscall"
"unsafe"
Expand Down Expand Up @@ -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
}
*/
44 changes: 44 additions & 0 deletions unix/syscall_solaris_test.go
Expand Up @@ -8,8 +8,11 @@
package unix_test

import (
"os"
"os/exec"
"runtime"
"testing"
"unsafe"

"golang.org/x/sys/unix"
)
Expand Down Expand Up @@ -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)
}
}
58 changes: 57 additions & 1 deletion unix/zsyscall_solaris_amd64.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a87345d

Please sign in to comment.