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