繁体   English   中英

如何从golang正确地进行IOCTL

[英]How to IOCTL properly from golang

我试图将raspberrypi 的用户空间代码从C移植到golang,并且遇到了涉及ioctl()的程序。

我在遵循以下C代码时遇到了麻烦

#define MAJOR_NUM 100
#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
static int mbox_property(int file_desc, void *buf){

   int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf);
   return ret_val;
}

而我与此等效的是

func mBoxProperty(f *os.File, buf [256]int64) {
        err := Ioctl(f.Fd(), IOWR(100, 0, 8), uintptr(unsafe.Pointer(&buf[0])))

        if err != nil {
                log.Fatalln("mBoxProperty() : ", err)
        }

}

func Ioctl(fd, op, arg uintptr) error {
        _, _, ep := syscall.Syscall(syscall.SYS_IOCTL, fd, op, arg)
        if ep != 0 {
                return syscall.Errno(ep)
        }
        return nil
}

func IOWR(t, nr, size uintptr) uintptr {
        return IOC(IocRead|IocWrite, t, nr, size)
}
func IOC(dir, t, nr, size uintptr) uintptr {
        return (dir << IocDirshift) | (t << IocTypeshift) | (nr << IocNrshift) | (size << IocSizeshift)
}

但是每当我运行此命令时,我都会得到invalid argument错误,我认为这可能是由于我如何调用IOCTL()而引起的,但是我不确定,如何解决此问题?

"golang.org/x/sys/unix"ioctl (2)包装器。 unix.IoctlSetInt可能会满足您的需求。

看起来您正在将控制权从较小的内存缓冲区移交给内核。 您需要注意以下几点:Go垃圾回收器释放了它认为未使用的内存对象,即使正在使用某些东西,它也可以将其移动。 内核对此一无所知,并将继续使用旧指针。 unsafe.Pointer文档在这个主题上有很多话要说,即使涉及较少的外来系统调用也是如此。 我不知道有什么可以“锁定”内存中的Go对象的方法,以防止它被移动或释放(例如,在runtime程序包中什么都不会跳出来)。

您可能考虑使用cgo编写一个非常小的扩展, malloc()编译了一个适当的缓冲区并将其交给ioctl。 malloc的内存不会被垃圾收集,因此不会移动或从您的身下释放; 一些低级的工具可能会认为这看起来像是内存泄漏(保留指针的旧值以便以后释放它并躲避它并不是一个坏主意)。

您可能还不了解uintpr(unsafe.Pointer(...)) 在调用 syscall.Syscall需要发生的细节。

以下是详细信息,来自https://golang.org/pkg/unsafe/#Pointer

(4)调用syscall.Syscall时将指针转换为uintptr。

软件包syscall中的Syscall函数将其uintptr参数直接传递给操作系统,然后,操作系统可以根据调用的详细信息将其中一些参数重新解释为指针。 也就是说,系统调用实现正在将某些参数从uintptr隐式转换回指针。

如果必须将指针参数转换为uintptr用作参数,则该转换必须出现在调用表达式本身中:

 syscall.Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(n)) 

编译器通过安排所引用的分配对象(如果有的话)被保留并且直到调用完成才移动,即使从类型本身开始,也处理在汇编中实现的函数的调用的参数列表中转换为uintptr的Pointer。似乎在调用过程中不再需要该对象。

为了使编译器能够识别这种模式,转换必须出现在参数列表中:

 // INVALID: uintptr cannot be stored in variable // before implicit conversion back to Pointer during system call. u := uintptr(unsafe.Pointer(p)) syscall.Syscall(SYS_READ, uintptr(fd), u, uintptr(n)) 

这种unsafe使用方法可以使您“锁定” Dave Maze在上面寻找的Go对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM