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 *****************************************************************************/
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 /*****************************************************************************
35 *****************************************************************************/
40 #include <vlc_common.h>
42 #include "../libvlc.h"
44 #include "audio_output/aout_internal.h"
46 #include "vlc_interface.h"
47 #include "vlc_codec.h"
49 #include "variables.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
)
65 if (obj
->obj
.parent
== NULL
)
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" : " ";
74 str
= last
? " \xE2\x94\x9C" : " \xE2\x94\x82";
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
)
97 if (unlikely(level
> 100))
99 msg_Warn (obj
, "structure tree is too deep");
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
;
127 DumpStructure (obj
, 0);
134 static vlc_object_t
*ObjectExists (vlc_object_t
*root
, void *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
);
152 vlc_mutex_unlock (&vlc_internals(root
)->tree_lock
);
156 static int VarsCommand (vlc_object_t
*obj
, char const *cmd
,
157 vlc_value_t oldval
, vlc_value_t newval
, void *data
)
161 (void) cmd
; (void) oldval
; (void) data
;
163 if (sscanf (newval
.psz_string
, "%p", &p
) == 1)
165 p
= ObjectExists (obj
, p
);
168 msg_Err (obj
, "no such object: %s", newval
.psz_string
);
174 vlc_object_hold (obj
);
176 printf(" o %p %s, parent %p\n", (void *)obj
,
177 obj
->obj
.object_type
, (void *)obj
->obj
.parent
);
179 vlc_object_release (obj
);
184 #undef vlc_custom_create
185 void *vlc_custom_create (vlc_object_t
*parent
, size_t length
,
186 const char *typename
)
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
))
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
);
235 libvlc_int_t
*self
= (libvlc_int_t
*)obj
;
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
);
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
;
292 vlc_mutex_lock (&name_lock
);
293 oldname
= priv
->psz_name
;
294 priv
->psz_name
= newname
;
295 vlc_mutex_unlock (&name_lock
);
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
);
306 vlc_mutex_lock (&name_lock
);
307 name
= priv
->psz_name
? strdup (priv
->psz_name
) : NULL
;
308 vlc_mutex_unlock (&name_lock
);
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
);
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
);
365 /* NOTE: nested locking here (due to recursive call) */
366 vlc_mutex_unlock (&vlc_internals(obj
)->tree_lock
);
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),
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. */
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
)
402 msg_Err( p_this
, "looking for object \"%s\"... FIXME XXX", psz_name
);
405 vlc_mutex_lock (&name_lock
);
406 p_found
= FindName (p_this
, psz_name
);
407 vlc_mutex_unlock (&name_lock
);
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 */
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
);
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 */
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
);
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
);
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
,
514 vlc_object_internals_t
*priv
;
517 vlc_mutex_lock (&vlc_internals(obj
)->tree_lock
);
518 vlc_children_foreach(priv
, vlc_internals(obj
))
521 tab
[count
] = vlc_object_hold(vlc_externals(priv
));
524 vlc_mutex_unlock (&vlc_internals(obj
)->tree_lock
);