virObject is the base struct that manages reference-counting for all structs that need the ability of reference-counting. virAtomic provides atomic operations which are thread-safe. --- src/Makefile.am | 2 + src/libvirt_private.syms | 11 ++++++ src/util/viratomic.c | 80 ++++++++++++++++++++++++++++++++++++++++++ src/util/viratomic.h | 32 +++++++++++++++++ src/util/virobject.c | 64 ++++++++++++++++++++++++++++++++++ src/util/virobject.h | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 275 insertions(+), 0 deletions(-) create mode 100644 src/util/viratomic.c create mode 100644 src/util/viratomic.h create mode 100644 src/util/virobject.c create mode 100644 src/util/virobject.h diff --git a/src/Makefile.am b/src/Makefile.am index dce866e..cb8acc3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -81,6 +81,8 @@ UTIL_SOURCES = \ util/util.c util/util.h \ util/xml.c util/xml.h \ util/virtaudit.c util/virtaudit.h \ + util/viratomic.c util/viratomic.h \ + util/virobject.c util/virobject.h \ util/virterror.c util/virterror_internal.h EXTRA_DIST += util/threads-pthread.c util/threads-win32.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 54e4482..a33e877 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -958,6 +958,17 @@ virUUIDGenerate; virUUIDParse; +# virobject.h +virObjectInit; +virObjectRef; +virObjectUnref; + + +# viratomic.h +virAtomicInc; +virAtomicDec; + + # virtaudit.h virAuditClose; virAuditEncode; diff --git a/src/util/viratomic.c b/src/util/viratomic.c new file mode 100644 index 0000000..c7bb44f --- /dev/null +++ b/src/util/viratomic.c @@ -0,0 +1,80 @@ +/* + * viratomic.c: atomic operations + * + * Copyright (C) 2011 Hu Tao + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Hu Tao <hutao@xxxxxxxxxxxxxx> + */ + +#include <config.h> + +#include "viratomic.h" + +#if defined(__GNUC__) + +long virAtomicInc(long *value) +{ + return __sync_add_and_fetch(value, 1); +} + +long virAtomicDec(long *value) +{ + return __sync_sub_and_fetch(value, 1); +} + +#elif defined(WIN32) + +long virAtomicInc(long *value) +{ + return InterlockedIncrement(value); +} + +long virAtomicDec(long *value) +{ + return InterlockedDecrement(value); +} + +#else + +#include "threads.h" + +static virMutex virAtomicLock = VIR_MUTEX_INITIALIZER; + +long virAtomicInc(long *value) +{ + long result; + virMutexLock(&virAtomicLock); + *value += 1; + result = *value; + virMutexUnlock(&virAtomicLock); + + return result; +} + +long virAtomicDec(long *value) +{ + long result; + virMutexLock(&virAtomicLock); + *value -= 1; + result = *value; + virMutexUnlock(&virAtomicLock); + + return result; +} + +#endif diff --git a/src/util/viratomic.h b/src/util/viratomic.h new file mode 100644 index 0000000..2b40c77 --- /dev/null +++ b/src/util/viratomic.h @@ -0,0 +1,32 @@ +/* + * viratomic.h: atomic operations + * + * Copyright (C) 2011 Hu Tao + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Hu Tao <hutao@xxxxxxxxxxxxxx> + */ + +#ifndef __VIR_ATOMIC_H +#define __VIR_ATOMIC_H + +#include "internal.h" + +long virAtomicInc(long *value) ATTRIBUTE_NONNULL(1); +long virAtomicDec(long *value) ATTRIBUTE_NONNULL(1); + +#endif /* __VIR_ATOMIC_H */ diff --git a/src/util/virobject.c b/src/util/virobject.c new file mode 100644 index 0000000..0af53e9 --- /dev/null +++ b/src/util/virobject.c @@ -0,0 +1,64 @@ +/* + * virobject.c: base object that manages reference-counting + * + * Copyright (C) 2011 Hu Tao + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Hu Tao <hutao@xxxxxxxxxxxxxx> + */ + +#include <stdlib.h> + +#include "viratomic.h" +#include "virobject.h" +#include "logging.h" + +int virObjectInit(virObjectPtr obj, virObjectFree f) +{ + if (obj->free) { + /* This means the obj is already initialized. A second + * initialization will destroy ref field, which is bad. + */ + VIR_ERROR("Object %p is already initialized.", obj); + return -1; + } + + if (!f) { + VIR_ERROR0("virObjectFree method is required."); + abort(); + } + + obj->ref = 1; + obj->free = f; + + return 0; +} + +void virObjectRef(virObjectPtr obj) +{ + if (virAtomicInc(&obj->ref) < 2) + abort(); /* BUG if we get here */ +} + +void virObjectUnref(virObjectPtr obj) +{ + long ref = virAtomicDec(&obj->ref); + if (ref == 0) + obj->free(obj); + else if (ref < 0) + abort(); /* BUG if we get here */ +} diff --git a/src/util/virobject.h b/src/util/virobject.h new file mode 100644 index 0000000..a9d3d35 --- /dev/null +++ b/src/util/virobject.h @@ -0,0 +1,86 @@ +/* + * virobject.h: base object that manages reference-counting + * + * Copyright (C) 2011 Hu Tao + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Hu Tao <hutao@xxxxxxxxxxxxxx> + */ + +#ifndef __VIR_OBJECT_H +#define __VIR_OBJECT_H + +typedef struct _virObject virObject; +typedef virObject *virObjectPtr; + +typedef void (*virObjectFree)(virObjectPtr obj); + +/* A thread owns a virObject by incrementing its reference-count by 1. + * If a thread owns a virObject, the virObject is guarenteed not be + * freed until the thread releases ownership by decrementing its + * reference-count by 1. A thread can't access a virObject after it + * releases the ownership of virObject because it can be freed at + * anytime. + * + * A thread can own a virObject legally in these ways: + * + * - a thread owns a virObject that it creates. + * - a thread owns a virObject if another thread passes the ownership + * to it. Example: qemuMonitorOpen + * - a thread gets a virObject from a container. + * Example: virDomainFindByUUID + * - a container owns a virObject by incrementing its reference-count + * by 1 before adding it to the container + * - if a virObject is removed from a container its reference-count + * must be decremented by 1 + */ +/* + * Usage of virObject: + * + * 1. embed virObject into your struct as the first member. + * + * struct foo { + * virObject obj; // must be the first member + * ... + * } + * + * 2. call virObjectInit(obj, fooFree) in your struct's initialization + * function. fooFree is the free method which be called automatically + * when the ref count becomes 0. + * + * 3. implement two functions to ref/unref your struct like this: + * + * void FooRef(struct foo *f) + * { + * virObjectRef(f->obj); + * } + * + * void FooUnref(struct foo *f) + * { + * virObjectUnref(f->obj); + * } + */ +struct _virObject { + long ref; + virObjectFree free; +}; + +int virObjectInit(virObjectPtr obj, virObjectFree f); +void virObjectRef(virObjectPtr obj); +void virObjectUnref(virObjectPtr obj); + +#endif /* __VIR_OBJECT_H */ -- 1.7.3.1 -- Thanks, Hu Tao -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list