1 /*****************************************************************************
2 * objects.c: vlc_object_t handling
3 *****************************************************************************
4 * Copyright (C) 2004-2008 the VideoLAN team
6 * Authors: Samuel Hocevar <sam@zoy.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
25 * This file contains the functions to handle the vlc_object_t type
27 * Unless otherwise stated, functions in this file are not cancellation point.
28 * All functions in this file are safe w.r.t. deferred cancellation.
32 /*****************************************************************************
34 *****************************************************************************/
39 #include <vlc_common.h>
41 #include "../libvlc.h"
44 #include "audio_output/aout_internal.h"
46 #include <vlc_access.h>
47 #include <vlc_demux.h>
48 #include <vlc_stream.h>
51 #include "stream_output/stream_output.h"
53 #include "vlc_interface.h"
54 #include "vlc_codec.h"
55 #include "vlc_filter.h"
57 #include "variables.h"
63 # include <errno.h> /* ENOSYS */
67 /*****************************************************************************
69 *****************************************************************************/
70 static int DumpCommand( vlc_object_t *, char const *,
71 vlc_value_t, vlc_value_t, void * );
73 static vlc_object_t * FindObject ( vlc_object_t *, int, int );
74 static vlc_object_t * FindObjectName( vlc_object_t *, const char *, int );
75 static void PrintObject ( vlc_object_t *, const char * );
76 static void DumpStructure ( vlc_object_t *, int, char * );
78 static vlc_list_t * NewList ( int );
79 static void ListReplace ( vlc_list_t *, vlc_object_t *, int );
80 /*static void ListAppend ( vlc_list_t *, vlc_object_t * );*/
81 static int CountChildren ( vlc_object_t *, int );
82 static void ListChildren ( vlc_list_t *, vlc_object_t *, int );
84 static void vlc_object_destroy( vlc_object_t *p_this );
85 static void vlc_object_detach_unlocked (vlc_object_t *p_this);
86 static void vlc_object_dump( vlc_object_t *p_this );
88 /*****************************************************************************
89 * Local structure lock
90 *****************************************************************************/
91 static void close_nocancel (int fd)
93 int canc = vlc_savecancel ();
95 vlc_restorecancel (canc);
98 static void libvlc_lock (libvlc_int_t *p_libvlc)
100 vlc_mutex_lock (&(libvlc_priv (p_libvlc)->structure_lock));
103 static void libvlc_unlock (libvlc_int_t *p_libvlc)
105 vlc_mutex_unlock (&(libvlc_priv (p_libvlc)->structure_lock));
108 void *__vlc_custom_create( vlc_object_t *p_this, size_t i_size,
109 int i_type, const char *psz_type )
112 vlc_object_internals_t *p_priv;
115 * VLC objects are laid out as follow:
116 * - first the LibVLC-private per-object data,
117 * - then VLC_COMMON members from vlc_object_t,
118 * - finally, the type-specific data (if any).
120 * This function initializes the LibVLC and common data,
121 * and zeroes the rest.
123 p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
127 assert (i_size >= sizeof (vlc_object_t));
128 p_new = (vlc_object_t *)(p_priv + 1);
130 p_new->i_object_type = i_type;
131 p_new->psz_object_type = psz_type;
132 p_new->psz_object_name = NULL;
134 p_new->b_die = false;
135 p_new->b_error = false;
136 p_new->b_force = false;
138 p_new->psz_header = NULL;
141 p_new->i_flags = p_this->i_flags
142 & (OBJECT_FLAGS_NODBG|OBJECT_FLAGS_QUIET|OBJECT_FLAGS_NOINTERACT);
144 p_priv->p_vars = calloc( sizeof( variable_t ), 16 );
146 if( !p_priv->p_vars )
154 libvlc_int_t *self = (libvlc_int_t*)p_new;
155 p_new->p_libvlc = self;
156 vlc_mutex_init (&(libvlc_priv (self)->structure_lock));
157 p_this = p_priv->next = p_priv->prev = p_new;
160 p_new->p_libvlc = p_this->p_libvlc;
162 vlc_spin_init( &p_priv->ref_spin );
163 p_priv->i_refcount = 1;
164 p_priv->pf_destructor = NULL;
165 p_priv->b_thread = false;
166 p_new->p_parent = NULL;
167 p_priv->pp_children = NULL;
168 p_priv->i_children = 0;
170 p_new->p_private = NULL;
172 /* Initialize mutexes and condvars */
173 vlc_mutex_init( &p_priv->lock );
174 vlc_cond_init( &p_priv->wait );
175 vlc_mutex_init( &p_priv->var_lock );
176 vlc_spin_init( &p_priv->spin );
177 p_priv->pipes[0] = p_priv->pipes[1] = -1;
179 p_priv->next = p_this;
180 libvlc_lock (p_new->p_libvlc);
181 p_priv->prev = vlc_internals (p_this)->prev;
182 vlc_internals (p_this)->prev = p_new;
183 vlc_internals (p_priv->prev)->next = p_new;
184 libvlc_unlock (p_new->p_libvlc);
186 if (p_new == VLC_OBJECT(p_new->p_libvlc))
187 { /* TODO: should be in src/libvlc.c */
188 int canc = vlc_savecancel ();
189 var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
190 var_AddCallback( p_new, "list", DumpCommand, NULL );
191 var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
192 var_AddCallback( p_new, "tree", DumpCommand, NULL );
193 var_Create( p_new, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
194 var_AddCallback( p_new, "vars", DumpCommand, NULL );
195 vlc_restorecancel (canc);
203 * Allocates and initializes a vlc object.
205 * @param i_type known object type (all of them are negative integer values),
206 * or object byte size (always positive).
208 * @return the new object, or NULL on error.
210 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
212 const char * psz_type;
217 case VLC_OBJECT_INTF:
218 i_size = sizeof(intf_thread_t);
219 psz_type = "interface";
221 case VLC_OBJECT_DECODER:
222 i_size = sizeof(decoder_t);
223 psz_type = "decoder";
225 case VLC_OBJECT_PACKETIZER:
226 i_size = sizeof(decoder_t);
227 psz_type = "packetizer";
229 case VLC_OBJECT_ENCODER:
230 i_size = sizeof(encoder_t);
231 psz_type = "encoder";
233 case VLC_OBJECT_AOUT:
234 i_size = sizeof(aout_instance_t);
235 psz_type = "audio output";
238 assert( i_type > 0 ); /* unknown type?! */
240 i_type = VLC_OBJECT_GENERIC;
241 psz_type = "generic";
245 return vlc_custom_create( p_this, i_size, i_type, psz_type );
250 ****************************************************************************
251 * Set the destructor of a vlc object
253 * This function sets the destructor of the vlc object. It will be called
254 * when the object is destroyed when the its refcount reaches 0.
255 * (It is called by the internal function vlc_object_destroy())
256 *****************************************************************************/
257 void __vlc_object_set_destructor( vlc_object_t *p_this,
258 vlc_destructor_t pf_destructor )
260 vlc_object_internals_t *p_priv = vlc_internals(p_this );
261 p_priv->pf_destructor = pf_destructor;
265 ****************************************************************************
266 * Destroy a vlc object (Internal)
268 * This function destroys an object that has been previously allocated with
269 * vlc_object_create. The object's refcount must be zero and it must not be
270 * attached to other objects in any way.
272 * This function must be called with cancellation disabled (currently).
273 *****************************************************************************/
274 static void vlc_object_destroy( vlc_object_t *p_this )
276 vlc_object_internals_t *p_priv = vlc_internals( p_this );
278 /* Objects are always detached beforehand */
279 assert( !p_this->p_parent );
281 /* Send a kill to the object's thread if applicable */
282 vlc_object_kill( p_this );
284 /* Call the custom "subclass" destructor */
285 if( p_priv->pf_destructor )
286 p_priv->pf_destructor( p_this );
288 /* Any thread must have been cleaned up at this point. */
289 assert( !p_priv->b_thread );
291 /* Destroy the associated variables, starting from the end so that
292 * no memmove calls have to be done. */
293 while( p_priv->i_vars )
295 var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
298 free( p_priv->p_vars );
299 vlc_mutex_destroy( &p_priv->var_lock );
301 free( p_this->psz_header );
303 FREENULL( p_this->psz_object_name );
305 vlc_spin_destroy( &p_priv->ref_spin );
306 vlc_mutex_destroy( &p_priv->lock );
307 vlc_cond_destroy( &p_priv->wait );
308 vlc_spin_destroy( &p_priv->spin );
309 if( p_priv->pipes[1] != -1 )
310 close( p_priv->pipes[1] );
311 if( p_priv->pipes[0] != -1 )
312 close( p_priv->pipes[0] );
313 if( VLC_OBJECT(p_this->p_libvlc) == p_this )
314 vlc_mutex_destroy (&(libvlc_priv ((libvlc_int_t *)p_this)->structure_lock));
320 /** Inter-object signaling */
322 void __vlc_object_lock( vlc_object_t *obj )
324 vlc_mutex_lock( &(vlc_internals(obj)->lock) );
327 void __vlc_object_unlock( vlc_object_t *obj )
329 vlc_assert_locked( &(vlc_internals(obj)->lock) );
330 vlc_mutex_unlock( &(vlc_internals(obj)->lock) );
334 # include <winsock2.h>
335 # include <ws2tcpip.h>
338 * select()-able pipes emulated using Winsock
340 static int pipe (int fd[2])
343 int addrlen = sizeof (addr);
345 SOCKET l = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP), a,
346 c = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
347 if ((l == INVALID_SOCKET) || (c == INVALID_SOCKET))
350 memset (&addr, 0, sizeof (addr));
351 addr.sin_family = AF_INET;
352 addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
353 if (bind (l, (PSOCKADDR)&addr, sizeof (addr))
354 || getsockname (l, (PSOCKADDR)&addr, &addrlen)
356 || connect (c, (PSOCKADDR)&addr, addrlen))
359 a = accept (l, NULL, NULL);
360 if (a == INVALID_SOCKET)
371 if (l != INVALID_SOCKET)
373 if (c != INVALID_SOCKET)
379 #define read( a, b, c ) recv (a, b, c, 0)
381 #define write( a, b, c ) send (a, b, c, 0)
383 #define close( a ) closesocket (a)
387 * Returns the readable end of a pipe that becomes readable once termination
388 * of the object is requested (vlc_object_kill()).
389 * This can be used to wake-up out of a select() or poll() event loop, such
390 * typically when doing network I/O.
392 * Note that the pipe will remain the same for the lifetime of the object.
393 * DO NOT read the pipe nor close it yourself. Ever.
395 * @param obj object that would be "killed"
396 * @return a readable pipe descriptor, or -1 on error.
398 int vlc_object_waitpipe( vlc_object_t *obj )
400 int pfd[2] = { -1, -1 };
401 vlc_object_internals_t *internals = vlc_internals( obj );
404 vlc_spin_lock (&internals->spin);
405 if (internals->pipes[0] == -1)
407 /* This can only ever happen if someone killed us without locking: */
408 assert (internals->pipes[1] == -1);
409 vlc_spin_unlock (&internals->spin);
414 vlc_spin_lock (&internals->spin);
415 if (internals->pipes[0] == -1)
417 internals->pipes[0] = pfd[0];
418 internals->pipes[1] = pfd[1];
419 pfd[0] = pfd[1] = -1;
423 vlc_spin_unlock (&internals->spin);
427 /* Race condition: vlc_object_kill() already invoked! */
430 vlc_spin_lock (&internals->spin);
431 fd = internals->pipes[1];
432 internals->pipes[1] = -1;
433 vlc_spin_unlock (&internals->spin);
435 msg_Dbg (obj, "waitpipe: object already dying");
440 /* Race condition: two threads call pipe() - unlikely */
446 return internals->pipes[0];
451 * Suspends until another thread calls vlc_object_signal_unlocked().
452 * The thread may be woken up earlier due to limitations of the underlying
455 * In new code, please use vlc_cond_wait() instead.
457 * This function is a cancellation point. In case of cancellation, the object
458 * will be in locked state.
460 void __vlc_object_wait( vlc_object_t *obj )
462 vlc_object_internals_t *priv = vlc_internals( obj );
463 vlc_assert_locked( &priv->lock);
464 vlc_cond_wait( &priv->wait, &priv->lock );
469 * Wakes up one thread waiting on the object. If no thread are (yet) waiting,
472 * Please do not use this function in new code as we are trying to untangle
473 * objects and threads. Use vlc_cond_wait() instead.
475 void __vlc_object_signal_unlocked( vlc_object_t *obj )
477 vlc_assert_locked (&(vlc_internals(obj)->lock));
478 vlc_cond_signal( &(vlc_internals(obj)->wait) );
483 * Requests termination of an object.
484 * If the object is LibVLC, also request to terminate all its children.
486 void __vlc_object_kill( vlc_object_t *p_this )
488 vlc_object_internals_t *priv = vlc_internals( p_this );
491 vlc_thread_cancel( p_this );
492 vlc_object_lock( p_this );
493 p_this->b_die = true;
495 vlc_spin_lock (&priv->spin);
498 vlc_spin_unlock (&priv->spin);
502 msg_Dbg (p_this, "waitpipe: object killed");
506 vlc_cond_broadcast (&priv->wait);
507 /* This also serves as a memory barrier toward vlc_object_alive(): */
508 vlc_object_unlock( p_this );
512 /*****************************************************************************
513 * find a typed object and increment its refcount
514 *****************************************************************************
515 * This function recursively looks for a given object type. i_mode can be one
516 * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
517 *****************************************************************************/
518 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
520 vlc_object_t *p_found;
522 /* If we are of the requested type ourselves, don't look further */
523 if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
525 vlc_object_hold( p_this );
529 /* Otherwise, recursively look for the object */
530 if ((i_mode & 0x000f) == FIND_ANYWHERE)
533 if (i_type == VLC_OBJECT_PLAYLIST)
534 msg_Err (p_this, "using vlc_object_find(VLC_OBJECT_PLAYLIST) "
535 "instead of pl_Hold()");
537 return vlc_object_find (p_this->p_libvlc, i_type,
538 (i_mode & ~0x000f)|FIND_CHILD);
541 libvlc_lock (p_this->p_libvlc);
542 p_found = FindObject( p_this, i_type, i_mode );
543 libvlc_unlock (p_this->p_libvlc);
547 #undef vlc_object_find_name
549 * Finds a named object and increment its reference count.
550 * Beware that objects found in this manner can be "owned" by another thread,
551 * be of _any_ type, and be attached to any module (if any). With such an
552 * object reference, you can set or get object variables, emit log messages,
553 * and read write-once object parameters (psz_object_type, etc).
554 * You CANNOT cast the object to a more specific object type, and you
555 * definitely cannot invoke object type-specific callbacks with this.
557 * @param p_this object to search from
558 * @param psz_name name of the object to search for
559 * @param i_mode search direction: FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
561 * @return a matching object (must be released by the caller),
564 vlc_object_t *vlc_object_find_name( vlc_object_t *p_this,
565 const char *psz_name, int i_mode )
567 vlc_object_t *p_found;
569 /* If have the requested name ourselves, don't look further */
570 if( !(i_mode & FIND_STRICT)
571 && p_this->psz_object_name
572 && !strcmp( p_this->psz_object_name, psz_name ) )
574 vlc_object_hold( p_this );
578 libvlc_lock (p_this->p_libvlc);
580 /* Otherwise, recursively look for the object */
581 if( (i_mode & 0x000f) == FIND_ANYWHERE )
583 vlc_object_t *p_root = p_this;
586 while( p_root->p_parent != NULL &&
587 p_root != VLC_OBJECT( p_this->p_libvlc ) )
589 p_root = p_root->p_parent;
592 p_found = FindObjectName( p_root, psz_name,
593 (i_mode & ~0x000f)|FIND_CHILD );
594 if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
596 p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
597 psz_name, (i_mode & ~0x000f)|FIND_CHILD );
602 p_found = FindObjectName( p_this, psz_name, i_mode );
605 libvlc_unlock (p_this->p_libvlc);
610 * Increment an object reference counter.
612 void * __vlc_object_hold( vlc_object_t *p_this )
614 vlc_object_internals_t *internals = vlc_internals( p_this );
616 vlc_spin_lock( &internals->ref_spin );
617 /* Avoid obvious freed object uses */
618 assert( internals->i_refcount > 0 );
619 /* Increment the counter */
620 internals->i_refcount++;
621 vlc_spin_unlock( &internals->ref_spin );
625 /*****************************************************************************
626 * Decrement an object refcount
627 * And destroy the object if its refcount reach zero.
628 *****************************************************************************/
629 void __vlc_object_release( vlc_object_t *p_this )
631 vlc_object_internals_t *internals = vlc_internals( p_this );
632 vlc_object_t *parent = NULL;
633 bool b_should_destroy;
635 vlc_spin_lock( &internals->ref_spin );
636 assert( internals->i_refcount > 0 );
638 if( internals->i_refcount > 1 )
641 /* There are still other references to the object */
642 internals->i_refcount--;
643 vlc_spin_unlock( &internals->ref_spin );
646 vlc_spin_unlock( &internals->ref_spin );
649 /* Remember that we cannot hold the spin while waiting on the mutex */
650 libvlc_lock (p_this->p_libvlc);
651 /* Take the spin again. Note that another thread may have held the
652 * object in the (very short) mean time. */
653 vlc_spin_lock( &internals->ref_spin );
654 b_should_destroy = --internals->i_refcount == 0;
655 vlc_spin_unlock( &internals->ref_spin );
657 if( b_should_destroy )
659 /* We have no children */
660 assert (internals->i_children == 0);
661 parent = p_this->p_parent;
664 if( VLC_OBJECT(p_this->p_libvlc) == p_this )
667 vlc_object_t *leaked = internals->next;
668 while( leaked != p_this )
670 /* We are leaking this object */
672 "ERROR: leaking object (%p, type:%s, name:%s)\n",
673 leaked, leaked->psz_object_type,
674 leaked->psz_object_name );
675 /* Dump object to ease debugging */
676 vlc_object_dump( leaked );
678 leaked = vlc_internals (leaked)->next;
681 if( internals->next != p_this )
682 /* Dump libvlc object to ease debugging */
683 vlc_object_dump( p_this );
686 /* Remove the object from object list
687 * so that it cannot be encountered by vlc_object_get() */
688 vlc_internals (internals->next)->prev = internals->prev;
689 vlc_internals (internals->prev)->next = internals->next;
692 /* Detach from parent to protect against FIND_CHILDREN */
693 vlc_object_detach_unlocked (p_this);
695 libvlc_unlock (p_this->p_libvlc);
697 if( b_should_destroy )
701 canc = vlc_savecancel ();
702 vlc_object_destroy( p_this );
703 vlc_restorecancel (canc);
705 vlc_object_release (parent);
710 ****************************************************************************
711 * attach object to a parent object
712 *****************************************************************************
713 * This function sets p_this as a child of p_parent, and p_parent as a parent
714 * of p_this. This link can be undone using vlc_object_detach.
715 *****************************************************************************/
716 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
718 if( !p_this ) return;
720 vlc_object_hold (p_parent);
721 libvlc_lock (p_this->p_libvlc);
723 /* Attach the parent to its child */
724 assert (!p_this->p_parent);
725 p_this->p_parent = p_parent;
727 /* Attach the child to its parent */
728 vlc_object_internals_t *priv = vlc_internals( p_parent );
729 INSERT_ELEM( priv->pp_children, priv->i_children, priv->i_children,
731 libvlc_unlock (p_this->p_libvlc);
735 static void vlc_object_detach_unlocked (vlc_object_t *p_this)
737 if (p_this->p_parent == NULL)
740 vlc_object_internals_t *priv = vlc_internals( p_this->p_parent );
744 /* Remove p_this's parent */
745 p_this->p_parent = NULL;
747 /* Remove all of p_parent's children which are p_this */
748 for( i_index = priv->i_children ; i_index-- ; )
750 if( priv->pp_children[i_index] == p_this )
753 for( i = i_index ; i < priv->i_children ; i++ )
754 priv->pp_children[i] = priv->pp_children[i+1];
758 if( priv->i_children )
760 vlc_object_t **pp_children = (vlc_object_t **)
761 realloc( priv->pp_children,
762 priv->i_children * sizeof(vlc_object_t *) );
764 priv->pp_children = pp_children;
768 /* Special case - don't realloc() to zero to avoid leaking */
769 free( priv->pp_children );
770 priv->pp_children = NULL;
776 ****************************************************************************
777 * detach object from its parent
778 *****************************************************************************
779 * This function removes all links between an object and its parent.
780 *****************************************************************************/
781 void __vlc_object_detach( vlc_object_t *p_this )
783 vlc_object_t *p_parent;
784 if( !p_this ) return;
786 libvlc_lock (p_this->p_libvlc);
787 p_parent = p_this->p_parent;
789 vlc_object_detach_unlocked( p_this );
790 libvlc_unlock (p_this->p_libvlc);
793 vlc_object_release (p_parent);
798 ****************************************************************************
799 * find a list typed objects and increment their refcount
800 *****************************************************************************
801 * This function recursively looks for a given object type. i_mode can be one
802 * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
803 *****************************************************************************/
804 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
809 /* Look for the objects */
810 switch( i_mode & 0x000f )
813 return vlc_list_find (p_this->p_libvlc, i_type, FIND_CHILD);
816 libvlc_lock (p_this->p_libvlc);
817 i_count = CountChildren( p_this, i_type );
818 p_list = NewList( i_count );
820 /* Check allocation was successful */
821 if( p_list->i_count != i_count )
823 libvlc_unlock (p_this->p_libvlc);
829 ListChildren( p_list, p_this, i_type );
830 libvlc_unlock (p_this->p_libvlc);
834 msg_Err( p_this, "unimplemented!" );
835 p_list = NewList( 0 );
843 * Gets the list of children of an objects, and increment their reference
845 * @return a list (possibly empty) or NULL in case of error.
847 vlc_list_t *__vlc_list_children( vlc_object_t *obj )
850 vlc_object_internals_t *priv = vlc_internals( obj );
852 libvlc_lock (obj->p_libvlc);
853 l = NewList( priv->i_children );
854 for (int i = 0; i < l->i_count; i++)
856 vlc_object_hold( priv->pp_children[i] );
857 l->p_values[i].p_object = priv->pp_children[i];
859 libvlc_unlock (obj->p_libvlc);
863 /*****************************************************************************
864 * DumpCommand: print the current vlc structure
865 *****************************************************************************
866 * This function prints either an ASCII tree showing the connections between
867 * vlc objects, and additional information such as their refcount, thread ID,
868 * etc. (command "tree"), or the same data as a simple list (command "list").
869 *****************************************************************************/
870 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
871 vlc_value_t oldval, vlc_value_t newval, void *p_data )
873 libvlc_int_t *p_libvlc = p_this->p_libvlc;
875 (void)oldval; (void)p_data;
876 if( *psz_cmd == 'l' )
878 vlc_object_t *cur = VLC_OBJECT (p_libvlc);
880 libvlc_lock (p_this->p_libvlc);
883 PrintObject (cur, "");
884 cur = vlc_internals (cur)->next;
886 while (cur != VLC_OBJECT(p_libvlc));
887 libvlc_unlock (p_this->p_libvlc);
891 vlc_object_t *p_object = NULL;
893 if( *newval.psz_string )
895 /* try using the object's name to find it */
896 p_object = vlc_object_find_name( p_this, newval.psz_string,
904 libvlc_lock (p_this->p_libvlc);
905 if( *psz_cmd == 't' )
907 char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
910 p_object = VLC_OBJECT(p_this->p_libvlc);
913 DumpStructure( p_object, 0, psz_foo );
915 else if( *psz_cmd == 'v' )
920 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
922 PrintObject( p_object, "" );
924 if( !vlc_internals( p_object )->i_vars )
925 printf( " `-o No variables\n" );
926 for( i = 0; i < vlc_internals( p_object )->i_vars; i++ )
928 variable_t *p_var = vlc_internals( p_object )->p_vars + i;
930 const char *psz_type = "unknown";
931 switch( p_var->i_type & VLC_VAR_TYPE )
933 #define MYCASE( type, nice ) \
934 case VLC_VAR_ ## type: \
937 MYCASE( VOID, "void" );
938 MYCASE( BOOL, "bool" );
939 MYCASE( INTEGER, "integer" );
940 MYCASE( HOTKEY, "hotkey" );
941 MYCASE( STRING, "string" );
942 MYCASE( MODULE, "module" );
943 MYCASE( FILE, "file" );
944 MYCASE( DIRECTORY, "directory" );
945 MYCASE( VARIABLE, "variable" );
946 MYCASE( FLOAT, "float" );
947 MYCASE( TIME, "time" );
948 MYCASE( ADDRESS, "address" );
949 MYCASE( MUTEX, "mutex" );
950 MYCASE( LIST, "list" );
953 printf( " %c-o \"%s\" (%s",
954 i + 1 == vlc_internals( p_object )->i_vars ? '`' : '|',
955 p_var->psz_name, psz_type );
956 if( p_var->psz_text )
957 printf( ", %s", p_var->psz_text );
959 if( p_var->i_type & VLC_VAR_HASCHOICE )
960 printf( ", has choices" );
961 if( p_var->i_type & VLC_VAR_ISCOMMAND )
962 printf( ", command" );
963 if( p_var->i_entries )
964 printf( ", %d callbacks", p_var->i_entries );
965 switch( p_var->i_type & VLC_VAR_CLASS )
971 printf( ": %s", p_var->val.b_bool ? "true" : "false" );
973 case VLC_VAR_INTEGER:
974 printf( ": %d", p_var->val.i_int );
977 printf( ": \"%s\"", p_var->val.psz_string );
980 printf( ": %f", p_var->val.f_float );
983 printf( ": %"PRIi64, (int64_t)p_var->val.i_time );
985 case VLC_VAR_ADDRESS:
986 printf( ": %p", p_var->val.p_address );
995 libvlc_unlock (p_this->p_libvlc);
997 if( *newval.psz_string )
999 vlc_object_release( p_object );
1006 /*****************************************************************************
1007 * vlc_list_release: free a list previously allocated by vlc_list_find
1008 *****************************************************************************
1009 * This function decreases the refcount of all objects in the list and
1011 *****************************************************************************/
1012 void vlc_list_release( vlc_list_t *p_list )
1016 for( i_index = 0; i_index < p_list->i_count; i_index++ )
1018 vlc_object_release( p_list->p_values[i_index].p_object );
1021 free( p_list->p_values );
1025 /*****************************************************************************
1026 * dump an object. (Debug function)
1027 *****************************************************************************/
1028 static void vlc_object_dump( vlc_object_t *p_this )
1030 char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
1033 DumpStructure( p_this, 0, psz_foo );
1036 /* Following functions are local */
1038 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
1041 vlc_object_t *p_tmp;
1043 switch( i_mode & 0x000f )
1046 p_tmp = p_this->p_parent;
1049 if( p_tmp->i_object_type == i_type )
1051 vlc_object_hold( p_tmp );
1056 return FindObject( p_tmp, i_type, i_mode );
1062 for( i = vlc_internals( p_this )->i_children; i--; )
1064 p_tmp = vlc_internals( p_this )->pp_children[i];
1065 if( p_tmp->i_object_type == i_type )
1067 vlc_object_hold( p_tmp );
1070 else if( vlc_internals( p_tmp )->i_children )
1072 p_tmp = FindObject( p_tmp, i_type, i_mode );
1082 /* Handled in vlc_object_find */
1089 static vlc_object_t * FindObjectName( vlc_object_t *p_this,
1090 const char *psz_name,
1094 vlc_object_t *p_tmp;
1096 switch( i_mode & 0x000f )
1099 p_tmp = p_this->p_parent;
1102 if( p_tmp->psz_object_name
1103 && !strcmp( p_tmp->psz_object_name, psz_name ) )
1105 vlc_object_hold( p_tmp );
1110 return FindObjectName( p_tmp, psz_name, i_mode );
1116 for( i = vlc_internals( p_this )->i_children; i--; )
1118 p_tmp = vlc_internals( p_this )->pp_children[i];
1119 if( p_tmp->psz_object_name
1120 && !strcmp( p_tmp->psz_object_name, psz_name ) )
1122 vlc_object_hold( p_tmp );
1125 else if( vlc_internals( p_tmp )->i_children )
1127 p_tmp = FindObjectName( p_tmp, psz_name, i_mode );
1137 /* Handled in vlc_object_find */
1145 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
1147 char psz_children[20], psz_refcount[20], psz_thread[30], psz_name[50],
1150 int canc = vlc_savecancel ();
1151 memset( &psz_name, 0, sizeof(psz_name) );
1152 if( p_this->psz_object_name )
1154 snprintf( psz_name, 49, " \"%s\"", p_this->psz_object_name );
1156 psz_name[48] = '\"';
1159 psz_children[0] = '\0';
1160 switch( vlc_internals( p_this )->i_children )
1165 strcpy( psz_children, ", 1 child" );
1168 snprintf( psz_children, 19, ", %i children",
1169 vlc_internals( p_this )->i_children );
1173 psz_refcount[0] = '\0';
1174 if( vlc_internals( p_this )->i_refcount > 0 )
1175 snprintf( psz_refcount, 19, ", refcount %u",
1176 vlc_internals( p_this )->i_refcount );
1178 psz_thread[0] = '\0';
1179 if( vlc_internals( p_this )->b_thread )
1180 snprintf( psz_thread, 29, " (thread %lu)",
1181 (unsigned long)vlc_internals( p_this )->thread_id );
1183 psz_parent[0] = '\0';
1184 if( p_this->p_parent )
1185 snprintf( psz_parent, 19, ", parent %p", p_this->p_parent );
1187 printf( " %so %p %s%s%s%s%s%s\n", psz_prefix,
1188 p_this, p_this->psz_object_type,
1189 psz_name, psz_thread, psz_refcount, psz_children,
1191 vlc_restorecancel (canc);
1194 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
1197 char i_back = psz_foo[i_level];
1198 psz_foo[i_level] = '\0';
1200 PrintObject( p_this, psz_foo );
1202 psz_foo[i_level] = i_back;
1204 if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
1206 msg_Warn( p_this, "structure tree is too deep" );
1210 for( i = 0 ; i < vlc_internals( p_this )->i_children ; i++ )
1214 psz_foo[i_level-1] = ' ';
1216 if( psz_foo[i_level-2] == '`' )
1218 psz_foo[i_level-2] = ' ';
1222 if( i == vlc_internals( p_this )->i_children - 1 )
1224 psz_foo[i_level] = '`';
1228 psz_foo[i_level] = '|';
1231 psz_foo[i_level+1] = '-';
1232 psz_foo[i_level+2] = '\0';
1234 DumpStructure( vlc_internals( p_this )->pp_children[i], i_level + 2,
1239 static vlc_list_t * NewList( int i_count )
1241 vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
1242 if( p_list == NULL )
1247 p_list->i_count = i_count;
1251 p_list->p_values = NULL;
1255 p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
1256 if( p_list->p_values == NULL )
1258 p_list->i_count = 0;
1265 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
1268 if( p_list == NULL || i_index >= p_list->i_count )
1273 vlc_object_hold( p_object );
1275 p_list->p_values[i_index].p_object = p_object;
1280 /*static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
1282 if( p_list == NULL )
1287 p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1288 * sizeof( vlc_value_t ) );
1289 if( p_list->p_values == NULL )
1291 p_list->i_count = 0;
1295 vlc_object_hold( p_object );
1297 p_list->p_values[p_list->i_count].p_object = p_object;
1303 static int CountChildren( vlc_object_t *p_this, int i_type )
1305 vlc_object_t *p_tmp;
1308 for( i = 0; i < vlc_internals( p_this )->i_children; i++ )
1310 p_tmp = vlc_internals( p_this )->pp_children[i];
1312 if( p_tmp->i_object_type == i_type )
1316 i_count += CountChildren( p_tmp, i_type );
1322 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1324 vlc_object_t *p_tmp;
1327 for( i = 0; i < vlc_internals( p_this )->i_children; i++ )
1329 p_tmp = vlc_internals( p_this )->pp_children[i];
1331 if( p_tmp->i_object_type == i_type )
1332 ListReplace( p_list, p_tmp, p_list->i_count++ );
1334 ListChildren( p_list, p_tmp, i_type );