asx: remove useless test
[vlc.git] / src / misc / objects.c
blobea8620a4e5c7625bf27eb28dc23906a7e2393b6e
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 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");
80 return;
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)
89 if (level > 0)
91 assert(level >= 2);
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;
119 if (cmd[0] == 't')
121 char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
123 psz_foo[0] = '|';
124 DumpStructure (obj, 0, psz_foo);
127 return VLC_SUCCESS;
130 static vlc_object_t *ObjectExists (vlc_object_t *root, void *obj)
132 if (root == 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);
145 return ret;
148 static int VarsCommand (vlc_object_t *obj, char const *cmd,
149 vlc_value_t oldval, vlc_value_t newval, void *data)
151 void *p;
153 (void) cmd; (void) oldval; (void) data;
155 if (sscanf (newval.psz_string, "%p", &p) == 1)
157 p = ObjectExists (obj, p);
158 if (p == NULL)
160 msg_Err (obj, "no such object: %s", newval.psz_string);
161 return VLC_ENOOBJ;
163 obj = p;
165 else
166 vlc_object_hold (obj);
168 PrintObject (obj, "");
169 DumpVariables (obj);
170 vlc_object_release (obj);
172 return VLC_SUCCESS;
175 #undef vlc_custom_create
176 void *vlc_custom_create (vlc_object_t *parent, size_t length,
177 const char *typename)
179 /* NOTE:
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))
192 return 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;
199 priv->prev = NULL;
200 priv->first = 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);
228 else
230 libvlc_int_t *self = (libvlc_int_t *)obj;
232 obj->obj.flags = 0;
233 obj->obj.libvlc = self;
234 obj->obj.parent = NULL;
235 priv->next = 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);
246 return obj;
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;
286 char *oldname;
288 vlc_mutex_lock (&name_lock);
289 oldname = priv->psz_name;
290 priv->psz_name = newname;
291 vlc_mutex_unlock (&name_lock);
293 free (oldname);
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);
301 char *name;
303 vlc_mutex_lock (&name_lock);
304 name = priv->psz_name ? strdup (priv->psz_name) : NULL;
305 vlc_mutex_unlock (&name_lock);
307 return name;
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 );
340 free( p_priv );
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);
359 return found;
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),
376 * or NULL on error.
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. */
387 #ifndef NDEBUG
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 )
398 return NULL;
399 msg_Err( p_this, "looking for object \"%s\"... FIXME XXX", psz_name );
400 #endif
402 vlc_mutex_lock (&name_lock);
403 p_found = FindName (p_this, psz_name);
404 vlc_mutex_unlock (&name_lock);
405 return p_found;
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 );
415 #ifndef NDEBUG
416 unsigned refs = atomic_fetch_add (&internals->refs, 1);
417 assert (refs > 0); /* Avoid obvious freed object uses */
418 #else
419 atomic_fetch_add (&internals->refs, 1);
420 #endif
421 return p_this;
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);
434 /* Fast path */
435 while (refs > 1)
437 if (atomic_compare_exchange_weak (&priv->refs, &refs, refs - 1))
438 return; /* There are still other references to the object */
440 assert (refs > 0);
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);
455 return;
458 /* Slow path */
459 vlc_object_internals_t *papriv = vlc_internals (parent);
461 vlc_mutex_lock (&papriv->tree_lock);
462 refs = atomic_fetch_sub (&priv->refs, 1);
463 assert (refs > 0);
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;
470 if (prev != NULL)
472 assert (prev->next == priv);
473 prev->next = next;
475 else
477 assert (papriv->first == priv);
478 papriv->first = next;
480 if (next != NULL)
482 assert (next->prev == priv);
483 next->prev = prev;
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
503 * count.
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))
510 return NULL;
512 l->i_count = 0;
513 l->p_values = NULL;
515 vlc_object_internals_t *priv;
516 unsigned count = 0;
518 vlc_mutex_lock (&vlc_internals(obj)->tree_lock);
519 for (priv = vlc_internals (obj)->first; priv; priv = priv->next)
520 count++;
522 if (count > 0)
524 l->p_values = vlc_alloc (count, sizeof (vlc_value_t));
525 if (unlikely(l->p_values == NULL))
527 vlc_mutex_unlock (&vlc_internals(obj)->tree_lock);
528 free (l);
529 return NULL;
531 l->i_count = count;
534 unsigned i = 0;
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);
539 return l;
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
546 * frees the list.
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 );
554 free( p_list );