bash_go_service/config-loader/internal/shm/shm.go

112 lines
3.7 KiB
Go

package shm
import (
"fmt"
"unsafe"
"bash_go_service/config-loader/internal/constants"
"bash_go_service/config-loader/internal/models"
"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.DebugLogger.Println("Starting to write configuration to shared memory")
// 创建或获取共享内存段
shmID, err := shmget(constants.ShmKey, constants.ShmSize, unix.IPC_CREAT|0666)
if err != nil {
logger.ErrorLogger.Printf("shmget failed: %v", err)
return fmt.Errorf("shmget failed: %w", err)
}
// 将共享内存段附加到进程地址空间
shmPtr, err := shmat(shmID, 0, 0)
if err != nil {
logger.ErrorLogger.Printf("shmat failed: %v", err)
return fmt.Errorf("shmat failed: %w", err)
}
defer shmdt(shmPtr) // 确保在函数结束时分离共享内存
// 检查配置数据大小是否超过共享内存大小
configSize := unsafe.Sizeof(*config)
if configSize > constants.ShmSize {
return fmt.Errorf("configuration size (%d) exceeds shared memory size (%d)", configSize, constants.ShmSize)
}
// 将配置数据复制到共享内存
data := (*[constants.ShmSize]byte)(unsafe.Pointer(config))[:]
copy((*[constants.ShmSize]byte)(shmPtr)[:], data)
logger.InfoLogger.Println("Configuration successfully written to shared memory")
return nil
}
// ReadConfigFromSharedMemory 从共享内存读取配置数据
func ReadConfigFromSharedMemory() (*models.ConfigData, error) {
logger.DebugLogger.Println("Starting to read configuration from shared memory")
// 获取共享内存段
shmID, err := shmget(constants.ShmKey, constants.ShmSize, 0)
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.InfoLogger.Println("Configuration successfully read from shared memory")
return config, nil
}