1 /*
2  * virobject.c: libvirt reference counted object
3  *
4  * Copyright (C) 2012-2014 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see
18  * <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include <config.h>
23 
24 #define VIR_PARENT_REQUIRED /* empty, to allow virObject to have no parent */
25 #include "virobject.h"
26 #include "virthread.h"
27 #include "viralloc.h"
28 #include "virerror.h"
29 #include "virlog.h"
30 #include "virprobe.h"
31 #include "virstring.h"
32 
33 #define VIR_FROM_THIS VIR_FROM_NONE
34 
35 VIR_LOG_INIT("util.object");
36 
37 static unsigned int magicCounter = 0xCAFE0000;
38 
39 struct _virClass {
40     virClass *parent;
41 
42     GType type;
43     unsigned int magic;
44     char *name;
45     size_t objectSize;
46 
47     virObjectDisposeCallback dispose;
48 };
49 
50 typedef struct _virObjectPrivate virObjectPrivate;
51 struct _virObjectPrivate {
52     virClass *klass;
53 };
54 
55 
56 G_DEFINE_TYPE_WITH_PRIVATE(virObject, vir_object, G_TYPE_OBJECT)
57 
58 #define VIR_OBJECT_NOTVALID(obj) (!obj || !VIR_IS_OBJECT(obj))
59 
60 #define VIR_OBJECT_USAGE_PRINT_WARNING(anyobj, objclass) \
61     do { \
62         virObject *obj = anyobj; \
63         if (!obj) \
64             VIR_WARN("Object cannot be NULL"); \
65         if (VIR_OBJECT_NOTVALID(obj)) \
66             VIR_WARN("Object %p (%s) is not a %s instance", \
67                      anyobj, g_type_name_from_instance((void*)anyobj), #objclass); \
68     } while (0)
69 
70 
71 static virClass *virObjectClassImpl;
72 static virClass *virObjectLockableClass;
73 static virClass *virObjectRWLockableClass;
74 
75 static void virObjectLockableDispose(void *anyobj);
76 static void virObjectRWLockableDispose(void *anyobj);
77 
78 static int
virObjectOnceInit(void)79 virObjectOnceInit(void)
80 {
81     if (!(virObjectClassImpl = virClassNew(NULL,
82                                            "virObject",
83                                            sizeof(virObject),
84                                            0,
85                                            NULL)))
86         return -1;
87 
88     if (!VIR_CLASS_NEW(virObjectLockable, virObjectClassImpl))
89         return -1;
90 
91     if (!VIR_CLASS_NEW(virObjectRWLockable, virObjectClassImpl))
92         return -1;
93 
94     return 0;
95 }
96 
97 VIR_ONCE_GLOBAL_INIT(virObject);
98 
99 
100 /**
101  * virClassForObject:
102  *
103  * Returns the class instance for the base virObject type
104  */
105 virClass *
virClassForObject(void)106 virClassForObject(void)
107 {
108     if (virObjectInitialize() < 0)
109         return NULL;
110 
111     return virObjectClassImpl;
112 }
113 
114 
115 /**
116  * virClassForObjectLockable:
117  *
118  * Returns the class instance for the virObjectLockable type
119  */
120 virClass *
virClassForObjectLockable(void)121 virClassForObjectLockable(void)
122 {
123     if (virObjectInitialize() < 0)
124         return NULL;
125 
126     return virObjectLockableClass;
127 }
128 
129 
130 /**
131  * virClassForObjectRWLockable:
132  *
133  * Returns the class instance for the virObjectRWLockable type
134  */
135 virClass *
virClassForObjectRWLockable(void)136 virClassForObjectRWLockable(void)
137 {
138     if (virObjectInitialize() < 0)
139         return NULL;
140 
141     return virObjectRWLockableClass;
142 }
143 
144 
virClassDummyInit(void * klass G_GNUC_UNUSED)145 static void virClassDummyInit(void *klass G_GNUC_UNUSED)
146 {
147 }
148 
virObjectDummyInit(void * obj G_GNUC_UNUSED)149 static void virObjectDummyInit(void *obj G_GNUC_UNUSED)
150 {
151 }
152 
153 /**
154  * virClassNew:
155  * @parent: the parent class
156  * @name: the class name
157  * @objectSize: total size of the object struct
158  * @dispose: callback to run to free object fields
159  *
160  * Register a new object class with @name. The @objectSize
161  * should give the total size of the object struct, which
162  * is expected to have a 'virObject parent;' field as (or
163  * contained in) its first member. When the last reference
164  * on the object is released, the @dispose callback will be
165  * invoked to free memory of the local object fields, as
166  * well as the dispose callbacks of the parent classes.
167  *
168  * Returns a new class instance
169  */
170 virClass *
virClassNew(virClass * parent,const char * name,size_t objectSize,size_t parentSize,virObjectDisposeCallback dispose)171 virClassNew(virClass *parent,
172             const char *name,
173             size_t objectSize,
174             size_t parentSize,
175             virObjectDisposeCallback dispose)
176 {
177     virClass *klass;
178 
179     if (parent == NULL &&
180         STRNEQ(name, "virObject")) {
181         virReportInvalidNonNullArg(parent);
182         return NULL;
183     } else if (objectSize <= parentSize ||
184                parentSize != (parent ? parent->objectSize : 0)) {
185         virReportInvalidArg(objectSize,
186                             _("object size %zu of %s is not larger than parent class %zu"),
187                             objectSize, name, parent->objectSize);
188         return NULL;
189     }
190 
191     klass = g_new0(virClass, 1);
192     klass->parent = parent;
193     klass->magic = g_atomic_int_add(&magicCounter, 1);
194     klass->name = g_strdup(name);
195     klass->objectSize = objectSize;
196     if (parent == NULL) {
197         klass->type = vir_object_get_type();
198     } else {
199         klass->type =
200             g_type_register_static_simple(parent->type,
201                                           name,
202                                           sizeof(virObjectClass),
203                                           (GClassInitFunc)virClassDummyInit,
204                                           objectSize,
205                                           (GInstanceInitFunc)virObjectDummyInit,
206                                           0);
207     }
208     klass->dispose = dispose;
209 
210     return klass;
211 }
212 
213 
214 /**
215  * virClassIsDerivedFrom:
216  * @klass: the klass to check
217  * @parent: the possible parent class
218  *
219  * Determine if @klass is derived from @parent
220  *
221  * Return true if @klass is derived from @parent, false otherwise
222  */
223 bool
virClassIsDerivedFrom(virClass * klass,virClass * parent)224 virClassIsDerivedFrom(virClass *klass,
225                       virClass *parent)
226 {
227     while (klass) {
228         if (klass->magic == parent->magic)
229             return true;
230         klass = klass->parent;
231     }
232     return false;
233 }
234 
235 
236 /**
237  * virObjectNew:
238  * @klass: the klass of object to create
239  *
240  * Allocates a new object of type @klass. The returned
241  * object will be an instance of "virObject *", which
242  * can be cast to the struct associated with @klass.
243  *
244  * The initial reference count of the object will be 1.
245  *
246  * Returns the new object
247  */
248 void *
virObjectNew(virClass * klass)249 virObjectNew(virClass *klass)
250 {
251     virObject *obj = NULL;
252     virObjectPrivate *priv;
253 
254     obj = g_object_new(klass->type, NULL);
255 
256     priv = vir_object_get_instance_private(obj);
257     priv->klass = klass;
258     PROBE(OBJECT_NEW, "obj=%p classname=%s", obj, priv->klass->name);
259 
260     return obj;
261 }
262 
263 
264 void *
virObjectLockableNew(virClass * klass)265 virObjectLockableNew(virClass *klass)
266 {
267     virObjectLockable *obj;
268 
269     if (!virClassIsDerivedFrom(klass, virClassForObjectLockable())) {
270         virReportInvalidArg(klass,
271                             _("Class %s must derive from virObjectLockable"),
272                             virClassName(klass));
273         return NULL;
274     }
275 
276     if (!(obj = virObjectNew(klass)))
277         return NULL;
278 
279     if (virMutexInit(&obj->lock) < 0) {
280         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
281                        _("Unable to initialize mutex"));
282         virObjectUnref(obj);
283         return NULL;
284     }
285 
286     return obj;
287 }
288 
289 
290 void *
virObjectRWLockableNew(virClass * klass)291 virObjectRWLockableNew(virClass *klass)
292 {
293     virObjectRWLockable *obj;
294 
295     if (!virClassIsDerivedFrom(klass, virClassForObjectRWLockable())) {
296         virReportInvalidArg(klass,
297                             _("Class %s must derive from virObjectRWLockable"),
298                             virClassName(klass));
299         return NULL;
300     }
301 
302     if (!(obj = virObjectNew(klass)))
303         return NULL;
304 
305     if (virRWLockInit(&obj->lock) < 0) {
306         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
307                        _("Unable to initialize RW lock"));
308         virObjectUnref(obj);
309         return NULL;
310     }
311 
312     return obj;
313 }
314 
vir_object_finalize(GObject * gobj)315 static void vir_object_finalize(GObject *gobj)
316 {
317     virObject *obj = VIR_OBJECT(gobj);
318     virObjectPrivate *priv = vir_object_get_instance_private(obj);
319     virClass *klass = priv->klass;
320 
321     PROBE(OBJECT_DISPOSE, "obj=%p", gobj);
322 
323     while (klass) {
324         if (klass->dispose)
325             klass->dispose(obj);
326         klass = klass->parent;
327     }
328 
329     G_OBJECT_CLASS(vir_object_parent_class)->finalize(gobj);
330 }
331 
vir_object_init(virObject * obj G_GNUC_UNUSED)332 static void vir_object_init(virObject *obj G_GNUC_UNUSED)
333 {
334 }
335 
336 
vir_object_class_init(virObjectClass * klass)337 static void vir_object_class_init(virObjectClass *klass)
338 {
339     GObjectClass *obj = G_OBJECT_CLASS(klass);
340 
341     obj->finalize = vir_object_finalize;
342 }
343 
344 static void
virObjectLockableDispose(void * anyobj)345 virObjectLockableDispose(void *anyobj)
346 {
347     virObjectLockable *obj = anyobj;
348 
349     virMutexDestroy(&obj->lock);
350 }
351 
352 
353 static void
virObjectRWLockableDispose(void * anyobj)354 virObjectRWLockableDispose(void *anyobj)
355 {
356     virObjectRWLockable *obj = anyobj;
357 
358     virRWLockDestroy(&obj->lock);
359 }
360 
361 
362 /**
363  * virObjectUnref:
364  * @anyobj: any instance of virObject *
365  *
366  * Decrement the reference count on @anyobj and if
367  * it hits zero, runs the "dispose" callbacks associated
368  * with the object class and its parents before freeing
369  * @anyobj.
370  */
371 void
virObjectUnref(void * anyobj)372 virObjectUnref(void *anyobj)
373 {
374     virObject *obj = anyobj;
375 
376     if (VIR_OBJECT_NOTVALID(obj))
377         return;
378 
379     g_object_unref(anyobj);
380     PROBE(OBJECT_UNREF, "obj=%p", obj);
381 }
382 
383 
384 /**
385  * virObjectRef:
386  * @anyobj: any instance of virObject *
387  *
388  * Increment the reference count on @anyobj and return
389  * the same pointer
390  *
391  * Returns @anyobj
392  */
393 void *
virObjectRef(void * anyobj)394 virObjectRef(void *anyobj)
395 {
396     virObject *obj = anyobj;
397 
398     if (VIR_OBJECT_NOTVALID(obj))
399         return NULL;
400 
401     g_object_ref(obj);
402     PROBE(OBJECT_REF, "obj=%p", obj);
403     return anyobj;
404 }
405 
406 
407 static virObjectLockable *
virObjectGetLockableObj(void * anyobj)408 virObjectGetLockableObj(void *anyobj)
409 {
410     if (virObjectIsClass(anyobj, virObjectLockableClass))
411         return anyobj;
412 
413     VIR_OBJECT_USAGE_PRINT_WARNING(anyobj, virObjectLockable);
414     return NULL;
415 }
416 
417 
418 static virObjectRWLockable *
virObjectGetRWLockableObj(void * anyobj)419 virObjectGetRWLockableObj(void *anyobj)
420 {
421     if (virObjectIsClass(anyobj, virObjectRWLockableClass))
422         return anyobj;
423 
424     VIR_OBJECT_USAGE_PRINT_WARNING(anyobj, virObjectRWLockable);
425     return NULL;
426 }
427 
428 
429 /**
430  * virObjectLock:
431  * @anyobj: any instance of virObjectLockable
432  *
433  * Acquire a lock on @anyobj. The lock must be released by
434  * virObjectUnlock.
435  *
436  * The caller is expected to have acquired a reference
437  * on the object before locking it (eg virObjectRef).
438  * The object must be unlocked before releasing this
439  * reference.
440  */
441 void
virObjectLock(void * anyobj)442 virObjectLock(void *anyobj)
443 {
444     virObjectLockable *obj = virObjectGetLockableObj(anyobj);
445 
446     if (!obj)
447         return;
448 
449     virMutexLock(&obj->lock);
450 }
451 
452 
453 /**
454  * virObjectRWLockRead:
455  * @anyobj: any instance of virObjectRWLockable
456  *
457  * Acquire a read lock on @anyobj. The lock must be
458  * released by virObjectRWUnlock.
459  *
460  * The caller is expected to have acquired a reference
461  * on the object before locking it (eg virObjectRef).
462  * The object must be unlocked before releasing this
463  * reference.
464  *
465  * NB: It's possible to return without the lock if
466  *     @anyobj was invalid - this has been considered
467  *     a programming error rather than something that
468  *     should be checked.
469  */
470 void
virObjectRWLockRead(void * anyobj)471 virObjectRWLockRead(void *anyobj)
472 {
473     virObjectRWLockable *obj = virObjectGetRWLockableObj(anyobj);
474 
475     if (!obj)
476         return;
477 
478     virRWLockRead(&obj->lock);
479 }
480 
481 
482 /**
483  * virObjectRWLockWrite:
484  * @anyobj: any instance of virObjectRWLockable
485  *
486  * Acquire a write lock on @anyobj. The lock must be
487  * released by virObjectRWUnlock.
488  *
489  * The caller is expected to have acquired a reference
490  * on the object before locking it (eg virObjectRef).
491  * The object must be unlocked before releasing this
492  * reference.
493  *
494  * NB: It's possible to return without the lock if
495  *     @anyobj was invalid - this has been considered
496  *     a programming error rather than something that
497  *     should be checked.
498  */
499 void
virObjectRWLockWrite(void * anyobj)500 virObjectRWLockWrite(void *anyobj)
501 {
502     virObjectRWLockable *obj = virObjectGetRWLockableObj(anyobj);
503 
504     if (!obj)
505         return;
506 
507     virRWLockWrite(&obj->lock);
508 }
509 
510 
511 /**
512  * virObjectUnlock:
513  * @anyobj: any instance of virObjectLockable
514  *
515  * Release a lock on @anyobj. The lock must have been acquired by
516  * virObjectLock.
517  */
518 void
virObjectUnlock(void * anyobj)519 virObjectUnlock(void *anyobj)
520 {
521     virObjectLockable *obj = virObjectGetLockableObj(anyobj);
522 
523     if (!obj)
524         return;
525 
526     virMutexUnlock(&obj->lock);
527 }
528 
529 
530 /**
531  * virObjectRWUnlock:
532  * @anyobj: any instance of virObjectRWLockable
533  *
534  * Release a lock on @anyobj. The lock must have been acquired by
535  * virObjectRWLockRead or virObjectRWLockWrite.
536  */
537 void
virObjectRWUnlock(void * anyobj)538 virObjectRWUnlock(void *anyobj)
539 {
540     virObjectRWLockable *obj = virObjectGetRWLockableObj(anyobj);
541 
542     if (!obj)
543         return;
544 
545     virRWLockUnlock(&obj->lock);
546 }
547 
548 
549 /**
550  * virObjectIsClass:
551  * @anyobj: any instance of virObject *
552  * @klass: the class to check
553  *
554  * Checks whether @anyobj is an instance of
555  * @klass
556  *
557  * Returns true if @anyobj is an instance of @klass
558  */
559 bool
virObjectIsClass(void * anyobj,virClass * klass)560 virObjectIsClass(void *anyobj,
561                  virClass *klass)
562 {
563     virObject *obj = anyobj;
564     virObjectPrivate *priv;
565 
566     if (VIR_OBJECT_NOTVALID(obj))
567         return false;
568 
569     priv = vir_object_get_instance_private(obj);
570     return virClassIsDerivedFrom(priv->klass, klass);
571 }
572 
573 
574 /**
575  * virClassName:
576  * @klass: the object class
577  *
578  * Returns the name of @klass
579  */
580 const char *
virClassName(virClass * klass)581 virClassName(virClass *klass)
582 {
583     return klass->name;
584 }
585 
586 
587 /**
588  * virObjectFreeCallback:
589  * @opaque: a pointer to a virObject instance
590  *
591  * Provides identical functionality to virObjectUnref,
592  * but with the signature matching the virFreeCallback
593  * typedef.
594  */
virObjectFreeCallback(void * opaque)595 void virObjectFreeCallback(void *opaque)
596 {
597     virObjectUnref(opaque);
598 }
599 
600 
601 /**
602  * virObjectFreeHashData:
603  * @opaque: a pointer to a virObject instance
604  * @name: ignored, name of the hash key being deleted
605  *
606  * Provides identical functionality to virObjectUnref,
607  * but with the signature matching the virHashDataFree
608  * typedef.
609  */
610 void
virObjectFreeHashData(void * opaque)611 virObjectFreeHashData(void *opaque)
612 {
613     virObjectUnref(opaque);
614 }
615 
616 
617 /**
618  * virObjectListFree:
619  * @list: A pointer to a NULL-terminated list of object pointers to free
620  *
621  * Unrefs all members of @list and frees the list itself.
622  */
623 void
virObjectListFree(void * list)624 virObjectListFree(void *list)
625 {
626     void **next;
627 
628     if (!list)
629         return;
630 
631     for (next = (void **) list; *next; next++)
632         virObjectUnref(*next);
633 
634     g_free(list);
635 }
636 
637 
638 /**
639  * virObjectListFreeCount:
640  * @list: A pointer to a list of object pointers to freea
641  * @count: Number of elements in the list.
642  *
643  * Unrefs all members of @list and frees the list itself.
644  */
645 void
virObjectListFreeCount(void * list,size_t count)646 virObjectListFreeCount(void *list,
647                        size_t count)
648 {
649     size_t i;
650 
651     if (!list)
652         return;
653 
654     for (i = 0; i < count; i++)
655         virObjectUnref(((void **)list)[i]);
656 
657     g_free(list);
658 }
659