132 lines
4.0 KiB
Go
132 lines
4.0 KiB
Go
package shm
|
|
|
|
import (
|
|
"fmt"
|
|
"unsafe"
|
|
|
|
"bash_go_service/config-loader/internal/models"
|
|
"bash_go_service/shared/pkg/constants"
|
|
"bash_go_service/shared/pkg/logger"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// shmget 调用系统调用 SYS_SHMGET 创建或获取共享内存段
|
|
// key: 共享内存的键值
|
|
// size: 共享内存的大小
|
|
// shmflg: 标志位,用于指定权限和行为
|
|
func shmget(key int, size int, shmflg int) (int, error) {
|
|
id, _, errno := unix.Syscall(unix.SYS_SHMGET, uintptr(key), uintptr(size), uintptr(shmflg))
|
|
if errno != 0 {
|
|
return 0, errno
|
|
}
|
|
return int(id), nil
|
|
}
|
|
|
|
// shmat 调用系统调用 SYS_SHMAT 将共享内存段附加到进程的地址空间
|
|
// shmid: 共享内存段的 ID
|
|
// shmaddr: 指定的附加地址(通常为 0 表示系统自动选择)
|
|
// shmflg: 标志位,用于指定附加模式
|
|
func shmat(shmid int, shmaddr uintptr, shmflg int) (unsafe.Pointer, error) {
|
|
addr, _, errno := unix.Syscall(unix.SYS_SHMAT, uintptr(shmid), shmaddr, uintptr(shmflg))
|
|
if errno != 0 {
|
|
return nil, errno
|
|
}
|
|
return unsafe.Pointer(addr), nil
|
|
}
|
|
|
|
// shmdt 调用系统调用 SYS_SHMDT 将共享内存段从进程的地址空间分离
|
|
// shmaddr: 共享内存段的地址
|
|
func shmdt(shmaddr unsafe.Pointer) error {
|
|
_, _, errno := unix.Syscall(unix.SYS_SHMDT, uintptr(shmaddr), 0, 0)
|
|
if errno != 0 {
|
|
return errno
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WriteConfigToSharedMemory 将配置数据写入共享内存
|
|
// config: 要写入的配置数据
|
|
func WriteConfigToSharedMemory(config *models.ConfigData) error {
|
|
logger.Debug("Starting to write configuration to shared memory")
|
|
|
|
// 使用 unsafe.Alignof 获取对齐要求
|
|
align := unsafe.Alignof(*config)
|
|
size := unsafe.Sizeof(*config)
|
|
|
|
// 确保大小是对齐的
|
|
alignedSize := (size + align - 1) &^ (align - 1)
|
|
|
|
if alignedSize > constants.ShmSize {
|
|
return fmt.Errorf("config size %d exceeds shared memory size %d", alignedSize, constants.ShmSize)
|
|
}
|
|
|
|
// 创建共享内存
|
|
shmID, err := shmget(constants.ShmKey, int(alignedSize), unix.IPC_CREAT|0666)
|
|
if err != nil {
|
|
// 获取更详细的错误信息
|
|
switch err {
|
|
case unix.EACCES:
|
|
logger.Error("Permission denied: %v", err)
|
|
case unix.EEXIST:
|
|
logger.Error("Shared memory segment already exists: %v", err)
|
|
case unix.EINVAL:
|
|
logger.Error("Invalid size or key: %v", err)
|
|
case unix.ENOENT:
|
|
logger.Error("Shared memory segment does not exist: %v", err)
|
|
case unix.ENOMEM:
|
|
logger.Error("No memory available: %v", err)
|
|
default:
|
|
logger.Error("Unknown error: %v", err)
|
|
}
|
|
return fmt.Errorf("shmget failed: %w", err)
|
|
}
|
|
|
|
// 附加共享内存
|
|
shmPtr, err := shmat(shmID, 0, 0)
|
|
if err != nil {
|
|
return fmt.Errorf("shmat failed: %w", err)
|
|
}
|
|
defer shmdt(shmPtr)
|
|
|
|
// 使用内存屏障确保对齐
|
|
alignedPtr := unsafe.Pointer((uintptr(shmPtr) + align - 1) &^ (align - 1))
|
|
|
|
// 复制数据
|
|
*(*models.ConfigData)(alignedPtr) = *config
|
|
|
|
logger.Info("Configuration successfully written to shared memory")
|
|
return nil
|
|
}
|
|
|
|
// ReadConfigFromSharedMemory 从共享内存读取配置数据
|
|
func ReadConfigFromSharedMemory() (*models.ConfigData, error) {
|
|
logger.Debug("Starting to read configuration from shared memory")
|
|
|
|
// 获取共享内存段
|
|
shmID, err := shmget(constants.ShmKey, constants.ShmSize, unix.IPC_CREAT|0640)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("shmget failed: %w", err)
|
|
}
|
|
|
|
// 将共享内存段附加到进程地址空间(只读模式)
|
|
shmPtr, err := shmat(shmID, 0, unix.SHM_RDONLY)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("shmat failed: %w", err)
|
|
}
|
|
defer shmdt(shmPtr) // 确保在函数结束时分离共享内存
|
|
|
|
// 创建一个新的配置数据对象
|
|
config := new(models.ConfigData)
|
|
configSize := unsafe.Sizeof(*config)
|
|
if configSize > constants.ShmSize {
|
|
return nil, fmt.Errorf("configuration size (%d) exceeds shared memory size (%d)", configSize, constants.ShmSize)
|
|
}
|
|
|
|
// 从共享内存复制数据到配置对象
|
|
copy((*[constants.ShmSize]byte)(unsafe.Pointer(config))[:], (*[constants.ShmSize]byte)(shmPtr)[:])
|
|
|
|
logger.Info("Configuration successfully read from shared memory")
|
|
return config, nil
|
|
}
|