diff --git a/unix/syscall_darwin.go b/unix/syscall_darwin.go index 23f6b576..d59fb95c 100644 --- a/unix/syscall_darwin.go +++ b/unix/syscall_darwin.go @@ -433,6 +433,11 @@ func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) { //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) +//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) +//sys shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error) +//sys shmdt(addr uintptr) (err error) +//sys shmget(key int, size int, flag int) (id int, err error) + /* * Exposed directly */ @@ -590,10 +595,6 @@ func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) { // Msgget // Msgsnd // Msgrcv -// Shmat -// Shmctl -// Shmdt -// Shmget // Shm_open // Shm_unlink // Sem_open diff --git a/unix/syscall_unix.go b/unix/syscall_unix.go index cf296a24..9d3d4615 100644 --- a/unix/syscall_unix.go +++ b/unix/syscall_unix.go @@ -433,3 +433,53 @@ func Lutimes(path string, tv []Timeval) error { } return UtimesNanoAt(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW) } + +// SysvShmAttach attaches the Sysv shared memory segment associated with the +// shared memory identifier id. +func SysvShmAttach(id int, addr uintptr, flag int) ([]byte, error) { + addr, errno := shmat(id, addr, flag) + if errno != nil { + return nil, errno + } + + // Retrieve the size of the shared memory to enable slice creation + var info SysvShmDesc + + _, err := SysvShmCtl(id, IPC_STAT, &info) + if err != nil { + // release the shared memory if we can't find the size; ignoring error + // here since there's nothing sensible we can return here + shmdt(addr) + return nil, err + } + + // Use unsafe to convert addr into a []byte. + var b []byte + hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b)) + hdr.Data = unsafe.Pointer(addr) + hdr.Cap = int(info.Segsz) + hdr.Len = int(info.Segsz) + return b, nil +} + +// SysvShmCtl performs control operations on the shared memory segment +// specified by id. +func SysvShmCtl(id, cmd int, desc *SysvShmDesc) (result int, err error) { + return shmctl(id, cmd, desc) +} + +// SysvShmDetach unmaps the shared memory slice returned from SysvShmAttach. +// +// It is not safe to use the slice after calling this function. +func SysvShmDetach(data []byte) error { + if data == nil { + return EINVAL + } + + return shmdt(uintptr(unsafe.Pointer(&data[0]))) +} + +// SysvShmGet returns the Sysv shared memory identifier associated with key. +func SysvShmGet(key, size, flag int) (id int, err error) { + return shmget(key, size, flag) +} diff --git a/unix/syscall_unix_test.go b/unix/syscall_unix_test.go index 2f672832..ea3a71be 100644 --- a/unix/syscall_unix_test.go +++ b/unix/syscall_unix_test.go @@ -852,6 +852,56 @@ func TestRenameat(t *testing.T) { } } +func TestSysvSharedMemory(t *testing.T) { + // create ipc + id, err := unix.SysvShmGet(unix.IPC_PRIVATE, 1024, unix.IPC_CREAT|unix.IPC_EXCL|0o600) + if err != nil { + t.Fatalf("SysvShmGet: %v", err) + } + defer func() { + _, err := unix.SysvShmCtl(id, unix.IPC_RMID, nil) + if err != nil { + t.Errorf("Remove failed: %v", err) + } + }() + + // attach + b1, err := unix.SysvShmAttach(id, 0, 0) + if err != nil { + t.Fatalf("Attach: %v", err) + } + + if len(b1) != 1024 { + t.Fatalf("b1 len = %v, want 1024", len(b1)) + } + + b1[42] = 'x' + + // attach again + b2, err := unix.SysvShmAttach(id, 0, 0) + if err != nil { + t.Fatalf("Attach: %v", err) + } + + if len(b2) != 1024 { + t.Fatalf("b2 len = %v, want 1024", len(b1)) + } + + b2[43] = 'y' + if b2[42] != 'x' || b1[43] != 'y' { + t.Fatalf("shared memory isn't shared") + } + + // detach + if err = unix.SysvShmDetach(b2); err != nil { + t.Fatalf("Detach: %v", err) + } + + if b1[42] != 'x' || b1[43] != 'y' { + t.Fatalf("shared memory was invalidated") + } +} + func TestUtimesNanoAt(t *testing.T) { defer chtmpdir(t)() diff --git a/unix/types_darwin.go b/unix/types_darwin.go index 0b13f935..3cbd0dab 100644 --- a/unix/types_darwin.go +++ b/unix/types_darwin.go @@ -27,6 +27,7 @@ package unix #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ package unix #include #include #include +#include #include #include #include @@ -323,3 +325,26 @@ type Vmspace C.struct_vmspace type Pcred C.struct__pcred type Ucred C.struct__ucred + +// shm + +type SysvIpcPerm C.struct_ipc_perm +type SysvShmDesc C.struct_shmid_ds + +const ( + IPC_CREAT = C.IPC_CREAT + IPC_EXCL = C.IPC_EXCL + IPC_NOWAIT = C.IPC_NOWAIT + IPC_PRIVATE = C.IPC_PRIVATE +) + +const ( + IPC_RMID = C.IPC_RMID + IPC_SET = C.IPC_SET + IPC_STAT = C.IPC_STAT +) + +const ( + SHM_RDONLY = C.SHM_RDONLY + SHM_RND = C.SHM_RND +) diff --git a/unix/zsyscall_darwin_amd64.go b/unix/zsyscall_darwin_amd64.go index d4efe8d4..0ae0ed4c 100644 --- a/unix/zsyscall_darwin_amd64.go +++ b/unix/zsyscall_darwin_amd64.go @@ -734,6 +734,65 @@ var libc_sendfile_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func shmat(id int, addr uintptr, flag int) (ret uintptr, err error) { + r0, _, e1 := syscall_syscall(libc_shmat_trampoline_addr, uintptr(id), uintptr(addr), uintptr(flag)) + ret = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_shmat_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_shmat shmat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error) { + r0, _, e1 := syscall_syscall(libc_shmctl_trampoline_addr, uintptr(id), uintptr(cmd), uintptr(unsafe.Pointer(buf))) + result = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_shmctl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_shmctl shmctl "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func shmdt(addr uintptr) (err error) { + _, _, e1 := syscall_syscall(libc_shmdt_trampoline_addr, uintptr(addr), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_shmdt_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_shmdt shmdt "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func shmget(key int, size int, flag int) (id int, err error) { + r0, _, e1 := syscall_syscall(libc_shmget_trampoline_addr, uintptr(key), uintptr(size), uintptr(flag)) + id = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_shmget_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_shmget shmget "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Access(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/unix/zsyscall_darwin_amd64.s b/unix/zsyscall_darwin_amd64.s index bc169c2a..eac6ca80 100644 --- a/unix/zsyscall_darwin_amd64.s +++ b/unix/zsyscall_darwin_amd64.s @@ -264,6 +264,30 @@ TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 DATA ·libc_sendfile_trampoline_addr(SB)/8, $libc_sendfile_trampoline<>(SB) +TEXT libc_shmat_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_shmat(SB) + +GLOBL ·libc_shmat_trampoline_addr(SB), RODATA, $8 +DATA ·libc_shmat_trampoline_addr(SB)/8, $libc_shmat_trampoline<>(SB) + +TEXT libc_shmctl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_shmctl(SB) + +GLOBL ·libc_shmctl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_shmctl_trampoline_addr(SB)/8, $libc_shmctl_trampoline<>(SB) + +TEXT libc_shmdt_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_shmdt(SB) + +GLOBL ·libc_shmdt_trampoline_addr(SB), RODATA, $8 +DATA ·libc_shmdt_trampoline_addr(SB)/8, $libc_shmdt_trampoline<>(SB) + +TEXT libc_shmget_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_shmget(SB) + +GLOBL ·libc_shmget_trampoline_addr(SB), RODATA, $8 +DATA ·libc_shmget_trampoline_addr(SB)/8, $libc_shmget_trampoline<>(SB) + TEXT libc_access_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_access(SB) diff --git a/unix/ztypes_darwin_amd64.go b/unix/ztypes_darwin_amd64.go index 4c8dc0ba..d48749fc 100644 --- a/unix/ztypes_darwin_amd64.go +++ b/unix/ztypes_darwin_amd64.go @@ -639,3 +639,38 @@ type Ucred struct { Ngroups int16 Groups [16]uint32 } +type SysvIpcPerm struct { + Uid uint32 + Gid uint32 + Cuid uint32 + Cgid uint32 + Mode uint16 + _ uint16 + _ int32 +} +type SysvShmDesc struct { + Perm SysvIpcPerm + Segsz uint64 + Lpid int32 + Cpid int32 + Nattch uint16 + _ [34]byte +} + +const ( + IPC_CREAT = 0x200 + IPC_EXCL = 0x400 + IPC_NOWAIT = 0x800 + IPC_PRIVATE = 0x0 +) + +const ( + IPC_RMID = 0x0 + IPC_SET = 0x1 + IPC_STAT = 0x2 +) + +const ( + SHM_RDONLY = 0x1000 + SHM_RND = 0x2000 +)