英文:
errno to Go errors
问题
我正在尝试从Go代码中发出KVM ioctls。目前我有以下代码:
func (vm *Vm) RegisterIrqFd(efd *EventFd, gsi uint32) error {
irqfd := (*C.struct_kvm_irqfd)(C.calloc(1, C.sizeof_struct_kvm_irqfd))
defer C.free(unsafe.Pointer(irqfd))
irqfd.fd = C.uint(efd.Fd())
irqfd.gsi = C.uint(gsi)
if _, err := sysutils.Ioctl(vm.Fd(), C.KVM_IRQFD, uintptr(unsafe.Pointer(irqfd))); err != nil {
return fmt.Errorf("RegisterIrqFd failed: %v", err)
}
return nil
}
Ioctl函数的实现如下:
func Ioctl(fd uintptr, cmd C.uint, arg uintptr) (uintptr, error) {
ret, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
fd,
uintptr(cmd),
uintptr(arg),
)
if int64(ret) == -1 {
return ret, ErrnoToErr(errno)
}
return ret, nil
}
ErrnoToErr函数的实现如下:
func ErrnoToErr(errno syscall.Errno) error {
return fmt.Errorf("%v", errno.Error())
}
- 在GetSupportedCpuid函数中,ioctl的参数
cpuid
是使用C.calloc
分配的。如果这是C代码,cpuid
可以直接在堆栈上分配。有没有办法避免使用calloc并且不使用free?有没有更符合惯用法的替代方法? - 是否有办法让ErrnoToErr返回与errno对应的Go错误类型?目前它使用syscall/syscall_unix.go中的
(e Errno) Error()
,因此它只是解引用字符串列表并返回字符串。如果我能够使用类型,那么在单元测试中就可以测试特定的错误了。
英文:
I'm trying to issue KVM ioctls from Go code. At the moment I have something as follows:
func (vm *Vm) RegisterIrqFd(efd *EventFd, gsi uint32) error {
irqfd := (*C.struct_kvm_irqfd)(C.calloc(1, C.sizeof_struct_kvm_irqfd))
defer C.free(unsafe.Pointer(irqfd))
irqfd.fd = C.uint(efd.Fd())
irqfd.gsi = C.uint(gsi)
if _, err := sysutils.Ioctl(vm.Fd(), C.KVM_IRQFD, uintptr(unsafe.Pointer(irqfd))); err != nil {
return fmt.Errorf("RegisterIrqFd failed: %v", err)
}
return nil
}
The Ioctl function is implemented as follows :
func Ioctl(fd uintptr, cmd C.uint, arg uintptr) (uintptr, error) {
ret, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
fd,
uintptr(cmd),
uintptr(arg),
)
if int64(ret) == -1 {
return ret, ErrnoToErr(errno)
}
return ret, nil
}
And the ErrnoToErr function is implemented as follows :
func ErrnoToErr(errno syscall.Errno) error {
return fmt.Errorf("%v", errno.Error())
}
- Inside GetSupportedCpuid, the argument for the ioctl,
cpuid
is allocated usingC.calloc
. If this were C codecpuid
could just be allocated on the stack. Is there any way I can get around allocating using calloc and using free? Any alternatives that would be more idiomatic? - Would there be a way to have ErrnoToErr return a go error type corresponding to the errno? Currently it uses the
(e Errno) Error()
inside syscall/syscall_unix.go; so it just dereferences a list of strings and returns the string. It would be nice to have a type, so that I can test for specific errors in my unit tests.
答案1
得分: 1
回复更新的示例,我们可以这样做:
func (vm *Vm) RegisterIrqFd(efd *EventFd, gsi uint32) error {
irqfd := C.struct_kvm_irqfd{}
irqfd.fd = C.uint(efd.Fd())
irqfd.gsi = C.uint(gsi)
if _, err := sysutils.Ioctl(vm.Fd(), C.KVM_IRQFD, uintptr(unsafe.Pointer(&irqfd))); err != nil {
return fmt.Errorf("RegisterIrqFd failed: %v", err)
}
return nil
}
我认为这是安全的,但我们可能会发现irqfd escapes to heap
,因为我们在这里取了它的地址,如果是这样的话,就没有太多的节省空间了。即便如此,只要这不违反Go指针规则(我认为不会),这样写起来会更好看。
英文:
Replying just to the updated example, we could do this:
func (vm *Vm) RegisterIrqFd(efd *EventFd, gsi uint32) error {
irqfd := C.struct_kvm_irqfd{}
irqfd.fd = C.uint(efd.Fd())
irqfd.gsi = C.uint(gsi)
if _, err := sysutils.Ioctl(vm.Fd(), C.KVM_IRQFD, uintptr(unsafe.Pointer(&irqfd))); err != nil {
return fmt.Errorf("RegisterIrqFd failed: %v", err)
}
return nil
}
I think this is safe, but we might find that irqfd escapes to heap
anyway since we take its address here, in which case there's not much savings. Even so, as long as this doesn't violate Go pointer rules (I don't think it does) it's a lot nicer to read.
答案2
得分: -1
阅读文档 syscall.Errno
因此,可以像这样执行转换
func ErrnoToErr(errno syscall.Errno) error {
if errno != 0 {
return errno
}
return nil
}
对于相等性,它只说明
可以使用 errors.Is 将 Errno 值与来自 os 包的错误值进行比较。
有关比较错误的问题已经在这里考虑过 How to compare Go errors
英文:
Read the documentation syscall.Errno
So convertion may be performed like this
func ErrnoToErr(errno syscall.Errno) error {
if errno != 0 {
return errno
}
return nil
}
For equality it only states
> Errno values can be tested against error values from the os package
> using errors.Is.
The question of comparing errors was already considered here How to compare Go errors
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论