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 static void PrintObject (vlc_object_t
*obj
, const char *prefix
)
60 vlc_object_internals_t
*priv
= vlc_internals(obj
);
62 int canc
= vlc_savecancel ();
63 printf (" %so %p %s, %u refs, parent %p\n", prefix
, (void *)obj
,
64 obj
->obj
.object_type
, atomic_load(&priv
->refs
),
65 (void *)obj
->obj
.parent
);
66 vlc_restorecancel (canc
);
69 static void DumpStructure (vlc_object_t
*obj
, unsigned level
, char *psz_foo
)
71 char back
= psz_foo
[level
];
73 psz_foo
[level
] = '\0';
74 PrintObject (obj
, psz_foo
);
75 psz_foo
[level
] = back
;
77 if (level
/ 2 >= MAX_DUMPSTRUCTURE_DEPTH
)
79 msg_Warn (obj
, "structure tree is too deep");
83 vlc_object_internals_t
*priv
= vlc_internals(obj
);
85 /* NOTE: nested locking here (due to recursive call) */
86 vlc_mutex_lock (&vlc_internals(obj
)->tree_lock
);
87 for (priv
= priv
->first
; priv
!= NULL
; priv
= priv
->next
)
92 psz_foo
[level
- 1] = ' ';
94 if (psz_foo
[level
- 2] == '`')
95 psz_foo
[level
- 2] = ' ';
98 psz_foo
[level
] = priv
->next
? '|' : '`';
99 psz_foo
[level
+ 1] = '-';
100 psz_foo
[level
+ 2] = '\0';
102 DumpStructure (vlc_externals(priv
), level
+ 2, psz_foo
);
104 vlc_mutex_unlock (&vlc_internals(obj
)->tree_lock
);
108 * Prints the VLC object tree
110 * This function prints either an ASCII tree showing the connections between
111 * vlc objects, and additional information such as their refcount, thread ID,
112 * etc. (command "tree"), or the same data as a simple list (command "list").
114 static int TreeCommand (vlc_object_t
*obj
, char const *cmd
,
115 vlc_value_t oldval
, vlc_value_t newval
, void *data
)
117 (void) cmd
; (void) oldval
; (void) newval
; (void) data
;
121 char psz_foo
[2 * MAX_DUMPSTRUCTURE_DEPTH
+ 1];
124 DumpStructure (obj
, 0, psz_foo
);
130 static vlc_object_t
*ObjectExists (vlc_object_t
*root
, void *obj
)
133 return vlc_object_hold (root
);
135 vlc_object_internals_t
*priv
= vlc_internals(root
);
136 vlc_object_t
*ret
= NULL
;
138 /* NOTE: nested locking here (due to recursive call) */
139 vlc_mutex_lock (&vlc_internals(root
)->tree_lock
);
141 for (priv
= priv
->first
; priv
!= NULL
&& ret
== NULL
; priv
= priv
->next
)
142 ret
= ObjectExists (vlc_externals (priv
), obj
);
144 vlc_mutex_unlock (&vlc_internals(root
)->tree_lock
);
148 static int VarsCommand (vlc_object_t
*obj
, char const *cmd
,
149 vlc_value_t oldval
, vlc_value_t newval
, void *data
)
153 (void) cmd
; (void) oldval
; (void) data
;
155 if (sscanf (newval
.psz_string
, "%p", &p
) == 1)
157 p
= ObjectExists (obj
, p
);
160 msg_Err (obj
, "no such object: %s", newval
.psz_string
);
166 vlc_object_hold (obj
);
168 PrintObject (obj
, "");
170 vlc_object_release (obj
);
175 #undef vlc_custom_create
176 void *vlc_custom_create (vlc_object_t
*parent
, size_t length
,
177 const char *typename
)
180 * VLC objects are laid out as follow:
181 * - first the LibVLC-private per-object data,
182 * - then VLC_COMMON members from vlc_object_t,
183 * - finally, the type-specific data (if any).
185 * This function initializes the LibVLC and common data,
186 * and zeroes the rest.
188 assert (length
>= sizeof (vlc_object_t
));
190 vlc_object_internals_t
*priv
= malloc (sizeof (*priv
) + length
);
191 if (unlikely(priv
== NULL
))
193 priv
->psz_name
= NULL
;
194 priv
->var_root
= NULL
;
195 vlc_mutex_init (&priv
->var_lock
);
196 vlc_cond_init (&priv
->var_wait
);
197 atomic_init (&priv
->refs
, 1);
198 priv
->pf_destructor
= NULL
;
201 vlc_mutex_init (&priv
->tree_lock
);
202 priv
->resources
= NULL
;
204 vlc_object_t
*obj
= (vlc_object_t
*)(priv
+ 1);
205 obj
->obj
.object_type
= typename
;
206 obj
->obj
.header
= NULL
;
207 obj
->obj
.force
= false;
208 memset (obj
+ 1, 0, length
- sizeof (*obj
)); /* type-specific stuff */
210 if (likely(parent
!= NULL
))
212 vlc_object_internals_t
*papriv
= vlc_internals (parent
);
214 obj
->obj
.flags
= parent
->obj
.flags
;
215 obj
->obj
.libvlc
= parent
->obj
.libvlc
;
217 /* Attach the child to its parent (no lock needed) */
218 obj
->obj
.parent
= vlc_object_hold (parent
);
220 /* Attach the parent to its child (structure lock needed) */
221 vlc_mutex_lock (&papriv
->tree_lock
);
222 priv
->next
= papriv
->first
;
223 if (priv
->next
!= NULL
)
224 priv
->next
->prev
= priv
;
225 papriv
->first
= priv
;
226 vlc_mutex_unlock (&papriv
->tree_lock
);
230 libvlc_int_t
*self
= (libvlc_int_t
*)obj
;
233 obj
->obj
.libvlc
= self
;
234 obj
->obj
.parent
= NULL
;
237 /* TODO: should be in src/libvlc.c */
238 int canc
= vlc_savecancel ();
239 var_Create (obj
, "tree", VLC_VAR_STRING
| VLC_VAR_ISCOMMAND
);
240 var_AddCallback (obj
, "tree", TreeCommand
, NULL
);
241 var_Create (obj
, "vars", VLC_VAR_STRING
| VLC_VAR_ISCOMMAND
);
242 var_AddCallback (obj
, "vars", VarsCommand
, NULL
);
243 vlc_restorecancel (canc
);
249 #undef vlc_object_create
251 * Allocates and initializes a vlc object.
253 * @param i_size object byte size
255 * @return the new object, or NULL on error.
257 void *vlc_object_create( vlc_object_t
*p_this
, size_t i_size
)
259 return vlc_custom_create( p_this
, i_size
, "generic" );
262 #undef vlc_object_set_destructor
264 ****************************************************************************
265 * Set the destructor of a vlc object
267 * This function sets the destructor of the vlc object. It will be called
268 * when the object is destroyed when the its refcount reaches 0.
269 * (It is called by the internal function vlc_object_destroy())
270 *****************************************************************************/
271 void vlc_object_set_destructor( vlc_object_t
*p_this
,
272 vlc_destructor_t pf_destructor
)
274 vlc_object_internals_t
*p_priv
= vlc_internals(p_this
);
276 p_priv
->pf_destructor
= pf_destructor
;
279 static vlc_mutex_t name_lock
= VLC_STATIC_MUTEX
;
281 #undef vlc_object_set_name
282 int vlc_object_set_name(vlc_object_t
*obj
, const char *name
)
284 vlc_object_internals_t
*priv
= vlc_internals(obj
);
285 char *newname
= name
? strdup (name
) : NULL
;
288 vlc_mutex_lock (&name_lock
);
289 oldname
= priv
->psz_name
;
290 priv
->psz_name
= newname
;
291 vlc_mutex_unlock (&name_lock
);
294 return (priv
->psz_name
|| !name
) ? VLC_SUCCESS
: VLC_ENOMEM
;
297 #undef vlc_object_get_name
298 char *vlc_object_get_name(const vlc_object_t
*obj
)
300 vlc_object_internals_t
*priv
= vlc_internals(obj
);
303 vlc_mutex_lock (&name_lock
);
304 name
= priv
->psz_name
? strdup (priv
->psz_name
) : NULL
;
305 vlc_mutex_unlock (&name_lock
);
311 * Destroys a VLC object once it has no more references.
313 * This function must be called with cancellation disabled (currently).
315 static void vlc_object_destroy( vlc_object_t
*p_this
)
317 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
319 assert(p_priv
->resources
== NULL
);
321 /* Call the custom "subclass" destructor */
322 if( p_priv
->pf_destructor
)
323 p_priv
->pf_destructor( p_this
);
325 if (unlikely(p_this
->obj
.parent
== NULL
))
327 /* TODO: should be in src/libvlc.c */
328 var_DelCallback (p_this
, "vars", VarsCommand
, NULL
);
329 var_DelCallback (p_this
, "tree", TreeCommand
, NULL
);
332 /* Destroy the associated variables. */
333 var_DestroyAll( p_this
);
335 vlc_mutex_destroy (&p_priv
->tree_lock
);
336 vlc_cond_destroy( &p_priv
->var_wait
);
337 vlc_mutex_destroy( &p_priv
->var_lock
);
338 free( p_this
->obj
.header
);
339 free( p_priv
->psz_name
);
343 static vlc_object_t
*FindName (vlc_object_t
*obj
, const char *name
)
345 vlc_object_internals_t
*priv
= vlc_internals(obj
);
347 if (priv
->psz_name
!= NULL
&& !strcmp (priv
->psz_name
, name
))
348 return vlc_object_hold (obj
);
350 vlc_object_t
*found
= NULL
;
351 /* NOTE: nested locking here (due to recursive call) */
352 vlc_mutex_lock (&vlc_internals(obj
)->tree_lock
);
354 for (priv
= priv
->first
; priv
!= NULL
&& found
== NULL
; priv
= priv
->next
)
355 found
= FindName (vlc_externals(priv
), name
);
357 /* NOTE: nested locking here (due to recursive call) */
358 vlc_mutex_unlock (&vlc_internals(obj
)->tree_lock
);
362 #undef vlc_object_find_name
364 * Finds a named object and increment its reference count.
365 * Beware that objects found in this manner can be "owned" by another thread,
366 * be of _any_ type, and be attached to any module (if any). With such an
367 * object reference, you can set or get object variables, emit log messages,
368 * and read write-once object parameters (obj.object_type, etc).
369 * You CANNOT cast the object to a more specific object type, and you
370 * definitely cannot invoke object type-specific callbacks with this.
372 * @param p_this object to search from
373 * @param psz_name name of the object to search for
375 * @return a matching object (must be released by the caller),
378 vlc_object_t
*vlc_object_find_name( vlc_object_t
*p_this
, const char *psz_name
)
380 vlc_object_t
*p_found
;
382 /* The object name is not thread-safe, provides no warranty that the
383 * object is fully initialized and still active, and that its owner can
384 * deal with asynchronous and external state changes. There may be multiple
385 * objects with the same name, and the function may fail even if a matching
386 * object exists. DO NOT USE THIS IN NEW CODE. */
388 /* This was officially deprecated on August 19 2009. For the convenience of
389 * wannabe code janitors, this is the list of names that remain used
390 * and unfixed since then. */
391 static const char bad
[][11] = { "adjust", "clone", "colorthres",
392 "erase", "extract", "gradient", "logo", "marq", "motionblur", "puzzle",
393 "rotate", "sharpen", "transform", "v4l2", "wall" };
394 static const char poor
[][13] = { "invert", "magnify", "motiondetect",
395 "psychedelic", "ripple", "wave" };
396 if( bsearch( psz_name
, bad
, 15, 11, (void *)strcmp
) == NULL
397 && bsearch( psz_name
, poor
, 6, 13, (void *)strcmp
) == NULL
)
399 msg_Err( p_this
, "looking for object \"%s\"... FIXME XXX", psz_name
);
402 vlc_mutex_lock (&name_lock
);
403 p_found
= FindName (p_this
, psz_name
);
404 vlc_mutex_unlock (&name_lock
);
408 #undef vlc_object_hold
410 * Increment an object reference counter.
412 void * vlc_object_hold( vlc_object_t
*p_this
)
414 vlc_object_internals_t
*internals
= vlc_internals( p_this
);
416 unsigned refs
= atomic_fetch_add (&internals
->refs
, 1);
417 assert (refs
> 0); /* Avoid obvious freed object uses */
419 atomic_fetch_add (&internals
->refs
, 1);
424 #undef vlc_object_release
426 * Drops a reference to an object (decrements the reference count).
427 * If the count reaches zero, the object is destroyed.
429 void vlc_object_release (vlc_object_t
*obj
)
431 vlc_object_internals_t
*priv
= vlc_internals(obj
);
432 unsigned refs
= atomic_load (&priv
->refs
);
437 if (atomic_compare_exchange_weak (&priv
->refs
, &refs
, refs
- 1))
438 return; /* There are still other references to the object */
443 vlc_object_t
*parent
= obj
->obj
.parent
;
445 if (unlikely(parent
== NULL
))
446 { /* Destroying the root object */
447 refs
= atomic_fetch_sub (&priv
->refs
, 1);
448 assert (refs
== 1); /* nobody to race against in this case */
450 assert (priv
->first
== NULL
); /* no children can be left */
452 int canc
= vlc_savecancel ();
453 vlc_object_destroy (obj
);
454 vlc_restorecancel (canc
);
459 vlc_object_internals_t
*papriv
= vlc_internals (parent
);
461 vlc_mutex_lock (&papriv
->tree_lock
);
462 refs
= atomic_fetch_sub (&priv
->refs
, 1);
465 if (likely(refs
== 1))
466 { /* Detach from parent to protect against vlc_object_find_name() */
467 vlc_object_internals_t
*prev
= priv
->prev
;
468 vlc_object_internals_t
*next
= priv
->next
;
472 assert (prev
->next
== priv
);
477 assert (papriv
->first
== priv
);
478 papriv
->first
= next
;
482 assert (next
->prev
== priv
);
486 vlc_mutex_unlock (&papriv
->tree_lock
);
488 if (likely(refs
== 1))
490 assert (priv
->first
== NULL
); /* no children can be left */
492 int canc
= vlc_savecancel ();
493 vlc_object_destroy (obj
);
494 vlc_restorecancel (canc
);
496 vlc_object_release (parent
);
500 #undef vlc_list_children
502 * Gets the list of children of an object, and increment their reference
504 * @return a list (possibly empty) or NULL in case of error.
506 vlc_list_t
*vlc_list_children( vlc_object_t
*obj
)
508 vlc_list_t
*l
= malloc (sizeof (*l
));
509 if (unlikely(l
== NULL
))
515 vlc_object_internals_t
*priv
;
518 vlc_mutex_lock (&vlc_internals(obj
)->tree_lock
);
519 for (priv
= vlc_internals (obj
)->first
; priv
; priv
= priv
->next
)
524 l
->p_values
= malloc (count
* sizeof (vlc_value_t
));
525 if (unlikely(l
->p_values
== NULL
))
527 vlc_mutex_unlock (&vlc_internals(obj
)->tree_lock
);
536 for (priv
= vlc_internals (obj
)->first
; priv
; priv
= priv
->next
)
537 l
->p_values
[i
++].p_address
= vlc_object_hold (vlc_externals (priv
));
538 vlc_mutex_unlock (&vlc_internals(obj
)->tree_lock
);
542 /*****************************************************************************
543 * vlc_list_release: free a list previously allocated by vlc_list_find
544 *****************************************************************************
545 * This function decreases the refcount of all objects in the list and
547 *****************************************************************************/
548 void vlc_list_release( vlc_list_t
*p_list
)
550 for( int i
= 0; i
< p_list
->i_count
; i
++ )
551 vlc_object_release( p_list
->p_values
[i
].p_address
);
553 free( p_list
->p_values
);