我正在阅读一些 Go 代码(来自 https://github.com/KarpelesLab/reflink),它使用
SyscallConn()
(在 *os.File
上定义的函数):
// reflinkInternal performs the actual reflink action without worrying about fallback
func reflinkInternal(d, s *os.File) error {
ss, err := s.SyscallConn()
if err != nil {
return err
}
sd, err := d.SyscallConn()
if err != nil {
return err
}
var err2, err3 error
err = sd.Control(func(dfd uintptr) {
err2 = ss.Control(func(sfd uintptr) {
// int ioctl(int dest_fd, FICLONE, int src_fd);
err3 = unix.IoctlFileClone(int(dfd), int(sfd))
})
})
if err != nil {
// sd.Control failed
return err
}
if err2 != nil {
// ss.Control failed
return err2
}
if err3 != nil && errors.Is(err3, unix.ENOTSUP) {
return ErrReflinkFailed
}
// err3 is ioctl() response
return err3
}
在此示例中,使用这些
Control()
函数而不是直接使用 d.Fd()
和 s.Fd()
有什么优势吗?更一般地说, func func (*os.File) SyscallConn() (syscall.RawConn, error)
有什么用?
file.Fd()
返回一个文件描述符,并且它使文件描述符在阻塞模式下运行(占用一个线程来进行阻塞操作)。 SyscallConn
不这样做。事实上,它是专门为了获取文件描述符而不使其阻塞而创建的。请参阅本期了解更多信息。