unix: add Sysv shared memory support

Implements proposed API from https://golang.org/issue/46084. I chose
`SysvShmDesc` since it's a clearer name than `SysvShm`. Initially supports Darwin and Linux.

Solaris support has a blocker (https://golang.org/issue/46084#issuecomment-836980018)

For golang/go#46084

Change-Id: Ied0f768a74c448254adc3315348417825a7ec63e
GitHub-Last-Rev: befbd7af6b2f838753ac163ef387cebdb7957467
GitHub-Pull-Request: golang/sys#110
Reviewed-on: https://go-review.googlesource.com/c/sys/+/327830
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
diff --git a/unix/example_sysvshm_test.go b/unix/example_sysvshm_test.go
new file mode 100644
index 0000000..537f770
--- /dev/null
+++ b/unix/example_sysvshm_test.go
@@ -0,0 +1,52 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (darwin && amd64) || (linux && !android)
+// +build darwin,amd64 linux,!android
+
+package unix_test
+
+import (
+	"log"
+
+	"golang.org/x/sys/unix"
+)
+
+func ExampleSysvShmGet() {
+
+	// create shared memory region of 1024 bytes
+	id, err := unix.SysvShmGet(unix.IPC_PRIVATE, 1024, unix.IPC_CREAT|unix.IPC_EXCL|0o600)
+	if err != nil {
+		log.Fatal("sysv shm create failed:", err)
+	}
+
+	// warning: sysv shared memory segments persist even after after a process
+	// is destroyed, so it's very important to explicitly delete it when you
+	// don't need it anymore.
+	defer func() {
+		_, err := unix.SysvShmCtl(id, unix.IPC_RMID, nil)
+		if err != nil {
+			log.Fatal(err)
+		}
+	}()
+
+	// to use a shared memory region you must attach to it
+	b, err := unix.SysvShmAttach(id, 0, 0)
+	if err != nil {
+		log.Fatal("sysv attach failed:", err)
+	}
+
+	// you should detach from the segment when finished with it. The byte
+	// slice is no longer valid after detaching
+	defer func() {
+		if err = unix.SysvShmDetach(b); err != nil {
+			log.Fatal("sysv detach failed:", err)
+		}
+	}()
+
+	// Changes to the contents of the byte slice are reflected in other
+	// mappings of the shared memory identifer in this and other processes
+	b[42] = 'h'
+	b[43] = 'i'
+}
diff --git a/unix/linux/types.go b/unix/linux/types.go
index 515e3b6..faea3d2 100644
--- a/unix/linux/types.go
+++ b/unix/linux/types.go
@@ -106,6 +106,7 @@
 #include <linux/if_packet.h>
 #include <linux/if_pppox.h>
 #include <linux/if_xdp.h>
+#include <linux/ipc.h>
 #include <linux/keyctl.h>
 #include <linux/landlock.h>
 #include <linux/loop.h>
@@ -128,6 +129,7 @@
 #include <linux/random.h>
 #include <linux/rtc.h>
 #include <linux/rtnetlink.h>
+#include <linux/shm.h>
 #include <linux/socket.h>
 #include <linux/stat.h>
 #include <linux/taskstats.h>
@@ -3835,3 +3837,28 @@
 const (
 	PIDFD_NONBLOCK = C.O_NONBLOCK
 )
+
+// shm
+
+type SysvIpcPerm C.struct_ipc64_perm
+type SysvShmDesc C.struct_shmid64_ds
+
+const (
+	IPC_CREAT   = C.IPC_CREAT
+	IPC_EXCL    = C.IPC_EXCL
+	IPC_NOWAIT  = C.IPC_NOWAIT
+	IPC_PRIVATE = C.IPC_PRIVATE
+
+	ipc_64 = C.IPC_64
+)
+
+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/syscall_darwin.go b/unix/syscall_darwin.go
index 23f6b57..d59fb95 100644
--- a/unix/syscall_darwin.go
+++ b/unix/syscall_darwin.go
@@ -433,6 +433,11 @@
 
 //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 @@
 // Msgget
 // Msgsnd
 // Msgrcv
-// Shmat
-// Shmctl
-// Shmdt
-// Shmget
 // Shm_open
 // Shm_unlink
 // Sem_open
diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go
index e253a91..fff38a8 100644
--- a/unix/syscall_linux.go
+++ b/unix/syscall_linux.go
@@ -2319,6 +2319,11 @@
 //sys	PidfdOpen(pid int, flags int) (fd int, err error) = SYS_PIDFD_OPEN
 //sys	PidfdGetfd(pidfd int, targetfd int, flags int) (fd int, err error) = SYS_PIDFD_GETFD
 
+//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)
+
 /*
  * Unimplemented
  */
@@ -2400,10 +2405,6 @@
 // SetRobustList
 // SetThreadArea
 // SetTidAddress
-// Shmat
-// Shmctl
-// Shmdt
-// Shmget
 // Sigaltstack
 // Swapoff
 // Swapon
diff --git a/unix/sysvshm_linux.go b/unix/sysvshm_linux.go
new file mode 100644
index 0000000..b9476c6
--- /dev/null
+++ b/unix/sysvshm_linux.go
@@ -0,0 +1,20 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux
+// +build linux
+
+package unix
+
+import "runtime"
+
+// SysvShmCtl performs control operations on the shared memory segment
+// specified by id.
+func SysvShmCtl(id, cmd int, desc *SysvShmDesc) (result int, err error) {
+	if runtime.GOARCH == "arm" {
+		cmd |= ipc_64
+	}
+
+	return shmctl(id, cmd, desc)
+}
diff --git a/unix/sysvshm_unix.go b/unix/sysvshm_unix.go
new file mode 100644
index 0000000..7d6ba36
--- /dev/null
+++ b/unix/sysvshm_unix.go
@@ -0,0 +1,61 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (darwin && amd64) || linux
+// +build darwin,amd64 linux
+
+package unix
+
+import (
+	"unsafe"
+
+	"golang.org/x/sys/internal/unsafeheader"
+)
+
+// 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 from shmdt as there's nothing sensible to return here
+		shmdt(addr)
+		return nil, err
+	}
+
+	// Use unsafe to convert addr into a []byte.
+	// TODO: convert to unsafe.Slice once we can assume Go 1.17
+	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
+}
+
+// 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 len(data) == 0 {
+		return EINVAL
+	}
+
+	return shmdt(uintptr(unsafe.Pointer(&data[0])))
+}
+
+// SysvShmGet returns the Sysv shared memory identifier associated with key.
+// If the IPC_CREAT flag is specified a new segment is created.
+func SysvShmGet(key, size, flag int) (id int, err error) {
+	return shmget(key, size, flag)
+}
diff --git a/unix/sysvshm_unix_other.go b/unix/sysvshm_unix_other.go
new file mode 100644
index 0000000..579b53b
--- /dev/null
+++ b/unix/sysvshm_unix_other.go
@@ -0,0 +1,14 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (darwin && amd64)
+// +build darwin,amd64
+
+package unix
+
+// 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)
+}
diff --git a/unix/sysvshm_unix_test.go b/unix/sysvshm_unix_test.go
new file mode 100644
index 0000000..61c7b8d
--- /dev/null
+++ b/unix/sysvshm_unix_test.go
@@ -0,0 +1,74 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (darwin && amd64) || linux
+// +build darwin,amd64 linux
+
+package unix_test
+
+import (
+	"runtime"
+	"testing"
+
+	"golang.org/x/sys/unix"
+)
+
+func TestSysvSharedMemory(t *testing.T) {
+	// create ipc
+	id, err := unix.SysvShmGet(unix.IPC_PRIVATE, 1024, unix.IPC_CREAT|unix.IPC_EXCL|0o600)
+
+	// ipc isn't implemented on android, should fail
+	if runtime.GOOS == "android" {
+		if err != unix.ENOSYS {
+			t.Fatalf("expected android to fail, but it didn't")
+		}
+		return
+	}
+
+	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")
+	}
+}
diff --git a/unix/types_darwin.go b/unix/types_darwin.go
index 0b13f93..3cbd0da 100644
--- a/unix/types_darwin.go
+++ b/unix/types_darwin.go
@@ -27,6 +27,7 @@
 #include <mach/mach.h>
 #include <mach/message.h>
 #include <sys/event.h>
+#include <sys/ipc.h>
 #include <sys/kern_control.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
@@ -34,6 +35,7 @@
 #include <sys/ptrace.h>
 #include <sys/resource.h>
 #include <sys/select.h>
+#include <sys/shm.h>
 #include <sys/signal.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -323,3 +325,26 @@
 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/zerrors_linux.go b/unix/zerrors_linux.go
index b959fe1..78d4b85 100644
--- a/unix/zerrors_linux.go
+++ b/unix/zerrors_linux.go
@@ -1397,6 +1397,8 @@
 	MADV_NOHUGEPAGE                             = 0xf
 	MADV_NORMAL                                 = 0x0
 	MADV_PAGEOUT                                = 0x15
+	MADV_POPULATE_READ                          = 0x16
+	MADV_POPULATE_WRITE                         = 0x17
 	MADV_RANDOM                                 = 0x1
 	MADV_REMOVE                                 = 0x9
 	MADV_SEQUENTIAL                             = 0x2
diff --git a/unix/zsyscall_darwin_amd64.go b/unix/zsyscall_darwin_amd64.go
index d4efe8d..0ae0ed4 100644
--- a/unix/zsyscall_darwin_amd64.go
+++ b/unix/zsyscall_darwin_amd64.go
@@ -734,6 +734,65 @@
 
 // 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 bc169c2..eac6ca8 100644
--- a/unix/zsyscall_darwin_amd64.s
+++ b/unix/zsyscall_darwin_amd64.s
@@ -264,6 +264,30 @@
 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/zsyscall_linux.go b/unix/zsyscall_linux.go
index 701f7eb..4f5da1f 100644
--- a/unix/zsyscall_linux.go
+++ b/unix/zsyscall_linux.go
@@ -1974,3 +1974,46 @@
 	}
 	return
 }
+
+// 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(SYS_SHMAT, uintptr(id), uintptr(addr), uintptr(flag))
+	ret = uintptr(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// 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(SYS_SHMCTL, uintptr(id), uintptr(cmd), uintptr(unsafe.Pointer(buf)))
+	result = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmdt(addr uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_SHMDT, uintptr(addr), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// 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(SYS_SHMGET, uintptr(key), uintptr(size), uintptr(flag))
+	id = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
diff --git a/unix/ztypes_darwin_amd64.go b/unix/ztypes_darwin_amd64.go
index 4c8dc0b..71db853 100644
--- a/unix/ztypes_darwin_amd64.go
+++ b/unix/ztypes_darwin_amd64.go
@@ -639,3 +639,39 @@
 	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
+)
diff --git a/unix/ztypes_linux.go b/unix/ztypes_linux.go
index 06dcd78..249ecfc 100644
--- a/unix/ztypes_linux.go
+++ b/unix/ztypes_linux.go
@@ -3936,3 +3936,23 @@
 const (
 	LANDLOCK_RULE_PATH_BENEATH = 0x1
 )
+
+const (
+	IPC_CREAT   = 0x200
+	IPC_EXCL    = 0x400
+	IPC_NOWAIT  = 0x800
+	IPC_PRIVATE = 0x0
+
+	ipc_64 = 0x100
+)
+
+const (
+	IPC_RMID = 0x0
+	IPC_SET  = 0x1
+	IPC_STAT = 0x2
+)
+
+const (
+	SHM_RDONLY = 0x1000
+	SHM_RND    = 0x2000
+)
diff --git a/unix/ztypes_linux_386.go b/unix/ztypes_linux_386.go
index 3219ade..eeeb9aa 100644
--- a/unix/ztypes_linux_386.go
+++ b/unix/ztypes_linux_386.go
@@ -639,3 +639,32 @@
 const (
 	PIDFD_NONBLOCK = 0x800
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint16
+	_    [2]uint8
+	Seq  uint16
+	_    uint16
+	_    uint32
+	_    uint32
+}
+type SysvShmDesc struct {
+	Perm       SysvIpcPerm
+	Segsz      uint32
+	Atime      uint32
+	Atime_high uint32
+	Dtime      uint32
+	Dtime_high uint32
+	Ctime      uint32
+	Ctime_high uint32
+	Cpid       int32
+	Lpid       int32
+	Nattch     uint32
+	_          uint32
+	_          uint32
+}
diff --git a/unix/ztypes_linux_amd64.go b/unix/ztypes_linux_amd64.go
index 16acd3b..d30e115 100644
--- a/unix/ztypes_linux_amd64.go
+++ b/unix/ztypes_linux_amd64.go
@@ -657,3 +657,29 @@
 const (
 	PIDFD_NONBLOCK = 0x800
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	_    [0]uint8
+	Seq  uint16
+	_    uint16
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm   SysvIpcPerm
+	Segsz  uint64
+	Atime  int64
+	Dtime  int64
+	Ctime  int64
+	Cpid   int32
+	Lpid   int32
+	Nattch uint64
+	_      uint64
+	_      uint64
+}
diff --git a/unix/ztypes_linux_arm.go b/unix/ztypes_linux_arm.go
index c4982a2..69d0297 100644
--- a/unix/ztypes_linux_arm.go
+++ b/unix/ztypes_linux_arm.go
@@ -634,3 +634,32 @@
 const (
 	PIDFD_NONBLOCK = 0x800
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint16
+	_    [2]uint8
+	Seq  uint16
+	_    uint16
+	_    uint32
+	_    uint32
+}
+type SysvShmDesc struct {
+	Perm       SysvIpcPerm
+	Segsz      uint32
+	Atime      uint32
+	Atime_high uint32
+	Dtime      uint32
+	Dtime_high uint32
+	Ctime      uint32
+	Ctime_high uint32
+	Cpid       int32
+	Lpid       int32
+	Nattch     uint32
+	_          uint32
+	_          uint32
+}
diff --git a/unix/ztypes_linux_arm64.go b/unix/ztypes_linux_arm64.go
index 98bb8a4..28a0455 100644
--- a/unix/ztypes_linux_arm64.go
+++ b/unix/ztypes_linux_arm64.go
@@ -636,3 +636,29 @@
 const (
 	PIDFD_NONBLOCK = 0x800
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	_    [0]uint8
+	Seq  uint16
+	_    uint16
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm   SysvIpcPerm
+	Segsz  uint64
+	Atime  int64
+	Dtime  int64
+	Ctime  int64
+	Cpid   int32
+	Lpid   int32
+	Nattch uint64
+	_      uint64
+	_      uint64
+}
diff --git a/unix/ztypes_linux_mips.go b/unix/ztypes_linux_mips.go
index d5bfc35..64a8454 100644
--- a/unix/ztypes_linux_mips.go
+++ b/unix/ztypes_linux_mips.go
@@ -640,3 +640,31 @@
 const (
 	PIDFD_NONBLOCK = 0x80
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	_    [0]uint8
+	Seq  uint16
+	_    uint16
+	_    uint32
+	_    uint32
+}
+type SysvShmDesc struct {
+	Perm       SysvIpcPerm
+	Segsz      uint32
+	Atime      uint32
+	Dtime      uint32
+	Ctime      uint32
+	Cpid       int32
+	Lpid       int32
+	Nattch     uint32
+	Atime_high uint16
+	Dtime_high uint16
+	Ctime_high uint16
+	_          uint16
+}
diff --git a/unix/ztypes_linux_mips64.go b/unix/ztypes_linux_mips64.go
index b52c568..a1b7dee 100644
--- a/unix/ztypes_linux_mips64.go
+++ b/unix/ztypes_linux_mips64.go
@@ -639,3 +639,29 @@
 const (
 	PIDFD_NONBLOCK = 0x80
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	_    [0]uint8
+	Seq  uint16
+	_    uint16
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm   SysvIpcPerm
+	Segsz  uint64
+	Atime  int64
+	Dtime  int64
+	Ctime  int64
+	Cpid   int32
+	Lpid   int32
+	Nattch uint64
+	_      uint64
+	_      uint64
+}
diff --git a/unix/ztypes_linux_mips64le.go b/unix/ztypes_linux_mips64le.go
index a340b84..936fa6a 100644
--- a/unix/ztypes_linux_mips64le.go
+++ b/unix/ztypes_linux_mips64le.go
@@ -639,3 +639,29 @@
 const (
 	PIDFD_NONBLOCK = 0x80
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	_    [0]uint8
+	Seq  uint16
+	_    uint16
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm   SysvIpcPerm
+	Segsz  uint64
+	Atime  int64
+	Dtime  int64
+	Ctime  int64
+	Cpid   int32
+	Lpid   int32
+	Nattch uint64
+	_      uint64
+	_      uint64
+}
diff --git a/unix/ztypes_linux_mipsle.go b/unix/ztypes_linux_mipsle.go
index b43d8e2..5dd546f 100644
--- a/unix/ztypes_linux_mipsle.go
+++ b/unix/ztypes_linux_mipsle.go
@@ -640,3 +640,31 @@
 const (
 	PIDFD_NONBLOCK = 0x80
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	_    [0]uint8
+	Seq  uint16
+	_    uint16
+	_    uint32
+	_    uint32
+}
+type SysvShmDesc struct {
+	Perm       SysvIpcPerm
+	Segsz      uint32
+	Atime      uint32
+	Dtime      uint32
+	Ctime      uint32
+	Cpid       int32
+	Lpid       int32
+	Nattch     uint32
+	Atime_high uint16
+	Dtime_high uint16
+	Ctime_high uint16
+	_          uint16
+}
diff --git a/unix/ztypes_linux_ppc.go b/unix/ztypes_linux_ppc.go
index efd7313..947b32e 100644
--- a/unix/ztypes_linux_ppc.go
+++ b/unix/ztypes_linux_ppc.go
@@ -646,3 +646,33 @@
 const (
 	PIDFD_NONBLOCK = 0x800
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	Seq  uint32
+	_    uint32
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm       SysvIpcPerm
+	Atime_high uint32
+	Atime      uint32
+	Dtime_high uint32
+	Dtime      uint32
+	Ctime_high uint32
+	Ctime      uint32
+	_          uint32
+	Segsz      uint32
+	Cpid       int32
+	Lpid       int32
+	Nattch     uint32
+	_          uint32
+	_          uint32
+	_          [4]byte
+}
diff --git a/unix/ztypes_linux_ppc64.go b/unix/ztypes_linux_ppc64.go
index 22cedda..2a60615 100644
--- a/unix/ztypes_linux_ppc64.go
+++ b/unix/ztypes_linux_ppc64.go
@@ -646,3 +646,28 @@
 const (
 	PIDFD_NONBLOCK = 0x800
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	Seq  uint32
+	_    uint32
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm   SysvIpcPerm
+	Atime  int64
+	Dtime  int64
+	Ctime  int64
+	Segsz  uint64
+	Cpid   int32
+	Lpid   int32
+	Nattch uint64
+	_      uint64
+	_      uint64
+}
diff --git a/unix/ztypes_linux_ppc64le.go b/unix/ztypes_linux_ppc64le.go
index 452a76d..d0d735d 100644
--- a/unix/ztypes_linux_ppc64le.go
+++ b/unix/ztypes_linux_ppc64le.go
@@ -646,3 +646,28 @@
 const (
 	PIDFD_NONBLOCK = 0x800
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	Seq  uint32
+	_    uint32
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm   SysvIpcPerm
+	Atime  int64
+	Dtime  int64
+	Ctime  int64
+	Segsz  uint64
+	Cpid   int32
+	Lpid   int32
+	Nattch uint64
+	_      uint64
+	_      uint64
+}
diff --git a/unix/ztypes_linux_riscv64.go b/unix/ztypes_linux_riscv64.go
index 96c667d..95e3d6d 100644
--- a/unix/ztypes_linux_riscv64.go
+++ b/unix/ztypes_linux_riscv64.go
@@ -664,3 +664,29 @@
 const (
 	PIDFD_NONBLOCK = 0x800
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	_    [0]uint8
+	Seq  uint16
+	_    uint16
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm   SysvIpcPerm
+	Segsz  uint64
+	Atime  int64
+	Dtime  int64
+	Ctime  int64
+	Cpid   int32
+	Lpid   int32
+	Nattch uint64
+	_      uint64
+	_      uint64
+}
diff --git a/unix/ztypes_linux_s390x.go b/unix/ztypes_linux_s390x.go
index af04ee1..cccf1ef 100644
--- a/unix/ztypes_linux_s390x.go
+++ b/unix/ztypes_linux_s390x.go
@@ -660,3 +660,28 @@
 const (
 	PIDFD_NONBLOCK = 0x800
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	_    uint16
+	Seq  uint16
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm   SysvIpcPerm
+	Segsz  uint64
+	Atime  int64
+	Dtime  int64
+	Ctime  int64
+	Cpid   int32
+	Lpid   int32
+	Nattch uint64
+	_      uint64
+	_      uint64
+}
diff --git a/unix/ztypes_linux_sparc64.go b/unix/ztypes_linux_sparc64.go
index 6f385cf..44fcbe4 100644
--- a/unix/ztypes_linux_sparc64.go
+++ b/unix/ztypes_linux_sparc64.go
@@ -641,3 +641,28 @@
 const (
 	PIDFD_NONBLOCK = 0x4000
 )
+
+type SysvIpcPerm struct {
+	Key  int32
+	Uid  uint32
+	Gid  uint32
+	Cuid uint32
+	Cgid uint32
+	Mode uint32
+	_    uint16
+	Seq  uint16
+	_    uint64
+	_    uint64
+}
+type SysvShmDesc struct {
+	Perm   SysvIpcPerm
+	Atime  int64
+	Dtime  int64
+	Ctime  int64
+	Segsz  uint64
+	Cpid   int32
+	Lpid   int32
+	Nattch uint64
+	_      uint64
+	_      uint64
+}