简体   繁体   English

syscall GetLastError()不返回错误

[英]syscall GetLastError() doesn't return error

In golang syscall.GetLastError() doesn't return the last error. 在golang中, syscall.GetLastError()不返回上一个错误。 See the following example 请参阅以下示例

if handle := _OpenSCManager(machineNamePtr, databaseNamePtr, desiredAccess); handle == nil {
    if err := syscall.GetLastError(); err != nil {
        return InvalidServiceDatabaseHandleHandle, ServiceErrno(err.(syscall.Errno))
    }
}

err is always nil . err永远是nil Assume machineNamePtr is a non exsiting machine. 假设machineNamePtr是不存在的计算机。 Tested the same code with c++ and GetLastError() throws RPC server is not available . 使用c ++测试了相同的代码,并且GetLastError()引发RPC server is not available So why not on go ? 那么,为什么不go呢?

EDIT 编辑

_OpenSCManager is generated with go generate . _OpenSCManager是通过go generate //sys _OpenSCManager(machineName *uint16, databaseName *uint16, desiredAcces ServiceAccessRight) (handle ServiceDatabaseHandle) = advapi32.OpenSCManagerW

func _OpenSCManager(machineName *uint16, databaseName *uint16, desiredAcces ServiceAccessRight) (handle ServiceDatabaseHandle) {
r0, _, _ := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(desiredAcces))
handle = ServiceDatabaseHandle(r0)
return

} }

So finally i've got this working. 所以终于我有了这个工作。 First i have tried to return an error variable with the following signature //sys _OpenSCManager(machineName *uint16, databaseName *uint16, desiredAcces ServiceAccessRight) (handle ServiceDatabaseHandle, lasterror error) = advapi32.OpenSCManagerW . 首先,我尝试返回具有以下签名的错误变量//sys _OpenSCManager(machineName *uint16, databaseName *uint16, desiredAcces ServiceAccessRight) (handle ServiceDatabaseHandle, lasterror error) = advapi32.OpenSCManagerW But go generate throws always Only last windows error is allowed as second return value... . 但是总是go generate抛出异常。 Only last windows error is allowed as second return value... But if you change it to //sys ... (handle ServiceDatabaseHandle, err error) = advapi32.OpenSCManagerW it successfully generates the code. 但是,如果将其更改为//sys ... (handle ServiceDatabaseHandle, err error) = advapi32.OpenSCManagerW它将成功生成代码。 So you explicit have to write err error . 因此,您必须显式地编写err error Someone knows why? 有人知道为什么吗? So now the function looks like 所以现在函数看起来像

func _OpenSCManager(machineName *uint16, databaseName *uint16, desiredAcces ServiceAccessRight) (handle ServiceDatabaseHandle, err error) {
r0, _, e1 := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(desiredAcces))
handle = ServiceDatabaseHandle(r0)
if handle == 0 {
    if e1 != 0 {
        err = errnoErr(e1)
    } else {
        err = syscall.EINVAL
    }
}
return
}

and it returns an error. 它返回一个错误。 So there is no need to call GetLastError() . 因此,无需调用GetLastError()

IIUC, the syscall.Syscall() on Windows automatically and atomically calls GetLastError() after the actual syscall finishes. IIUC,Windows上的syscall.Syscall()在实际的系统调用完成后自动自动调用GetLastError() That should be understandable once you consider that as soon as a goroutine exits from a syscall, the Go runtime scheduler is free to preempt it and run another goroutine on the very thread the just-preempted goroutine had just been running on. 一旦您考虑到goroutine从系统调用中退出,Go运行时调度程序就可以随意抢占它并在刚被抢占的goroutine运行于其上的线程上运行另一个goroutine,这应该是可以理解的

Since GetLastError() accesses per-thread state, if the second goroutine makes another syscall, it would likely thrash that last error value, so in the context of Go, each syscall should be accompanied with the following call to GetLastError() done in the context of a single syscall invocation — as seen from the Go side. 由于GetLastError()访问每个线程状态,因此,如果第二个goroutine进行了另一个系统调用,则可能会破坏该最后一个错误值,因此在Go的上下文中,每个系统调用都应伴随以下对GetLastError()调用:单个syscall调用的上下文-从Go端看。

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

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