代码之家  ›  专栏  ›  技术社区  ›  Sigma

如何从golang正确导入

  •  1
  • Sigma  · 技术社区  · 7 年前

    raspberrypi's userspace 从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() 但我不确定,我该如何解决这个问题?

    1 回复  |  直到 7 年前
        1
  •  6
  •   David Maze    7 年前

    ioctl (2) 包装 "golang.org/x/sys/unix" . unix.IoctlSetInt 这可能满足你的需要。

    它看起来也像是将一个小内存缓冲区的控制权交给了内核。您需要小心这样做:Go垃圾收集器会释放它认为没有使用的内存对象,即使某些东西正在使用,它也可以移动它。内核将不知道这一点,并将继续使用旧指针。这个 unsafe.Pointer 在这个主题上,文档有相当多的内容可以说,即使是关于不太奇特的系统调用。我不知道有什么东西可以“锁定”内存中的Go对象,从而防止它被移动或释放(内存中没有跳出任何东西) runtime

    cgo 那个 malloc() 分配一个合适的缓冲区并将其交给ioctl。malloc的内存不会被垃圾收集,因此它不会移动或从您的下面释放;一些低级工具可能会认为这看起来像是内存泄漏(保留指针的旧值以便以后能够释放并避开它不是一个坏主意)。

        2
  •  3
  •   hartzell    6 年前

    你也可能会与这个细节发生冲突 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的指针,即使仅从类型来看,调用期间似乎不再需要该对象。

    要使编译器识别此模式,转换必须出现在参数列表中:

    // 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

    推荐文章