Dshow: relicense to LGPL
[vlc.git] / src / misc / objects.c
blob51ddb027063a7e7bcca191bf7214354183b9c426
1 /*****************************************************************************
2 * objects.c: vlc_object_t handling
3 *****************************************************************************
4 * Copyright (C) 2004-2008 VLC authors and VideoLAN
5 * Copyright (C) 2006-2010 RĂ©mi Denis-Courmont
7 * Authors: Samuel Hocevar <sam@zoy.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /**
25 * \file
26 * This file contains the functions to handle the vlc_object_t type
28 * Unless otherwise stated, functions in this file are not cancellation point.
29 * All functions in this file are safe w.r.t. deferred cancellation.
33 /*****************************************************************************
34 * Preamble
35 *****************************************************************************/
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
40 #include <vlc_common.h>
42 #include "../libvlc.h"
43 #include <vlc_aout.h>
44 #include "audio_output/aout_internal.h"
46 #include "vlc_interface.h"
47 #include "vlc_codec.h"
49 #include "variables.h"
51 #ifdef HAVE_SEARCH_H
52 # include <search.h>
53 #endif
55 #include <limits.h>
56 #include <assert.h>
58 #define vlc_children_foreach(pos, priv) \
59 vlc_list_foreach(pos, &priv->children, siblings)
61 static void PrintObjectPrefix(vlc_object_t *obj, bool last)
63 const char *str;
65 if (obj->obj.parent == NULL)
66 return;
68 PrintObjectPrefix(obj->obj.parent, false);
70 if (vlc_list_is_last(&vlc_internals(obj)->siblings,
71 &vlc_internals(obj->obj.parent)->children))
72 str = last ? " \xE2\x94\x94" : " ";
73 else
74 str = last ? " \xE2\x94\x9C" : " \xE2\x94\x82";
76 fputs(str, stdout);
79 static void PrintObject(vlc_object_t *obj)
81 vlc_object_internals_t *priv = vlc_internals(obj);
83 int canc = vlc_savecancel ();
85 PrintObjectPrefix(obj, true);
86 printf("\xE2\x94\x80\xE2\x94%c\xE2\x95\xB4%p %s, %u refs\n",
87 vlc_list_is_empty(&priv->children) ? 0x80 : 0xAC,
88 (void *)obj, obj->obj.object_type, atomic_load(&priv->refs));
90 vlc_restorecancel (canc);
93 static void DumpStructure(vlc_object_t *obj, unsigned level)
95 PrintObject(obj);
97 if (unlikely(level > 100))
99 msg_Warn (obj, "structure tree is too deep");
100 return;
103 vlc_object_internals_t *priv = vlc_internals(obj);
105 /* NOTE: nested locking here (due to recursive call) */
106 vlc_mutex_lock (&vlc_internals(obj)->tree_lock);
107 vlc_children_foreach(priv, priv)
108 DumpStructure(vlc_externals(priv), level + 1);
109 vlc_mutex_unlock (&vlc_internals(obj)->tree_lock);
113 * Prints the VLC object tree
115 * This function prints either an ASCII tree showing the connections between
116 * vlc objects, and additional information such as their refcount, thread ID,
117 * etc. (command "tree"), or the same data as a simple list (command "list").
119 static int TreeCommand (vlc_object_t *obj, char const *cmd,
120 vlc_value_t oldval, vlc_value_t newval, void *data)
122 (void) cmd; (void) oldval; (void) newval; (void) data;
124 if (cmd[0] == 't')
126 flockfile(stdout);
127 DumpStructure (obj, 0);
128 funlockfile(stdout);
131 return VLC_SUCCESS;
134 static vlc_object_t *ObjectExists (vlc_object_t *root, void *obj)
136 if (root == obj)
137 return vlc_object_hold (root);
139 vlc_object_internals_t *priv = vlc_internals(root);
140 vlc_object_t *ret = NULL;
142 /* NOTE: nested locking here (due to recursive call) */
143 vlc_mutex_lock (&vlc_internals(root)->tree_lock);
145 vlc_children_foreach(priv, priv)
147 ret = ObjectExists (vlc_externals (priv), obj);
148 if (ret != NULL)
149 break;
152 vlc_mutex_unlock (&vlc_internals(root)->tree_lock);
153 return ret;
156 static int VarsCommand (vlc_object_t *obj, char const *cmd,
157 vlc_value_t oldval, vlc_value_t newval, void *data)
159 void *p;
161 (void) cmd; (void) oldval; (void) data;
163 if (sscanf (newval.psz_string, "%p", &p) == 1)
165 p = ObjectExists (obj, p);
166 if (p == NULL)
168 msg_Err (obj, "no such object: %s", newval.psz_string);
169 return VLC_ENOOBJ;
171 obj = p;
173 else
174 vlc_object_hold (obj);
176 printf(" o %p %s, parent %p\n", (void *)obj,
177 obj->obj.object_type, (void *)obj->obj.parent);
178 DumpVariables (obj);
179 vlc_object_release (obj);
181 return VLC_SUCCESS;
184 #undef vlc_custom_create
185 void *vlc_custom_create (vlc_object_t *parent, size_t length,
186 const char *typename)
188 /* NOTE:
189 * VLC objects are laid out as follow:
190 * - first the LibVLC-private per-object data,
191 * - then VLC_COMMON members from vlc_object_t,
192 * - finally, the type-specific data (if any).
194 * This function initializes the LibVLC and common data,
195 * and zeroes the rest.
197 assert (length >= sizeof (vlc_object_t));
199 vlc_object_internals_t *priv = malloc (sizeof (*priv) + length);
200 if (unlikely(priv == NULL))
201 return NULL;
202 priv->psz_name = NULL;
203 priv->var_root = NULL;
204 vlc_mutex_init (&priv->var_lock);
205 vlc_cond_init (&priv->var_wait);
206 atomic_init (&priv->refs, 1);
207 priv->pf_destructor = NULL;
208 vlc_list_init(&priv->children);
209 vlc_mutex_init (&priv->tree_lock);
210 priv->resources = NULL;
212 vlc_object_t *obj = (vlc_object_t *)(priv + 1);
213 obj->obj.object_type = typename;
214 obj->obj.header = NULL;
215 obj->obj.force = false;
216 memset (obj + 1, 0, length - sizeof (*obj)); /* type-specific stuff */
218 if (likely(parent != NULL))
220 vlc_object_internals_t *papriv = vlc_internals (parent);
222 obj->obj.flags = parent->obj.flags;
223 obj->obj.libvlc = parent->obj.libvlc;
225 /* Attach the child to its parent (no lock needed) */
226 obj->obj.parent = vlc_object_hold (parent);
228 /* Attach the parent to its child (structure lock needed) */
229 vlc_mutex_lock (&papriv->tree_lock);
230 vlc_list_append(&priv->siblings, &papriv->children);
231 vlc_mutex_unlock (&papriv->tree_lock);
233 else
235 libvlc_int_t *self = (libvlc_int_t *)obj;
237 obj->obj.flags = 0;
238 obj->obj.libvlc = self;
239 obj->obj.parent = NULL;
241 /* TODO: should be in src/libvlc.c */
242 int canc = vlc_savecancel ();
243 var_Create (obj, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND);
244 var_AddCallback (obj, "tree", TreeCommand, NULL);
245 var_Create (obj, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND);
246 var_AddCallback (obj, "vars", VarsCommand, NULL);
247 vlc_restorecancel (canc);
250 return obj;
253 #undef vlc_object_create
255 * Allocates and initializes a vlc object.
257 * @param i_size object byte size
259 * @return the new object, or NULL on error.
261 void *vlc_object_create( vlc_object_t *p_this, size_t i_size )
263 return vlc_custom_create( p_this, i_size, "generic" );
266 #undef vlc_object_set_destructor
268 ****************************************************************************
269 * Set the destructor of a vlc object
271 * This function sets the destructor of the vlc object. It will be called
272 * when the object is destroyed when the its refcount reaches 0.
273 * (It is called by the internal function vlc_object_destroy())
274 *****************************************************************************/
275 void vlc_object_set_destructor( vlc_object_t *p_this,
276 vlc_destructor_t pf_destructor )
278 vlc_object_internals_t *p_priv = vlc_internals(p_this );
280 p_priv->pf_destructor = pf_destructor;
283 static vlc_mutex_t name_lock = VLC_STATIC_MUTEX;
285 #undef vlc_object_set_name
286 int vlc_object_set_name(vlc_object_t *obj, const char *name)
288 vlc_object_internals_t *priv = vlc_internals(obj);
289 char *newname = name ? strdup (name) : NULL;
290 char *oldname;
292 vlc_mutex_lock (&name_lock);
293 oldname = priv->psz_name;
294 priv->psz_name = newname;
295 vlc_mutex_unlock (&name_lock);
297 free (oldname);
298 return (priv->psz_name || !name) ? VLC_SUCCESS : VLC_ENOMEM;
301 char *vlc_object_get_name(const vlc_object_t *obj)
303 vlc_object_internals_t *priv = vlc_internals(obj);
304 char *name;
306 vlc_mutex_lock (&name_lock);
307 name = priv->psz_name ? strdup (priv->psz_name) : NULL;
308 vlc_mutex_unlock (&name_lock);
310 return name;
314 * Destroys a VLC object once it has no more references.
316 * This function must be called with cancellation disabled (currently).
318 static void vlc_object_destroy( vlc_object_t *p_this )
320 vlc_object_internals_t *p_priv = vlc_internals( p_this );
322 assert(p_priv->resources == NULL);
324 /* Call the custom "subclass" destructor */
325 if( p_priv->pf_destructor )
326 p_priv->pf_destructor( p_this );
328 if (unlikely(p_this->obj.parent == NULL))
330 /* TODO: should be in src/libvlc.c */
331 var_DelCallback (p_this, "vars", VarsCommand, NULL);
332 var_DelCallback (p_this, "tree", TreeCommand, NULL);
335 /* Destroy the associated variables. */
336 var_DestroyAll( p_this );
338 vlc_mutex_destroy (&p_priv->tree_lock);
339 vlc_cond_destroy( &p_priv->var_wait );
340 vlc_mutex_destroy( &p_priv->var_lock );
341 free( p_this->obj.header );
342 free( p_priv->psz_name );
343 free( p_priv );
346 static vlc_object_t *FindName (vlc_object_t *obj, const char *name)
348 vlc_object_internals_t *priv = vlc_internals(obj);
350 if (priv->psz_name != NULL && !strcmp (priv->psz_name, name))
351 return vlc_object_hold (obj);
353 vlc_object_t *found = NULL;
355 /* NOTE: nested locking here (due to recursive call) */
356 vlc_mutex_lock (&vlc_internals(obj)->tree_lock);
358 vlc_children_foreach(priv, priv)
360 found = FindName (vlc_externals(priv), name);
361 if (found != NULL)
362 break;
365 /* NOTE: nested locking here (due to recursive call) */
366 vlc_mutex_unlock (&vlc_internals(obj)->tree_lock);
367 return found;
370 #undef vlc_object_find_name
372 * Finds a named object and increment its reference count.
373 * Beware that objects found in this manner can be "owned" by another thread,
374 * be of _any_ type, and be attached to any module (if any). With such an
375 * object reference, you can set or get object variables, emit log messages,
376 * and read write-once object parameters (obj.object_type, etc).
377 * You CANNOT cast the object to a more specific object type, and you
378 * definitely cannot invoke object type-specific callbacks with this.
380 * @param p_this object to search from
381 * @param psz_name name of the object to search for
383 * @return a matching object (must be released by the caller),
384 * or NULL on error.
386 vlc_object_t *vlc_object_find_name( vlc_object_t *p_this, const char *psz_name )
388 vlc_object_t *p_found;
390 /* The object name is not thread-safe, provides no warranty that the
391 * object is fully initialized and still active, and that its owner can
392 * deal with asynchronous and external state changes. There may be multiple
393 * objects with the same name, and the function may fail even if a matching
394 * object exists. DO NOT USE THIS IN NEW CODE. */
395 #ifndef NDEBUG
396 /* This was officially deprecated on August 19 2009. For the convenience of
397 * wannabe code janitors, this is the list of names that remain used
398 * and unfixed since then. */
399 static const char bad[][5] = { "v4l2", "zvbi" };
400 if( bsearch( psz_name, bad, 2, 5, (void *)strcmp ) == NULL )
401 return NULL;
402 msg_Err( p_this, "looking for object \"%s\"... FIXME XXX", psz_name );
403 #endif
405 vlc_mutex_lock (&name_lock);
406 p_found = FindName (p_this, psz_name);
407 vlc_mutex_unlock (&name_lock);
408 return p_found;
411 #undef vlc_object_hold
413 * Increment an object reference counter.
415 void * vlc_object_hold( vlc_object_t *p_this )
417 vlc_object_internals_t *internals = vlc_internals( p_this );
418 unsigned refs = atomic_fetch_add_explicit(&internals->refs, 1,
419 memory_order_relaxed);
421 assert (refs > 0); /* Avoid obvious freed object uses */
422 (void) refs;
423 return p_this;
426 #undef vlc_object_release
428 * Drops a reference to an object (decrements the reference count).
429 * If the count reaches zero, the object is destroyed.
431 void vlc_object_release (vlc_object_t *obj)
433 vlc_object_internals_t *priv = vlc_internals(obj);
434 unsigned refs = atomic_load_explicit(&priv->refs, memory_order_relaxed);
436 /* Fast path */
437 while (refs > 1)
439 if (atomic_compare_exchange_weak_explicit(&priv->refs, &refs, refs - 1,
440 memory_order_release, memory_order_relaxed))
441 return; /* There are still other references to the object */
443 assert (refs > 0);
446 vlc_object_t *parent = obj->obj.parent;
448 if (unlikely(parent == NULL))
449 { /* Destroying the root object */
450 refs = atomic_fetch_sub_explicit(&priv->refs, 1, memory_order_relaxed);
451 assert (refs == 1); /* nobody to race against in this case */
452 /* no children can be left */
453 assert(vlc_list_is_empty(&priv->children));
455 int canc = vlc_savecancel ();
456 vlc_object_destroy (obj);
457 vlc_restorecancel (canc);
458 return;
461 /* Slow path */
462 vlc_object_internals_t *papriv = vlc_internals (parent);
464 vlc_mutex_lock (&papriv->tree_lock);
465 refs = atomic_fetch_sub_explicit(&priv->refs, 1, memory_order_release);
466 assert (refs > 0);
468 if (likely(refs == 1))
469 /* Detach from parent to protect against vlc_object_find_name() */
470 vlc_list_remove(&priv->siblings);
471 vlc_mutex_unlock (&papriv->tree_lock);
473 if (likely(refs == 1))
475 atomic_thread_fence(memory_order_acquire);
476 /* no children can be left (because children reference their parent) */
477 assert(vlc_list_is_empty(&priv->children));
479 int canc = vlc_savecancel ();
480 vlc_object_destroy (obj);
481 vlc_restorecancel (canc);
483 vlc_object_release (parent);
488 * Lists the children of an object.
490 * Fills a table of pointers to children object of an object, incrementing the
491 * reference count for each of them.
493 * @param obj object whose children are to be listed
494 * @param tab base address to hold the list of children [OUT]
495 * @param max size of the table
497 * @return the actual numer of children (may be larger than requested).
499 * @warning The list of object can change asynchronously even before the
500 * function returns. The list meant exclusively for debugging and tracing,
501 * not for functional introspection of any kind.
503 * @warning Objects appear in the object tree early, and disappear late.
504 * Most object properties are not accessible or not defined when the object is
505 * accessed through this function.
506 * For instance, the object cannot be used as a message log target
507 * (because object flags are not accessible asynchronously).
508 * Also type-specific object variables may not have been created yet, or may
509 * already have been deleted.
511 size_t vlc_list_children(vlc_object_t *obj, vlc_object_t **restrict tab,
512 size_t max)
514 vlc_object_internals_t *priv;
515 size_t count = 0;
517 vlc_mutex_lock (&vlc_internals(obj)->tree_lock);
518 vlc_children_foreach(priv, vlc_internals(obj))
520 if (count < max)
521 tab[count] = vlc_object_hold(vlc_externals(priv));
522 count++;
524 vlc_mutex_unlock (&vlc_internals(obj)->tree_lock);
525 return count;