[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH v3 01/10] Add a generic reference counted virObject type



From: "Daniel P. Berrange" <berrange redhat com>

This introduces a fairly basic reference counted virObject type
and an associated virClass type, that use atomic operations for
ref counting.

In a global initializer (recommended to be invoked using the
virOnceInit API), a virClass type must be allocated for each
object type. This requires a class name, a "dispose" callback
which will be invoked to free memory associated with the object's
fields, and the size in bytes of the object struct.

eg,

   virClassPtr  connclass = virClassNew("virConnect",
                                        sizeof(virConnect),
                                        virConnectDispose);

The struct for the object, must include 'virObject' as its
first member

eg

  struct _virConnect {
    virObject object;

    virURIPtr uri;
  };

The 'dispose' callback is only responsible for freeing
fields in the object, not the object itself. eg a suitable
impl for the above struct would be

  void virConnectDispose(void *obj) {
     virConnectPtr conn = obj;
     virURIFree(conn->uri);
  }

There is no need to reset fields to 'NULL' or '0' in the
dispose callback, since the entire object will be memset
to 0, and the klass pointer & magic integer fields will
be poisoned with 0xDEADBEEF before being free()d

When creating an instance of an object, one needs simply
pass the virClassPtr eg

   virConnectPtr conn = virObjectNew(connclass);
   if (!conn)
      return NULL;
   conn->uri = virURIParse("foo:///bar")

Object references can be manipulated with

   virObjectRef(conn)
   virObjectUnref(conn)

The latter returns a true value, if the object has been
freed (ie its ref count hit zero)

Signed-off-by: Daniel P. Berrange <berrange redhat com>
---
 cfg.mk                   |    2 +
 src/Makefile.am          |    1 +
 src/libvirt_private.syms |   10 +++
 src/libvirt_probes.d     |    7 ++
 src/util/virobject.c     |  216 ++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virobject.h     |   60 +++++++++++++
 6 files changed, 296 insertions(+)
 create mode 100644 src/util/virobject.c
 create mode 100644 src/util/virobject.h

diff --git a/cfg.mk b/cfg.mk
index e2af2bb..ccff146 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -171,6 +171,8 @@ useless_free_options =				\
   --name=virNetworkObjFree			\
   --name=virNodeDeviceDefFree			\
   --name=virNodeDeviceObjFree			\
+  --name=virObjectUnref                         \
+  --name=virObjectFreeCallback                  \
   --name=virSecretDefFree			\
   --name=virStorageEncryptionFree		\
   --name=virStorageEncryptionSecretFree		\
diff --git a/src/Makefile.am b/src/Makefile.am
index 49bcf50..6ed4a41 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -85,6 +85,7 @@ UTIL_SOURCES =							\
 		util/virauthconfig.c util/virauthconfig.h	\
 		util/virfile.c util/virfile.h			\
 		util/virnodesuspend.c util/virnodesuspend.h	\
+		util/virobject.c util/virobject.h		\
 		util/virpidfile.c util/virpidfile.h		\
 		util/virtypedparam.c util/virtypedparam.h	\
 		util/xml.c util/xml.h				\
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 44b6652..9ed6a8d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1644,6 +1644,16 @@ nodeSuspendForDuration;
 virNodeSuspendGetTargetMask;
 
 
+# virobject.h
+virClassName;
+virClassNew;
+virObjectFreeCallback;
+virObjectIsClass;
+virObjectNew;
+virObjectRef;
+virObjectUnref;
+
+
 # virpidfile.h
 virPidFileAcquire;
 virPidFileAcquirePath;
diff --git a/src/libvirt_probes.d b/src/libvirt_probes.d
index 0dac8f3..ceb3caa 100644
--- a/src/libvirt_probes.d
+++ b/src/libvirt_probes.d
@@ -16,6 +16,13 @@ provider libvirt {
 	probe event_poll_run(int nfds, int timeout);
 
 
+        # file: src/util/virobject.c
+        # prefix: object
+        probe object_new(void *obj, const char *klassname);
+        probe object_ref(void *obj);
+        probe object_unref(void *obj);
+        probe object_dispose(void *obj);
+
 	# file: src/rpc/virnetsocket.c
 	# prefix: rpc
 	probe rpc_socket_new(void *sock, int refs, int fd, int errfd, pid_t pid, const char *localAddr, const char *remoteAddr);
diff --git a/src/util/virobject.c b/src/util/virobject.c
new file mode 100644
index 0000000..80a1f40
--- /dev/null
+++ b/src/util/virobject.c
@@ -0,0 +1,216 @@
+/*
+ * virobject.c: libvirt reference counted object
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include "virobject.h"
+#include "threads.h"
+#include "memory.h"
+#include "viratomic.h"
+#include "virterror_internal.h"
+#include "logging.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+static unsigned int magicCounter = 0xCAFE0000;
+
+struct _virClass {
+    unsigned int magic;
+    const char *name;
+    size_t objectSize;
+
+    virObjectDisposeCallback dispose;
+};
+
+
+/**
+ * virClassNew:
+ * @name: the class name
+ * @objectSize: total size of the object struct
+ * @dispose: callback to run to free object fields
+ *
+ * Register a new object class with @name. The @objectSize
+ * should give the total size of the object struct, which
+ * is expected to have a 'virObject object;' field as its
+ * first member. When the last reference on the object is
+ * released, the @dispose callback will be invoked to free
+ * memory of the object fields
+ *
+ * Returns a new class instance
+ */
+virClassPtr virClassNew(const char *name,
+                        size_t objectSize,
+                        virObjectDisposeCallback dispose)
+{
+    virClassPtr klass;
+
+    if (VIR_ALLOC(klass) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    if (!(klass->name = strdup(name)))
+        goto no_memory;
+    klass->magic = virAtomicIntInc(&magicCounter);
+    klass->objectSize = objectSize;
+    klass->dispose = dispose;
+
+    return klass;
+
+no_memory:
+    VIR_FREE(klass);
+    virReportOOMError();
+    return NULL;
+}
+
+
+/**
+ * virObjectNew:
+ * @klass: the klass of object to create
+ *
+ * Allocates a new object of type @klass. The returned
+ * object will be an instance of "virObjectPtr", which
+ * can be cast to the struct associated with @klass.
+ *
+ * The initial reference count of the object will be 1.
+ *
+ * Returns the new object
+ */
+void *virObjectNew(virClassPtr klass)
+{
+    virObjectPtr obj = NULL;
+    char *somebytes;
+
+    if (VIR_ALLOC_N(somebytes, klass->objectSize) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+    obj = (virObjectPtr)somebytes;
+
+    obj->magic = klass->magic;
+    obj->klass = klass;
+    virAtomicIntSet(&obj->refs, 1);
+
+    PROBE(OBJECT_NEW, "obj=%p classname=%s", obj, obj->klass->name);
+
+    return obj;
+}
+
+
+/**
+ * virObjectUnref:
+ * @anyobj: any instance of virObjectPtr
+ *
+ * Decrement the reference count on @anyobj and if
+ * it hits zero, runs the "dispose" callback associated
+ * with the object class and frees @anyobj.
+ *
+ * Returns true if the remaining reference count is
+ * non-zero, false if the object was disposed of
+ */
+bool virObjectUnref(void *anyobj)
+{
+    virObjectPtr obj = anyobj;
+
+    if (!obj)
+        return false;
+
+    bool lastRef = virAtomicIntDecAndTest(&obj->refs);
+    PROBE(OBJECT_UNREF, "obj=%p", obj);
+    if (lastRef) {
+        PROBE(OBJECT_DISPOSE, "obj=%p", obj);
+        if (obj->klass->dispose)
+            obj->klass->dispose(obj);
+
+        /* Clear & poison object */
+        memset(obj, 0, obj->klass->objectSize);
+        obj->magic = 0xDEADBEEF;
+        obj->klass = (void*)0xDEADBEEF;
+        VIR_FREE(obj);
+    }
+
+    return !lastRef;
+}
+
+
+/**
+ * virObjectRef:
+ * @anyobj: any instance of virObjectPtr
+ *
+ * Increment the reference count on @anyobj and return
+ * the same pointer
+ *
+ * Returns @anyobj
+ */
+void *virObjectRef(void *anyobj)
+{
+    virObjectPtr obj = anyobj;
+
+    if (!obj)
+        return NULL;
+    virAtomicIntInc(&obj->refs);
+    PROBE(OBJECT_REF, "obj=%p", obj);
+    return anyobj;
+}
+
+
+/**
+ * virObjectIsClass:
+ * @anyobj: any instance of virObjectPtr
+ * @klass: the class to check
+ *
+ * Checks whether @anyobj is an instance of
+ * @klass
+ *
+ * Returns true if @anyobj is an instance of @klass
+ */
+bool virObjectIsClass(void *anyobj,
+                      virClassPtr klass)
+{
+    virObjectPtr obj = anyobj;
+    return obj != NULL && (obj->magic == klass->magic) && (obj->klass == klass);
+}
+
+
+/**
+ * virClassName:
+ * @klass: the object class
+ *
+ * Returns the name of @klass
+ */
+const char *virClassName(virClassPtr klass)
+{
+    return klass->name;
+}
+
+
+/**
+ * virObjectFreeCallback:
+ * @opaque: a pointer to a virObject instance
+ *
+ * Provides identical functionality to virObjectUnref,
+ * but with the signature maching the virFreeCallback
+ * typedef.
+ */
+void virObjectFreeCallback(void *opaque)
+{
+    virObjectUnref(opaque);
+}
diff --git a/src/util/virobject.h b/src/util/virobject.h
new file mode 100644
index 0000000..2581cb5
--- /dev/null
+++ b/src/util/virobject.h
@@ -0,0 +1,60 @@
+/*
+ * virobject.h: libvirt reference counted object
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_OBJECT_H__
+# define __VIR_OBJECT_H__
+
+# include "internal.h"
+
+typedef struct _virClass virClass;
+typedef virClass *virClassPtr;
+
+typedef struct _virObject virObject;
+typedef virObject *virObjectPtr;
+
+typedef void (*virObjectDisposeCallback)(void *obj);
+
+struct _virObject {
+    unsigned int magic;
+    int refs;
+    virClassPtr klass;
+};
+
+virClassPtr virClassNew(const char *name,
+                        size_t objectSize,
+                        virObjectDisposeCallback dispose)
+    ATTRIBUTE_NONNULL(1);
+
+const char *virClassName(virClassPtr klass)
+    ATTRIBUTE_NONNULL(1);
+
+void *virObjectNew(virClassPtr klass)
+    ATTRIBUTE_NONNULL(1);
+bool virObjectUnref(void *obj);
+void *virObjectRef(void *obj);
+
+bool virObjectIsClass(void *obj,
+                      virClassPtr klass)
+    ATTRIBUTE_NONNULL(2);
+
+void virObjectFreeCallback(void *opaque);
+
+#endif /* __VIR_OBJECT_H */
-- 
1.7.10.4


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]