138 lines
3.4 KiB
Go
138 lines
3.4 KiB
Go
// +build darwin dragonfly freebsd linux netbsd openbsd
|
|
|
|
// Package shm implements System V shared memory functions (shmctl, shmget, shmat, shmdt).
|
|
package shm
|
|
|
|
import (
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
// Constants.
|
|
const (
|
|
// Mode bits for `shmget`.
|
|
|
|
// Create key if key does not exist.
|
|
IPC_CREAT = 01000
|
|
// Fail if key exists.
|
|
IPC_EXCL = 02000
|
|
// Return error on wait.
|
|
IPC_NOWAIT = 04000
|
|
|
|
// Special key values.
|
|
|
|
// Private key.
|
|
IPC_PRIVATE = 0
|
|
|
|
// Flags for `shmat`.
|
|
|
|
// Attach read-only access.
|
|
SHM_RDONLY = 010000
|
|
// Round attach address to SHMLBA.
|
|
SHM_RND = 020000
|
|
// Take-over region on attach.
|
|
SHM_REMAP = 040000
|
|
// Execution access.
|
|
SHM_EXEC = 0100000
|
|
|
|
// Commands for `shmctl`.
|
|
|
|
// Lock segment (root only).
|
|
SHM_LOCK = 1
|
|
// Unlock segment (root only).
|
|
SHM_UNLOCK = 12
|
|
|
|
// Control commands for `shmctl`.
|
|
|
|
// Remove identifier.
|
|
IPC_RMID = 0
|
|
// Set `ipc_perm` options.
|
|
IPC_SET = 1
|
|
// Get `ipc_perm' options.
|
|
IPC_STAT = 2
|
|
)
|
|
|
|
// Get allocates a shared memory segment.
|
|
//
|
|
// Get() returns the identifier of the shared memory segment associated with the value of the argument key.
|
|
// A new shared memory segment is created if key has the value IPC_PRIVATE or key isn't IPC_PRIVATE,
|
|
// no shared memory segment corresponding to key exists, and IPC_CREAT is specified in shmFlg.
|
|
//
|
|
// If shmFlg specifies both IPC_CREAT and IPC_EXCL and a shared memory segment already exists for key,
|
|
// then Get() fails with errno set to EEXIST.
|
|
func Get(key int, size int, shmFlg int) (shmId int, err error) {
|
|
id, _, errno := syscall.Syscall(sysShmGet, uintptr(int32(key)), uintptr(int32(size)), uintptr(int32(shmFlg)))
|
|
if int(id) == -1 {
|
|
return -1, errno
|
|
}
|
|
|
|
return int(id), nil
|
|
}
|
|
|
|
// At attaches the shared memory segment identified by shmId.
|
|
//
|
|
// Using At() with shmAddr equal to NULL is the preferred, portable way of attaching a shared memory segment.
|
|
func At(shmId int, shmAddr uintptr, shmFlg int) (data []byte, err error) {
|
|
addr, _, errno := syscall.Syscall(sysShmAt, uintptr(int32(shmId)), shmAddr, uintptr(int32(shmFlg)))
|
|
if int(addr) == -1 {
|
|
return nil, errno
|
|
}
|
|
|
|
length, err := Size(shmId)
|
|
if err != nil {
|
|
syscall.Syscall(sysShmDt, addr, 0, 0)
|
|
return nil, err
|
|
}
|
|
|
|
var b = struct {
|
|
addr uintptr
|
|
len int
|
|
cap int
|
|
}{addr, int(length), int(length)}
|
|
|
|
data = *(*[]byte)(unsafe.Pointer(&b))
|
|
return data, nil
|
|
}
|
|
|
|
// Dt detaches the shared memory segment.
|
|
//
|
|
// The to-be-detached segment must be currently attached with shmAddr equal to the value returned by the attaching At() call.
|
|
func Dt(data []byte) error {
|
|
result, _, errno := syscall.Syscall(sysShmDt, uintptr(unsafe.Pointer(&data[0])), 0, 0)
|
|
if int(result) == -1 {
|
|
return errno
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Ctl performs the control operation specified by cmd on the shared memory segment whose identifier is given in shmId.
|
|
//
|
|
// The buf argument is a pointer to a IdDs structure.
|
|
func Ctl(shmId int, cmd int, buf *IdDs) (int, error) {
|
|
result, _, errno := syscall.Syscall(sysShmCtl, uintptr(int32(shmId)), uintptr(int32(cmd)), uintptr(unsafe.Pointer(buf)))
|
|
if int(result) == -1 {
|
|
return -1, errno
|
|
}
|
|
|
|
return int(result), nil
|
|
}
|
|
|
|
// Rm removes the shared memory segment.
|
|
func Rm(shmId int) error {
|
|
_, err := Ctl(shmId, IPC_RMID, nil)
|
|
return err
|
|
}
|
|
|
|
// Size returns size of shared memory segment.
|
|
func Size(shmId int) (int64, error) {
|
|
var idDs IdDs
|
|
|
|
_, err := Ctl(shmId, IPC_STAT, &idDs)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return int64(idDs.SegSz), nil
|
|
}
|