[libvirt] [go PATCH 32/37] qemu: fix error reporting thread safety

Daniel P. Berrangé berrange at redhat.com
Mon Jul 16 13:24:18 UTC 2018


Create wrapper functions for each qemu C API that accepts a
virErrorPtr parameter. This avoids accessing a thread local from a
goroutine which may race with other goroutines doing native API calls in
the same OS thread.

Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
---
 qemu.go         | 31 ++++++++++---------
 qemu_wrapper.go | 79 ++++++++++++++++++++++++++++++++++++++++++++-----
 qemu_wrapper.h  | 33 +++++++++++++++++----
 3 files changed, 115 insertions(+), 28 deletions(-)

diff --git a/qemu.go b/qemu.go
index 3631b00..dd4f258 100644
--- a/qemu.go
+++ b/qemu.go
@@ -81,10 +81,11 @@ func (d *Domain) QemuMonitorCommand(command string, flags DomainQemuMonitorComma
 	var cResult *C.char
 	cCommand := C.CString(command)
 	defer C.free(unsafe.Pointer(cCommand))
-	result := C.virDomainQemuMonitorCommand(d.ptr, cCommand, &cResult, C.uint(flags))
+	var err C.virError
+	result := C.virDomainQemuMonitorCommandWrapper(d.ptr, cCommand, &cResult, C.uint(flags), &err)
 
 	if result != 0 {
-		return "", GetLastError()
+		return "", makeError(&err)
 	}
 
 	rstring := C.GoString(cResult)
@@ -95,10 +96,11 @@ func (d *Domain) QemuMonitorCommand(command string, flags DomainQemuMonitorComma
 func (d *Domain) QemuAgentCommand(command string, timeout DomainQemuAgentCommandTimeout, flags uint32) (string, error) {
 	cCommand := C.CString(command)
 	defer C.free(unsafe.Pointer(cCommand))
-	result := C.virDomainQemuAgentCommand(d.ptr, cCommand, C.int(timeout), C.uint(flags))
+	var err C.virError
+	result := C.virDomainQemuAgentCommandWrapper(d.ptr, cCommand, C.int(timeout), C.uint(flags), &err)
 
 	if result == nil {
-		return "", GetLastError()
+		return "", makeError(&err)
 	}
 
 	rstring := C.GoString(result)
@@ -107,10 +109,10 @@ func (d *Domain) QemuAgentCommand(command string, timeout DomainQemuAgentCommand
 }
 
 func (c *Connect) DomainQemuAttach(pid uint32, flags uint32) (*Domain, error) {
-
-	ptr := C.virDomainQemuAttach(c.ptr, C.uint(pid), C.uint(flags))
+	var err C.virError
+	ptr := C.virDomainQemuAttachWrapper(c.ptr, C.uint(pid), C.uint(flags), &err)
 	if ptr == nil {
-		return nil, GetLastError()
+		return nil, makeError(&err)
 	}
 	return &Domain{ptr: ptr}, nil
 }
@@ -156,19 +158,18 @@ func (c *Connect) DomainQemuMonitorEventRegister(dom *Domain, event string, call
 	defer C.free(unsafe.Pointer(cEvent))
 	goCallBackId := registerCallbackId(callback)
 
-	callbackPtr := unsafe.Pointer(C.domainQemuMonitorEventCallbackHelper)
 	var cdom C.virDomainPtr
 	if dom != nil {
 		cdom = dom.ptr
 	}
+	var err C.virError
 	ret := C.virConnectDomainQemuMonitorEventRegisterWrapper(c.ptr, cdom,
 		cEvent,
-		C.virConnectDomainQemuMonitorEventCallback(callbackPtr),
 		C.long(goCallBackId),
-		C.uint(flags))
-	if ret == -1 {
+		C.uint(flags), &err)
+	if ret < 0 {
 		freeCallbackId(goCallBackId)
-		return 0, GetLastError()
+		return 0, makeError(&err)
 	}
 	return int(ret), nil
 }
@@ -179,8 +180,10 @@ func (c *Connect) DomainQemuEventDeregister(callbackId int) error {
 	}
 
 	// Deregister the callback
-	if i := int(C.virConnectDomainQemuMonitorEventDeregisterWrapper(c.ptr, C.int(callbackId))); i != 0 {
-		return GetLastError()
+	var err C.virError
+	ret := int(C.virConnectDomainQemuMonitorEventDeregisterWrapper(c.ptr, C.int(callbackId), &err))
+	if ret < 0 {
+		return makeError(&err)
 	}
 	return nil
 }
diff --git a/qemu_wrapper.go b/qemu_wrapper.go
index 1dda84d..20089d2 100644
--- a/qemu_wrapper.go
+++ b/qemu_wrapper.go
@@ -45,26 +45,89 @@ void domainQemuMonitorEventCallbackHelper(virConnectPtr c, virDomainPtr d,
     domainQemuMonitorEventCallback(c, d, event, secs, micros, details, (int)(intptr_t)data);
 }
 
-int virConnectDomainQemuMonitorEventRegisterWrapper(virConnectPtr c,  virDomainPtr d,
-                                                    const char *event, virConnectDomainQemuMonitorEventCallback cb,
-                                                    long goCallbackId, unsigned int flags) {
+
+int
+virConnectDomainQemuMonitorEventDeregisterWrapper(virConnectPtr conn,
+                                                  int callbackID,
+                                                  virErrorPtr err)
+{
 #if LIBVIR_VERSION_NUMBER < 1002003
     assert(0); // Caller should have checked version
 #else
-    void* id = (void*)goCallbackId;
-    return virConnectDomainQemuMonitorEventRegister(c, d, event, cb, id, freeGoCallbackHelper, flags);
+    int ret = virConnectDomainQemuMonitorEventDeregister(conn, callbackID);
+    if (ret < 0) {
+        virCopyLastError(err);
+    }
+    return ret;
 #endif
 }
 
-int virConnectDomainQemuMonitorEventDeregisterWrapper(virConnectPtr conn,
-						     int callbackID)
+
+int
+virConnectDomainQemuMonitorEventRegisterWrapper(virConnectPtr conn,
+                                                virDomainPtr dom,
+                                                const char *event,
+                                                long goCallbackId,
+                                                unsigned int flags,
+                                                virErrorPtr err)
 {
 #if LIBVIR_VERSION_NUMBER < 1002003
     assert(0); // Caller should have checked version
 #else
-    return virConnectDomainQemuMonitorEventDeregister(conn, callbackID);
+    void *id = (void*)goCallbackId;
+    int ret = virConnectDomainQemuMonitorEventRegister(conn, dom, event, domainQemuMonitorEventCallbackHelper,
+                                                       id, freeGoCallbackHelper, flags);
+    if (ret < 0) {
+        virCopyLastError(err);
+    }
+    return ret;
 #endif
 }
 
+
+char *
+virDomainQemuAgentCommandWrapper(virDomainPtr domain,
+                                 const char *cmd,
+                                 int timeout,
+                                 unsigned int flags,
+                                 virErrorPtr err)
+{
+    char * ret = virDomainQemuAgentCommand(domain, cmd, timeout, flags);
+    if (!ret) {
+        virCopyLastError(err);
+    }
+    return ret;
+}
+
+
+virDomainPtr
+virDomainQemuAttachWrapper(virConnectPtr conn,
+                           unsigned int pid_value,
+                           unsigned int flags,
+                           virErrorPtr err)
+{
+    virDomainPtr ret = virDomainQemuAttach(conn, pid_value, flags);
+    if (!ret) {
+        virCopyLastError(err);
+    }
+    return ret;
+}
+
+
+int
+virDomainQemuMonitorCommandWrapper(virDomainPtr domain,
+                                   const char *cmd,
+                                   char **result,
+                                   unsigned int flags,
+                                   virErrorPtr err)
+{
+    int ret = virDomainQemuMonitorCommand(domain, cmd, result, flags);
+    if (ret < 0) {
+        virCopyLastError(err);
+    }
+    return ret;
+}
+
+
 */
 import "C"
diff --git a/qemu_wrapper.h b/qemu_wrapper.h
index e365fbd..df389c4 100644
--- a/qemu_wrapper.h
+++ b/qemu_wrapper.h
@@ -42,16 +42,37 @@ domainQemuMonitorEventCallbackHelper(virConnectPtr c,
                                      void *data);
 
 int
-virConnectDomainQemuMonitorEventRegisterWrapper(virConnectPtr c,
-                                                virDomainPtr d,
+virConnectDomainQemuMonitorEventDeregisterWrapper(virConnectPtr conn,
+                                                  int callbackID,
+                                                  virErrorPtr err);
+
+int
+virConnectDomainQemuMonitorEventRegisterWrapper(virConnectPtr conn,
+                                                virDomainPtr dom,
                                                 const char *event,
-                                                virConnectDomainQemuMonitorEventCallback cb,
                                                 long goCallbackId,
-                                                unsigned int flags);
+                                                unsigned int flags,
+                                                virErrorPtr err);
+
+char *
+virDomainQemuAgentCommandWrapper(virDomainPtr domain,
+                                 const char *cmd,
+                                 int timeout,
+                                 unsigned int flags,
+                                 virErrorPtr err);
+
+virDomainPtr
+virDomainQemuAttachWrapper(virConnectPtr conn,
+                           unsigned int pid_value,
+                           unsigned int flags,
+                           virErrorPtr err);
 
 int
-virConnectDomainQemuMonitorEventDeregisterWrapper(virConnectPtr conn,
-                                                  int callbackID);
+virDomainQemuMonitorCommandWrapper(virDomainPtr domain,
+                                   const char *cmd,
+                                   char **result,
+                                   unsigned int flags,
+                                   virErrorPtr err);
 
 
 #endif /* LIBVIRT_GO_DOMAIN_EVENTS_WRAPPER_H__ */
-- 
2.17.1




More information about the libvir-list mailing list