]> git.sesse.net Git - vlc/blob - src/misc/objects.c
objects: Export vlc_object_dump() to debug.
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2004-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /**
25  * \file
26  * This file contains the functions to handle the vlc_object_t type
27  */
28
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <vlc/vlc.h>
38
39 #include "../libvlc.h"
40 #include <vlc_vout.h>
41 #include <vlc_aout.h>
42 #include "audio_output/aout_internal.h"
43
44 #include <vlc_access.h>
45 #include <vlc_demux.h>
46 #include <vlc_stream.h>
47
48 #include <vlc_sout.h>
49 #include "stream_output/stream_output.h"
50
51 #include "vlc_interface.h"
52 #include "vlc_codec.h"
53 #include "vlc_filter.h"
54
55 #include "variables.h"
56 #ifndef WIN32
57 # include <unistd.h>
58 #else
59 # include <io.h>
60 # include <fcntl.h>
61 # include <errno.h> /* ENOSYS */
62 #endif
63 #include <assert.h>
64
65 /*****************************************************************************
66  * Constants
67  *****************************************************************************/
68
69 const vlc_destructor_t kVLCDestructor = NULL;
70
71 /*****************************************************************************
72  * Local prototypes
73  *****************************************************************************/
74 static int  DumpCommand( vlc_object_t *, char const *,
75                          vlc_value_t, vlc_value_t, void * );
76
77 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
78 static vlc_object_t * FindObjectName( vlc_object_t *, const char *, int );
79 static void           DetachObject  ( vlc_object_t * );
80 static void           PrintObject   ( vlc_object_t *, const char * );
81 static void           DumpStructure ( vlc_object_t *, int, char * );
82 static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
83 static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
84
85 static vlc_list_t   * NewList       ( int );
86 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
87 /*static void           ListAppend    ( vlc_list_t *, vlc_object_t * );*/
88 static int            CountChildren ( vlc_object_t *, int );
89 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
90
91 static void vlc_object_destroy( vlc_object_t *p_this );
92 static void vlc_object_yield_locked( vlc_object_t *p_this );
93
94 /*****************************************************************************
95  * Local structure lock
96  *****************************************************************************/
97 static vlc_mutex_t    structure_lock;
98
99 void *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
100                          int i_type, const char *psz_type )
101 {
102     vlc_object_t *p_new;
103     vlc_object_internals_t *p_priv;
104
105     p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
106     if( p_priv == NULL )
107         return NULL;
108
109     if( i_type == VLC_OBJECT_GLOBAL )
110         p_new = p_this;
111     else
112     {
113         assert (i_size >= sizeof (vlc_object_t));
114         p_new = (vlc_object_t *)(p_priv + 1);
115     }
116
117     p_new->p_internals = p_priv;
118     p_new->i_object_type = i_type;
119     p_new->psz_object_type = psz_type;
120
121     p_new->psz_object_name = NULL;
122
123     p_new->b_die = VLC_FALSE;
124     p_new->b_error = VLC_FALSE;
125     p_new->b_dead = VLC_FALSE;
126     p_priv->b_attached = VLC_FALSE;
127     p_new->b_force = VLC_FALSE;
128
129     p_new->psz_header = NULL;
130
131     p_new->i_flags |= p_this->i_flags
132         & (OBJECT_FLAGS_NODBG|OBJECT_FLAGS_QUIET|OBJECT_FLAGS_NOINTERACT);
133
134     p_priv->p_vars = calloc( sizeof( variable_t ), 16 );
135
136     if( !p_priv->p_vars )
137     {
138         free( p_priv );
139         return NULL;
140     }
141
142     if( i_type == VLC_OBJECT_GLOBAL )
143     {
144         /* If i_type is global, then p_new is actually p_libvlc_global */
145         libvlc_global_data_t *p_libvlc_global = (libvlc_global_data_t *)p_new;
146         p_new->p_libvlc = NULL;
147
148         p_libvlc_global->i_counter = 0;
149         p_new->i_object_id = 0;
150
151         p_libvlc_global->i_objects = 1;
152         p_libvlc_global->pp_objects = malloc( sizeof(vlc_object_t *) );
153         p_libvlc_global->pp_objects[0] = p_new;
154         p_priv->b_attached = VLC_TRUE;
155         vlc_mutex_init( p_new, &structure_lock );
156     }
157     else
158     {
159         libvlc_global_data_t *p_libvlc_global = vlc_global();
160         if( i_type == VLC_OBJECT_LIBVLC )
161         {
162             p_new->p_libvlc = (libvlc_int_t*)p_new;
163             p_priv->b_attached = VLC_TRUE;
164         }
165         else
166         {
167             p_new->p_libvlc = p_this->p_libvlc;
168         }
169
170         vlc_mutex_lock( &structure_lock );
171
172         p_libvlc_global->i_counter++;
173         p_new->i_object_id = p_libvlc_global->i_counter;
174
175         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
176          * useless to try and recover anything if pp_objects gets smashed. */
177         TAB_APPEND( p_libvlc_global->i_objects, p_libvlc_global->pp_objects,
178                     p_new );
179
180         vlc_mutex_unlock( &structure_lock );
181     }
182
183     p_priv->i_refcount = 1;
184     p_priv->pf_destructor = kVLCDestructor;
185     p_priv->b_thread = VLC_FALSE;
186     p_new->p_parent = NULL;
187     p_new->pp_children = NULL;
188     p_new->i_children = 0;
189
190     p_new->p_private = NULL;
191
192     /* Initialize mutexes and condvars */
193     vlc_mutex_init( p_new, &p_new->object_lock );
194     vlc_cond_init( p_new, &p_new->object_wait );
195     vlc_mutex_init( p_new, &p_priv->var_lock );
196     vlc_spin_init( &p_priv->spin );
197     p_priv->pipes[0] = p_priv->pipes[1] = -1;
198
199     if( i_type == VLC_OBJECT_LIBVLC )
200     {
201         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
202         var_AddCallback( p_new, "list", DumpCommand, NULL );
203         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
204         var_AddCallback( p_new, "tree", DumpCommand, NULL );
205         var_Create( p_new, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
206         var_AddCallback( p_new, "vars", DumpCommand, NULL );
207     }
208
209     return p_new;
210 }
211
212
213 /**
214  * Allocates and initializes a vlc object.
215  *
216  * @param i_type known object type (all of them are negative integer values),
217  *               or object byte size (always positive).
218  *
219  * @return the new object, or NULL on error.
220  */
221 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
222 {
223     const char   * psz_type;
224     size_t         i_size;
225
226     switch( i_type )
227     {
228         case VLC_OBJECT_LIBVLC:
229             i_size = sizeof(libvlc_int_t);
230             psz_type = "libvlc";
231             break;
232         case VLC_OBJECT_INTF:
233             i_size = sizeof(intf_thread_t);
234             psz_type = "interface";
235             break;
236         case VLC_OBJECT_DIALOGS:
237             i_size = sizeof(intf_thread_t);
238             psz_type = "dialogs";
239             break;
240         case VLC_OBJECT_DEMUX:
241             i_size = sizeof(demux_t);
242             psz_type = "demux";
243             break;
244         case VLC_OBJECT_ACCESS:
245             i_size = sizeof(access_t);
246             psz_type = "access";
247             break;
248         case VLC_OBJECT_DECODER:
249             i_size = sizeof(decoder_t);
250             psz_type = "decoder";
251             break;
252         case VLC_OBJECT_PACKETIZER:
253             i_size = sizeof(decoder_t);
254             psz_type = "packetizer";
255             break;
256         case VLC_OBJECT_ENCODER:
257             i_size = sizeof(encoder_t);
258             psz_type = "encoder";
259             break;
260         case VLC_OBJECT_FILTER:
261             i_size = sizeof(filter_t);
262             psz_type = "filter";
263             break;
264         case VLC_OBJECT_VOUT:
265             i_size = sizeof(vout_thread_t);
266             psz_type = "video output";
267             break;
268         case VLC_OBJECT_AOUT:
269             i_size = sizeof(aout_instance_t);
270             psz_type = "audio output";
271             break;
272         case VLC_OBJECT_SOUT:
273             i_size = sizeof(sout_instance_t);
274             psz_type = "stream output";
275             break;
276         case VLC_OBJECT_OPENGL:
277             i_size = sizeof( vout_thread_t );
278             psz_type = "opengl";
279             break;
280         case VLC_OBJECT_ANNOUNCE:
281             i_size = sizeof( announce_handler_t );
282             psz_type = "announce";
283             break;
284         case VLC_OBJECT_INTERACTION:
285             i_size = sizeof( interaction_t );
286             psz_type = "interaction";
287             break;
288         default:
289             i_size = i_type > (int)sizeof(vlc_object_t)
290                          ? i_type : (int)sizeof(vlc_object_t);
291             i_type = VLC_OBJECT_GENERIC;
292             psz_type = "generic";
293             break;
294     }
295
296     return vlc_custom_create( p_this, i_size, i_type, psz_type );
297 }
298
299
300 /**
301  ****************************************************************************
302  * Set the destructor of a vlc object
303  *
304  * This function sets the destructor of the vlc object. It will be called
305  * when the object is destroyed when the its refcount reaches 0.
306  * (It is called by the internal function vlc_object_destroy())
307  *****************************************************************************/
308 void __vlc_object_set_destructor( vlc_object_t *p_this,
309                                   vlc_destructor_t pf_destructor )
310 {
311     vlc_object_internals_t *p_priv = vlc_internals(p_this );
312
313     vlc_mutex_lock( &structure_lock );
314     p_priv->pf_destructor = pf_destructor;
315     vlc_mutex_unlock( &structure_lock );
316 }
317
318 /**
319  ****************************************************************************
320  * Destroy a vlc object (Internal)
321  *
322  * This function destroys an object that has been previously allocated with
323  * vlc_object_create. The object's refcount must be zero and it must not be
324  * attached to other objects in any way.
325  *****************************************************************************/
326 static void vlc_object_destroy( vlc_object_t *p_this )
327 {
328     vlc_object_internals_t *p_priv = vlc_internals( p_this );
329
330     /* Automatically detach the object from its parents */
331     if( p_this->p_parent ) vlc_object_detach( p_this );
332
333
334     /* Send a kill to the object's thread if applicable */
335     vlc_object_kill( p_this );
336
337     /* If we are running on a thread, wait until it ends */
338     if( p_priv->b_thread )
339         vlc_thread_join( p_this );
340
341     /* Call the custom "subclass" destructor */
342     if( p_priv->pf_destructor )
343         p_priv->pf_destructor( p_this );
344
345     /* Sanity checks */
346     if( p_this->i_children )
347     {
348         int i;
349
350         fprintf( stderr,
351                  "ERROR: cannot delete object (%i, %s) with %d children\n",
352                  p_this->i_object_id, p_this->psz_object_name,
353                  p_this->i_children );
354
355         for( i = 0; i < p_this->i_children; i++ )
356         {
357             fprintf( stderr,
358                      "ERROR: Remaining children object "
359                      "(id:%i, type:%s, name:%s)\n",
360                      p_this->pp_children[i]->i_object_id,
361                      p_this->pp_children[i]->psz_object_type,
362                      p_this->pp_children[i]->psz_object_name );
363         }
364         fflush(stderr);
365         abort();
366     }
367
368     /* Destroy the associated variables, starting from the end so that
369      * no memmove calls have to be done. */
370     while( p_priv->i_vars )
371     {
372         var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
373     }
374
375     free( p_priv->p_vars );
376     vlc_mutex_destroy( &p_priv->var_lock );
377
378     free( p_this->psz_header );
379
380     if( p_this->i_object_type == VLC_OBJECT_GLOBAL )
381     {
382         libvlc_global_data_t *p_global = (libvlc_global_data_t *)p_this;
383
384         /* Test for leaks */
385         if( p_global->i_objects > 0 )
386         {
387             int i;
388             for( i = 0; i < p_global->i_objects; i++ )
389             {
390                 /* We are leaking this object */
391                 fprintf( stderr,
392                          "ERROR: leaking object (id:%i, type:%s, name:%s)\n",
393                          p_global->pp_objects[i]->i_object_id,
394                          p_global->pp_objects[i]->psz_object_type,
395                          p_global->pp_objects[i]->psz_object_name );
396                 fflush(stderr);
397             }
398             /* Strongly abort, cause we want these to be fixed */
399             abort();
400         }
401
402         /* We are the global object ... no need to lock. */
403         free( p_global->pp_objects );
404         p_global->pp_objects = NULL;
405
406         vlc_mutex_destroy( &structure_lock );
407     }
408
409 #if defined(WIN32) || defined(UNDER_CE)
410     /* if object has an associated thread, close it now */
411     if( p_priv->thread_id.hThread )
412        CloseHandle(p_priv->thread_id.hThread);
413 #endif
414
415     vlc_mutex_destroy( &p_this->object_lock );
416     vlc_cond_destroy( &p_this->object_wait );
417     vlc_spin_destroy( &p_priv->spin );
418     if( p_priv->pipes[1] != -1 )
419         close( p_priv->pipes[1] );
420     if( p_priv->pipes[0] != -1 )
421         close( p_priv->pipes[0] );
422
423     free( p_priv );
424 }
425
426
427 /** Inter-object signaling */
428
429 void __vlc_object_lock( vlc_object_t *obj )
430 {
431     vlc_mutex_lock( &obj->object_lock );
432 }
433
434 void __vlc_object_unlock( vlc_object_t *obj )
435 {
436     vlc_assert_locked( &obj->object_lock );
437     vlc_mutex_unlock( &obj->object_lock );
438 }
439
440 #ifdef WIN32
441 # include <winsock2.h>
442 # include <ws2tcpip.h>
443
444 /**
445  * select()-able pipes emulated using Winsock
446  */
447 static int pipe (int fd[2])
448 {
449     SOCKADDR_IN addr;
450     int addrlen = sizeof (addr);
451
452     SOCKET l = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP), a,
453            c = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
454     if ((l == INVALID_SOCKET) || (c == INVALID_SOCKET))
455         goto error;
456
457     memset (&addr, 0, sizeof (addr));
458     addr.sin_family = AF_INET;
459     addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
460     if (bind (l, (PSOCKADDR)&addr, sizeof (addr))
461      || getsockname (l, (PSOCKADDR)&addr, &addrlen)
462      || listen (l, 1)
463      || connect (c, (PSOCKADDR)&addr, addrlen))
464         goto error;
465
466     a = accept (l, NULL, NULL);
467     if (a == INVALID_SOCKET)
468         goto error;
469
470     closesocket (l);
471     //shutdown (a, 0);
472     //shutdown (c, 1);
473     fd[0] = c;
474     fd[1] = a;
475     return 0;
476
477 error:
478     if (l != INVALID_SOCKET)
479         closesocket (l);
480     if (c != INVALID_SOCKET)
481         closesocket (c);
482     return -1;
483 }
484
485 #undef  read
486 #define read( a, b, c )  recv (a, b, c, 0)
487 #undef  write
488 #define write( a, b, c ) send (a, b, c, 0)
489 #undef  close
490 #define close( a )       closesocket (a)
491 #endif /* WIN32 */
492
493 /**
494  * Returns the readable end of a pipe that becomes readable once termination
495  * of the object is requested (vlc_object_kill()).
496  * This can be used to wake-up out of a select() or poll() event loop, such
497  * typically when doing network I/O.
498  *
499  * Note that the pipe will remain the same for the lifetime of the object.
500  * DO NOT read the pipe nor close it yourself. Ever.
501  *
502  * @param obj object that would be "killed"
503  * @return a readable pipe descriptor, or -1 on error.
504  */
505 int __vlc_object_waitpipe( vlc_object_t *obj )
506 {
507     int pfd[2] = { -1, -1 };
508     struct vlc_object_internals_t *internals = obj->p_internals;
509     vlc_bool_t killed = VLC_FALSE;
510
511     vlc_spin_lock (&internals->spin);
512     if (internals->pipes[0] == -1)
513     {
514         /* This can only ever happen if someone killed us without locking: */
515         assert (internals->pipes[1] == -1);
516         vlc_spin_unlock (&internals->spin);
517
518         if (pipe (pfd))
519             return -1;
520
521         vlc_spin_lock (&internals->spin);
522         if (internals->pipes[0] == -1)
523         {
524             internals->pipes[0] = pfd[0];
525             internals->pipes[1] = pfd[1];
526             pfd[0] = pfd[1] = -1;
527         }
528         killed = obj->b_die;
529     }
530     vlc_spin_unlock (&internals->spin);
531
532     if (killed)
533     {
534         /* Race condition: vlc_object_kill() already invoked! */
535         int fd;
536
537         vlc_spin_lock (&internals->spin);
538         fd = internals->pipes[1];
539         internals->pipes[1] = -1;
540         vlc_spin_unlock (&internals->spin);
541
542         msg_Dbg (obj, "waitpipe: object already dying");
543         if (fd != -1)
544             close (fd);
545     }
546
547     /* Race condition: two threads call pipe() - unlikely */
548     if (pfd[0] != -1)
549         close (pfd[0]);
550     if (pfd[1] != -1)
551         close (pfd[1]);
552
553     return internals->pipes[0];
554 }
555
556
557 /**
558  * Waits for the object to be signaled (using vlc_object_signal()).
559  * If the object already has a signal pending, this function will return
560  * immediately. It is asserted that the caller holds the object lock.
561  *
562  * @return true if the object is dying and should terminate.
563  */
564 vlc_bool_t __vlc_object_wait( vlc_object_t *obj )
565 {
566     vlc_assert_locked( &obj->object_lock );
567     vlc_cond_wait( &obj->object_wait, &obj->object_lock );
568     return obj->b_die;
569 }
570
571
572 /**
573  * Waits for the object to be signaled (using vlc_object_signal()), or for
574  * a timer to expire.
575  * If the object already has a signal pending, this function will return
576  * immediately. It is asserted that the caller holds the object lock.
577  *
578  * @return negative if the object is dying and should terminate,
579  * positive if the the object has been signaled but is not dying,
580  * 0 if timeout has been reached.
581  */
582 int __vlc_object_timedwait( vlc_object_t *obj, mtime_t deadline )
583 {
584     int v;
585
586     vlc_assert_locked( &obj->object_lock );
587     v = vlc_cond_timedwait( &obj->object_wait, &obj->object_lock, deadline );
588     if( v == 0 ) /* signaled */
589         return obj->b_die ? -1 : 1;
590     return 0;
591 }
592
593
594 /**
595  * Checks whether an object has been "killed".
596  * The object lock must be held.
597  *
598  * Typical code for an object thread could be:
599  *
600    vlc_object_lock (self);
601    ...initialization...
602    while (vlc_object_alive (self))
603    {
604        ...preprocessing...
605
606        if (vlc_object_wait (self))
607            continue;
608
609        ...postprocessing...
610    }
611    ...deinitialization...
612    vlc_object_unlock (self);
613  *
614  *
615  * @return true iff the object has not been killed yet
616  */
617 vlc_bool_t __vlc_object_alive( vlc_object_t *obj )
618 {
619     vlc_assert_locked( &obj->object_lock );
620     return !obj->b_die;
621 }
622
623
624 /**
625  * Signals an object for which the lock is held.
626  */
627 void __vlc_object_signal_unlocked( vlc_object_t *obj )
628 {
629     vlc_assert_locked (&obj->object_lock);
630     vlc_cond_signal( &obj->object_wait );
631 }
632
633
634 /**
635  * Requests termination of an object.
636  * If the object is LibVLC, also request to terminate all its children.
637  */
638 void __vlc_object_kill( vlc_object_t *p_this )
639 {
640     struct vlc_object_internals_t *internals = p_this->p_internals;
641     int fd;
642
643     vlc_mutex_lock( &p_this->object_lock );
644     p_this->b_die = VLC_TRUE;
645
646     vlc_spin_lock (&internals->spin);
647     fd = internals->pipes[1];
648     internals->pipes[1] = -1;
649     vlc_spin_unlock (&internals->spin);
650
651     if( fd != -1 )
652     {
653         msg_Dbg (p_this, "waitpipe: object killed");
654         close (fd);
655     }
656
657     if( p_this->i_object_type == VLC_OBJECT_LIBVLC )
658         for( int i = 0; i < p_this->i_children ; i++ )
659             vlc_object_kill( p_this->pp_children[i] );
660
661     vlc_object_signal_unlocked( p_this );
662     vlc_mutex_unlock( &p_this->object_lock );
663 }
664
665
666 /**
667  * find an object given its ID
668  *
669  * This function looks for the object whose i_object_id field is i_id. We
670  * use a dichotomy so that lookups are in log2(n).
671  *****************************************************************************/
672 void * vlc_object_get( int i_id )
673 {
674     int i_max, i_middle;
675     vlc_object_t **pp_objects;
676     libvlc_global_data_t *p_libvlc_global = vlc_global();
677
678     vlc_mutex_lock( &structure_lock );
679
680     pp_objects = p_libvlc_global->pp_objects;
681
682     /* Perform our dichotomy */
683     for( i_max = p_libvlc_global->i_objects - 1 ; ; )
684     {
685         i_middle = i_max / 2;
686
687         if( pp_objects[i_middle]->i_object_id > i_id )
688         {
689             i_max = i_middle;
690         }
691         else if( pp_objects[i_middle]->i_object_id < i_id )
692         {
693             if( i_middle )
694             {
695                 pp_objects += i_middle;
696                 i_max -= i_middle;
697             }
698             else
699             {
700                 /* This happens when there are only two remaining objects */
701                 if( pp_objects[i_middle+1]->i_object_id == i_id
702                     && pp_objects[i_middle+1]->p_internals->i_refcount > 0 )
703                 {
704                     vlc_object_yield_locked( pp_objects[i_middle+1] );
705                     vlc_mutex_unlock( &structure_lock );
706                     return pp_objects[i_middle+1];
707                 }
708                 break;
709             }
710         }
711         else if( pp_objects[i_middle]->p_internals->i_refcount > 0 )
712         {
713             vlc_object_yield_locked( pp_objects[i_middle] );
714             vlc_mutex_unlock( &structure_lock );
715             return pp_objects[i_middle];
716         }
717
718         if( i_max == 0 )
719         {
720             /* this means that i_max == i_middle, and since we have already
721              * tested pp_objects[i_middle]), p_found is properly set. */
722             break;
723         }
724     }
725
726     vlc_mutex_unlock( &structure_lock );
727     return NULL;
728 }
729
730 /**
731  ****************************************************************************
732  * find a typed object and increment its refcount
733  *****************************************************************************
734  * This function recursively looks for a given object type. i_mode can be one
735  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
736  *****************************************************************************/
737 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
738 {
739     vlc_object_t *p_found;
740
741     vlc_mutex_lock( &structure_lock );
742
743     /* If we are of the requested type ourselves, don't look further */
744     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type
745         && p_this->p_internals->i_refcount > 0 )
746     {
747         vlc_object_yield_locked( p_this );
748         vlc_mutex_unlock( &structure_lock );
749         return p_this;
750     }
751
752     /* Otherwise, recursively look for the object */
753     if( (i_mode & 0x000f) == FIND_ANYWHERE )
754     {
755         vlc_object_t *p_root = p_this;
756
757         /* Find the root */
758         while( p_root->p_parent != NULL &&
759                p_root != VLC_OBJECT( p_this->p_libvlc ) )
760         {
761             p_root = p_root->p_parent;
762         }
763
764         p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
765         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
766         {
767             p_found = FindObject( VLC_OBJECT( p_this->p_libvlc ),
768                                   i_type, (i_mode & ~0x000f)|FIND_CHILD );
769         }
770     }
771     else
772     {
773         p_found = FindObject( p_this, i_type, i_mode );
774     }
775
776     vlc_mutex_unlock( &structure_lock );
777
778     return p_found;
779 }
780
781 /**
782  ****************************************************************************
783  * find a named object and increment its refcount
784  *****************************************************************************
785  * This function recursively looks for a given object name. i_mode can be one
786  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
787  *****************************************************************************/
788 void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
789                                int i_mode )
790 {
791     vlc_object_t *p_found;
792
793     vlc_mutex_lock( &structure_lock );
794
795     /* Avoid obvious freed object uses */
796     assert( p_this->p_internals->i_refcount > 0 );
797
798     /* If have the requested name ourselves, don't look further */
799     if( !(i_mode & FIND_STRICT)
800         && p_this->psz_object_name
801         && !strcmp( p_this->psz_object_name, psz_name )
802         && p_this->p_internals->i_refcount > 0 )
803     {
804         vlc_object_yield_locked( p_this );
805         vlc_mutex_unlock( &structure_lock );
806         return p_this;
807     }
808
809     /* Otherwise, recursively look for the object */
810     if( (i_mode & 0x000f) == FIND_ANYWHERE )
811     {
812         vlc_object_t *p_root = p_this;
813
814         /* Find the root */
815         while( p_root->p_parent != NULL &&
816                p_root != VLC_OBJECT( p_this->p_libvlc ) )
817         {
818             p_root = p_root->p_parent;
819         }
820
821         p_found = FindObjectName( p_root, psz_name,
822                                  (i_mode & ~0x000f)|FIND_CHILD );
823         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
824         {
825             p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
826                                       psz_name, (i_mode & ~0x000f)|FIND_CHILD );
827         }
828     }
829     else
830     {
831         p_found = FindObjectName( p_this, psz_name, i_mode );
832     }
833
834     vlc_mutex_unlock( &structure_lock );
835
836     return p_found;
837 }
838
839 /**
840  ****************************************************************************
841  * increment an object refcount
842  *****************************************************************************/
843
844 /* When the structure_lock is locked */
845 static void vlc_object_yield_locked( vlc_object_t *p_this )
846 {
847     vlc_assert_locked (&structure_lock);
848
849     /* Avoid obvious freed object uses */
850     assert( p_this->p_internals->i_refcount > 0 );
851
852     /* Increment the counter */
853     p_this->p_internals->i_refcount++;
854 }
855
856 /* Public function */
857 void __vlc_object_yield( vlc_object_t *p_this )
858 {
859     vlc_mutex_lock( &structure_lock );
860     vlc_object_yield_locked( p_this );
861     vlc_mutex_unlock( &structure_lock );
862 }
863
864
865 /*****************************************************************************
866  * decrement an object refcount
867  * And destroy the object if its refcount reach zero.
868  *****************************************************************************/
869 void __vlc_object_release( vlc_object_t *p_this )
870 {
871     vlc_bool_t b_should_destroy;
872
873     vlc_mutex_lock( &structure_lock );
874
875     assert( p_this->p_internals->i_refcount > 0 );
876     p_this->p_internals->i_refcount--;
877     b_should_destroy = (p_this->p_internals->i_refcount == 0);
878
879     if( b_should_destroy )
880     {
881         /* Make sure this object can't be obtained via vlc_find_object now that
882          * it is freed */
883         libvlc_global_data_t *p_libvlc_global = vlc_global();
884         int i_index;
885
886         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
887          * useless to try and recover anything if pp_objects gets smashed. */
888         i_index = FindIndex( p_this, p_libvlc_global->pp_objects,
889                              p_libvlc_global->i_objects );
890         REMOVE_ELEM( p_libvlc_global->pp_objects,
891                      p_libvlc_global->i_objects, i_index );
892     }
893
894     vlc_mutex_unlock( &structure_lock );
895
896     if( b_should_destroy )
897         vlc_object_destroy( p_this );
898 }
899
900 /**
901  ****************************************************************************
902  * attach object to a parent object
903  *****************************************************************************
904  * This function sets p_this as a child of p_parent, and p_parent as a parent
905  * of p_this. This link can be undone using vlc_object_detach.
906  *****************************************************************************/
907 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
908 {
909     if( !p_this ) return;
910
911     vlc_mutex_lock( &structure_lock );
912
913     /* Avoid obvious freed object uses */
914     assert( p_this->p_internals->i_refcount > 0 );
915
916     /* Attach the parent to its child */
917     p_this->p_parent = p_parent;
918
919     /* Attach the child to its parent */
920     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
921                  p_parent->i_children, p_this );
922
923     /* Climb up the tree to see whether we are connected with the root */
924     if( p_parent->p_internals->b_attached )
925     {
926         SetAttachment( p_this, VLC_TRUE );
927     }
928
929     vlc_mutex_unlock( &structure_lock );
930 }
931
932 /**
933  ****************************************************************************
934  * detach object from its parent
935  *****************************************************************************
936  * This function removes all links between an object and its parent.
937  *****************************************************************************/
938 void __vlc_object_detach( vlc_object_t *p_this )
939 {
940     if( !p_this ) return;
941
942     vlc_mutex_lock( &structure_lock );
943
944     if( !p_this->p_parent )
945     {
946         msg_Err( p_this, "object is not attached" );
947         vlc_mutex_unlock( &structure_lock );
948         return;
949     }
950
951     /* Climb up the tree to see whether we are connected with the root */
952     if( p_this->p_parent->p_internals->b_attached )
953     {
954         SetAttachment( p_this, VLC_FALSE );
955     }
956
957     DetachObject( p_this );
958     vlc_mutex_unlock( &structure_lock );
959     p_this = NULL;
960 }
961
962 /**
963  ****************************************************************************
964  * find a list typed objects and increment their refcount
965  *****************************************************************************
966  * This function recursively looks for a given object type. i_mode can be one
967  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
968  *****************************************************************************/
969 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
970 {
971     vlc_list_t *p_list;
972     vlc_object_t **pp_current, **pp_end;
973     int i_count = 0, i_index = 0;
974     libvlc_global_data_t *p_libvlc_global = vlc_global();
975
976     vlc_mutex_lock( &structure_lock );
977
978     /* Look for the objects */
979     switch( i_mode & 0x000f )
980     {
981     case FIND_ANYWHERE:
982         pp_current = p_libvlc_global->pp_objects;
983         pp_end = pp_current + p_libvlc_global->i_objects;
984
985         for( ; pp_current < pp_end ; pp_current++ )
986         {
987             if( (*pp_current)->p_internals->b_attached
988                  && (*pp_current)->i_object_type == i_type )
989             {
990                 i_count++;
991             }
992         }
993
994         p_list = NewList( i_count );
995         pp_current = p_libvlc_global->pp_objects;
996
997         for( ; pp_current < pp_end ; pp_current++ )
998         {
999             if( (*pp_current)->p_internals->b_attached
1000                  && (*pp_current)->i_object_type == i_type )
1001             {
1002                 ListReplace( p_list, *pp_current, i_index );
1003                 if( i_index < i_count ) i_index++;
1004             }
1005         }
1006     break;
1007
1008     case FIND_CHILD:
1009         i_count = CountChildren( p_this, i_type );
1010         p_list = NewList( i_count );
1011
1012         /* Check allocation was successful */
1013         if( p_list->i_count != i_count )
1014         {
1015             msg_Err( p_this, "list allocation failed!" );
1016             p_list->i_count = 0;
1017             break;
1018         }
1019
1020         p_list->i_count = 0;
1021         ListChildren( p_list, p_this, i_type );
1022         break;
1023
1024     default:
1025         msg_Err( p_this, "unimplemented!" );
1026         p_list = NewList( 0 );
1027         break;
1028     }
1029
1030     vlc_mutex_unlock( &structure_lock );
1031
1032     return p_list;
1033 }
1034
1035 /*****************************************************************************
1036  * DumpCommand: print the current vlc structure
1037  *****************************************************************************
1038  * This function prints either an ASCII tree showing the connections between
1039  * vlc objects, and additional information such as their refcount, thread ID,
1040  * etc. (command "tree"), or the same data as a simple list (command "list").
1041  *****************************************************************************/
1042 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
1043                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
1044 {
1045     libvlc_global_data_t *p_libvlc_global = vlc_global();
1046
1047     (void)oldval; (void)p_data;
1048     if( *psz_cmd == 'l' )
1049     {
1050         vlc_mutex_lock( &structure_lock );
1051
1052         vlc_object_t **pp_current, **pp_end;
1053
1054         pp_current = p_libvlc_global->pp_objects;
1055         pp_end = pp_current + p_libvlc_global->i_objects;
1056
1057         for( ; pp_current < pp_end ; pp_current++ )
1058         {
1059             if( (*pp_current)->p_internals->b_attached )
1060             {
1061                 PrintObject( *pp_current, "" );
1062             }
1063             else
1064             {
1065                 printf( " o %.8i %s (not attached)\n",
1066                         (*pp_current)->i_object_id,
1067                         (*pp_current)->psz_object_type );
1068             }
1069         }
1070
1071         vlc_mutex_unlock( &structure_lock );
1072     }
1073     else
1074     {
1075         vlc_object_t *p_object = NULL;
1076
1077         if( *newval.psz_string )
1078         {
1079             char *end;
1080             int i_id = strtol( newval.psz_string, &end, 0 );
1081             if( end != newval.psz_string )
1082                 p_object = vlc_object_get( i_id );
1083             else
1084             {
1085                 /* try using the object's name to find it */
1086                 vlc_object_t *p_libvlc = vlc_object_get( 1 );
1087                 if( p_libvlc )
1088                 {
1089                     /* Look in p_libvlc's children tree */
1090                     p_object = vlc_object_find_name( p_libvlc,
1091                                                      newval.psz_string,
1092                                                      FIND_CHILD );
1093                     vlc_object_release( p_libvlc );
1094                 }
1095                 if( !p_object )
1096                 {
1097                     /* If it's not in libvlc, look in libvlc_global (== p_this) */
1098                     p_object = vlc_object_find_name( p_this,
1099                                                      newval.psz_string,
1100                                                      FIND_CHILD );
1101                 }
1102             }
1103
1104             if( !p_object )
1105             {
1106                 return VLC_ENOOBJ;
1107             }
1108         }
1109
1110         vlc_mutex_lock( &structure_lock );
1111
1112         if( *psz_cmd == 't' )
1113         {
1114             char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
1115
1116             if( !p_object )
1117                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
1118
1119             psz_foo[0] = '|';
1120             DumpStructure( p_object, 0, psz_foo );
1121         }
1122         else if( *psz_cmd == 'v' )
1123         {
1124             int i;
1125
1126             if( !p_object )
1127                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
1128
1129             PrintObject( p_object, "" );
1130
1131             if( !p_object->p_internals->i_vars )
1132                 printf( " `-o No variables\n" );
1133             for( i = 0; i < p_object->p_internals->i_vars; i++ )
1134             {
1135                 variable_t *p_var = p_object->p_internals->p_vars + i;
1136
1137                 const char *psz_type = "unknown";
1138                 switch( p_var->i_type & VLC_VAR_TYPE )
1139                 {
1140 #define MYCASE( type, nice )                \
1141                     case VLC_VAR_ ## type:  \
1142                         psz_type = nice;    \
1143                         break;
1144                     MYCASE( VOID, "void" );
1145                     MYCASE( BOOL, "bool" );
1146                     MYCASE( INTEGER, "integer" );
1147                     MYCASE( HOTKEY, "hotkey" );
1148                     MYCASE( STRING, "string" );
1149                     MYCASE( MODULE, "module" );
1150                     MYCASE( FILE, "file" );
1151                     MYCASE( DIRECTORY, "directory" );
1152                     MYCASE( VARIABLE, "variable" );
1153                     MYCASE( FLOAT, "float" );
1154                     MYCASE( TIME, "time" );
1155                     MYCASE( ADDRESS, "address" );
1156                     MYCASE( MUTEX, "mutex" );
1157                     MYCASE( LIST, "list" );
1158 #undef MYCASE
1159                 }
1160                 printf( " %c-o \"%s\" (%s",
1161                         i + 1 == p_object->p_internals->i_vars ? '`' : '|',
1162                         p_var->psz_name, psz_type );
1163                 if( p_var->psz_text )
1164                     printf( ", %s", p_var->psz_text );
1165                 printf( ")" );
1166                 if( p_var->i_type & VLC_VAR_ISCOMMAND )
1167                     printf( ", command" );
1168                 if( p_var->i_entries )
1169                     printf( ", %d callbacks", p_var->i_entries );
1170                 switch( p_var->i_type & 0x00f0 )
1171                 {
1172                     case VLC_VAR_VOID:
1173                     case VLC_VAR_MUTEX:
1174                         break;
1175                     case VLC_VAR_BOOL:
1176                         printf( ": %s", p_var->val.b_bool ? "true" : "false" );
1177                         break;
1178                     case VLC_VAR_INTEGER:
1179                         printf( ": %d", p_var->val.i_int );
1180                         break;
1181                     case VLC_VAR_STRING:
1182                         printf( ": \"%s\"", p_var->val.psz_string );
1183                         break;
1184                     case VLC_VAR_FLOAT:
1185                         printf( ": %f", p_var->val.f_float );
1186                         break;
1187                     case VLC_VAR_TIME:
1188                         printf( ": " I64Fi, (int64_t)p_var->val.i_time );
1189                         break;
1190                     case VLC_VAR_ADDRESS:
1191                         printf( ": %p", p_var->val.p_address );
1192                         break;
1193                     case VLC_VAR_LIST:
1194                         printf( ": TODO" );
1195                         break;
1196                 }
1197                 printf( "\n" );
1198             }
1199         }
1200
1201         vlc_mutex_unlock( &structure_lock );
1202
1203         if( *newval.psz_string )
1204         {
1205             vlc_object_release( p_object );
1206         }
1207     }
1208
1209     return VLC_SUCCESS;
1210 }
1211
1212 /*****************************************************************************
1213  * vlc_list_release: free a list previously allocated by vlc_list_find
1214  *****************************************************************************
1215  * This function decreases the refcount of all objects in the list and
1216  * frees the list.
1217  *****************************************************************************/
1218 void vlc_list_release( vlc_list_t *p_list )
1219 {
1220     int i_index;
1221
1222     for( i_index = 0; i_index < p_list->i_count; i_index++ )
1223     {
1224         vlc_object_release( p_list->p_values[i_index].p_object );
1225     }
1226
1227     free( p_list->p_values );
1228     free( p_list );
1229 }
1230
1231 /*****************************************************************************
1232  * dump an object. (Debug function)
1233  *****************************************************************************/
1234 void __vlc_object_dump( vlc_object_t *p_this )
1235 {
1236     vlc_mutex_lock( &structure_lock );
1237     PrintObject( p_this, "vlc_object_dump: " );
1238     vlc_mutex_unlock( &structure_lock );
1239 }
1240
1241 /* Following functions are local */
1242
1243 /*****************************************************************************
1244  * FindIndex: find the index of an object in an array of objects
1245  *****************************************************************************
1246  * This function assumes that p_this can be found in pp_objects. It will not
1247  * crash if p_this cannot be found, but will return a wrong value. It is your
1248  * duty to check the return value if you are not certain that the object could
1249  * be found for sure.
1250  *****************************************************************************/
1251 static int FindIndex( vlc_object_t *p_this,
1252                       vlc_object_t **pp_objects, int i_count )
1253 {
1254     int i_middle = i_count / 2;
1255
1256     if( i_count == 0 )
1257     {
1258         return 0;
1259     }
1260
1261     if( pp_objects[i_middle] == p_this )
1262     {
1263         return i_middle;
1264     }
1265
1266     if( i_count == 1 )
1267     {
1268         return 0;
1269     }
1270
1271     /* We take advantage of the sorted array */
1272     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
1273     {
1274         return i_middle + FindIndex( p_this, pp_objects + i_middle,
1275                                              i_count - i_middle );
1276     }
1277     else
1278     {
1279         return FindIndex( p_this, pp_objects, i_middle );
1280     }
1281 }
1282
1283 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
1284 {
1285     int i;
1286     vlc_object_t *p_tmp;
1287
1288     switch( i_mode & 0x000f )
1289     {
1290     case FIND_PARENT:
1291         p_tmp = p_this->p_parent;
1292         if( p_tmp )
1293         {
1294             if( p_tmp->i_object_type == i_type
1295                 && p_tmp->p_internals->i_refcount > 0 )
1296             {
1297                 vlc_object_yield_locked( p_tmp );
1298                 return p_tmp;
1299             }
1300             else
1301             {
1302                 return FindObject( p_tmp, i_type, i_mode );
1303             }
1304         }
1305         break;
1306
1307     case FIND_CHILD:
1308         for( i = p_this->i_children; i--; )
1309         {
1310             p_tmp = p_this->pp_children[i];
1311             if( p_tmp->i_object_type == i_type
1312                 && p_tmp->p_internals->i_refcount > 0 )
1313             {
1314                 vlc_object_yield_locked( p_tmp );
1315                 return p_tmp;
1316             }
1317             else if( p_tmp->i_children )
1318             {
1319                 p_tmp = FindObject( p_tmp, i_type, i_mode );
1320                 if( p_tmp )
1321                 {
1322                     return p_tmp;
1323                 }
1324             }
1325         }
1326         break;
1327
1328     case FIND_ANYWHERE:
1329         /* Handled in vlc_object_find */
1330         break;
1331     }
1332
1333     return NULL;
1334 }
1335
1336 static vlc_object_t * FindObjectName( vlc_object_t *p_this,
1337                                       const char *psz_name,
1338                                       int i_mode )
1339 {
1340     int i;
1341     vlc_object_t *p_tmp;
1342
1343     switch( i_mode & 0x000f )
1344     {
1345     case FIND_PARENT:
1346         p_tmp = p_this->p_parent;
1347         if( p_tmp )
1348         {
1349             if( p_tmp->psz_object_name
1350                 && !strcmp( p_tmp->psz_object_name, psz_name )
1351                 && p_tmp->p_internals->i_refcount > 0 )
1352             {
1353                 vlc_object_yield_locked( p_tmp );
1354                 return p_tmp;
1355             }
1356             else
1357             {
1358                 return FindObjectName( p_tmp, psz_name, i_mode );
1359             }
1360         }
1361         break;
1362
1363     case FIND_CHILD:
1364         for( i = p_this->i_children; i--; )
1365         {
1366             p_tmp = p_this->pp_children[i];
1367             if( p_tmp->psz_object_name
1368                 && !strcmp( p_tmp->psz_object_name, psz_name )
1369                 && p_tmp->p_internals->i_refcount > 0 )
1370             {
1371                 vlc_object_yield_locked( p_tmp );
1372                 return p_tmp;
1373             }
1374             else if( p_tmp->i_children )
1375             {
1376                 p_tmp = FindObjectName( p_tmp, psz_name, i_mode );
1377                 if( p_tmp )
1378                 {
1379                     return p_tmp;
1380                 }
1381             }
1382         }
1383         break;
1384
1385     case FIND_ANYWHERE:
1386         /* Handled in vlc_object_find */
1387         break;
1388     }
1389
1390     return NULL;
1391 }
1392
1393 static void DetachObject( vlc_object_t *p_this )
1394 {
1395     vlc_object_t *p_parent = p_this->p_parent;
1396     int i_index, i;
1397
1398     /* Remove p_this's parent */
1399     p_this->p_parent = NULL;
1400
1401     /* Remove all of p_parent's children which are p_this */
1402     for( i_index = p_parent->i_children ; i_index-- ; )
1403     {
1404         if( p_parent->pp_children[i_index] == p_this )
1405         {
1406             p_parent->i_children--;
1407             for( i = i_index ; i < p_parent->i_children ; i++ )
1408             {
1409                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
1410             }
1411         }
1412     }
1413
1414     if( p_parent->i_children )
1415     {
1416         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
1417                                p_parent->i_children * sizeof(vlc_object_t *) );
1418     }
1419     else
1420     {
1421         free( p_parent->pp_children );
1422         p_parent->pp_children = NULL;
1423     }
1424 }
1425
1426 /*****************************************************************************
1427  * SetAttachment: recursively set the b_attached flag of a subtree.
1428  *****************************************************************************
1429  * This function is used by the attach and detach functions to propagate
1430  * the b_attached flag in a subtree.
1431  *****************************************************************************/
1432 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
1433 {
1434     int i_index;
1435
1436     for( i_index = p_this->i_children ; i_index-- ; )
1437     {
1438         SetAttachment( p_this->pp_children[i_index], b_attached );
1439     }
1440
1441     p_this->p_internals->b_attached = b_attached;
1442 }
1443
1444 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
1445 {
1446     char psz_children[20], psz_refcount[20], psz_thread[30], psz_name[50],
1447          psz_parent[20];
1448
1449     psz_name[0] = '\0';
1450     if( p_this->psz_object_name )
1451     {
1452         snprintf( psz_name, 49, " \"%s\"", p_this->psz_object_name );
1453         if( psz_name[48] )
1454             psz_name[48] = '\"';
1455     }
1456
1457     psz_children[0] = '\0';
1458     switch( p_this->i_children )
1459     {
1460         case 0:
1461             break;
1462         case 1:
1463             strcpy( psz_children, ", 1 child" );
1464             break;
1465         default:
1466             snprintf( psz_children, 19, ", %i children", p_this->i_children );
1467             break;
1468     }
1469
1470     psz_refcount[0] = '\0';
1471     if( p_this->p_internals->i_refcount > 0 )
1472         snprintf( psz_refcount, 19, ", refcount %u",
1473                   p_this->p_internals->i_refcount );
1474
1475     psz_thread[0] = '\0';
1476     if( p_this->p_internals->b_thread )
1477         snprintf( psz_thread, 29, " (thread %u)",
1478 #if defined(WIN32) || defined(UNDER_CE)
1479                   (unsigned)p_this->p_internals->thread_id.id );
1480 #else
1481                   (unsigned)p_this->p_internals->thread_id );
1482 #endif
1483
1484     psz_parent[0] = '\0';
1485     if( p_this->p_parent )
1486         snprintf( psz_parent, 19, ", parent %i", p_this->p_parent->i_object_id );
1487
1488     printf( " %so %.8i %s%s%s%s%s%s\n", psz_prefix,
1489             p_this->i_object_id, p_this->psz_object_type,
1490             psz_name, psz_thread, psz_refcount, psz_children,
1491             psz_parent );
1492 }
1493
1494 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
1495 {
1496     int i;
1497     char i_back = psz_foo[i_level];
1498     psz_foo[i_level] = '\0';
1499
1500     PrintObject( p_this, psz_foo );
1501
1502     psz_foo[i_level] = i_back;
1503
1504     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
1505     {
1506         msg_Warn( p_this, "structure tree is too deep" );
1507         return;
1508     }
1509
1510     for( i = 0 ; i < p_this->i_children ; i++ )
1511     {
1512         if( i_level )
1513         {
1514             psz_foo[i_level-1] = ' ';
1515
1516             if( psz_foo[i_level-2] == '`' )
1517             {
1518                 psz_foo[i_level-2] = ' ';
1519             }
1520         }
1521
1522         if( i == p_this->i_children - 1 )
1523         {
1524             psz_foo[i_level] = '`';
1525         }
1526         else
1527         {
1528             psz_foo[i_level] = '|';
1529         }
1530
1531         psz_foo[i_level+1] = '-';
1532         psz_foo[i_level+2] = '\0';
1533
1534         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
1535     }
1536 }
1537
1538 static vlc_list_t * NewList( int i_count )
1539 {
1540     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
1541     if( p_list == NULL )
1542     {
1543         return NULL;
1544     }
1545
1546     p_list->i_count = i_count;
1547
1548     if( i_count == 0 )
1549     {
1550         p_list->p_values = NULL;
1551         return p_list;
1552     }
1553
1554     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
1555     if( p_list->p_values == NULL )
1556     {
1557         p_list->i_count = 0;
1558         return p_list;
1559     }
1560
1561     return p_list;
1562 }
1563
1564 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
1565                          int i_index )
1566 {
1567     if( p_list == NULL || i_index >= p_list->i_count )
1568     {
1569         return;
1570     }
1571
1572     vlc_object_yield_locked( p_object );
1573
1574     p_list->p_values[i_index].p_object = p_object;
1575
1576     return;
1577 }
1578
1579 /*static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
1580 {
1581     if( p_list == NULL )
1582     {
1583         return;
1584     }
1585
1586     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1587                                 * sizeof( vlc_value_t ) );
1588     if( p_list->p_values == NULL )
1589     {
1590         p_list->i_count = 0;
1591         return;
1592     }
1593
1594     vlc_object_yield_locked( p_object );
1595
1596     p_list->p_values[p_list->i_count].p_object = p_object;
1597     p_list->i_count++;
1598
1599     return;
1600 }*/
1601
1602 static int CountChildren( vlc_object_t *p_this, int i_type )
1603 {
1604     vlc_object_t *p_tmp;
1605     int i, i_count = 0;
1606
1607     for( i = 0; i < p_this->i_children; i++ )
1608     {
1609         p_tmp = p_this->pp_children[i];
1610
1611         if( p_tmp->i_object_type == i_type )
1612         {
1613             i_count++;
1614         }
1615
1616         if( p_tmp->i_children )
1617         {
1618             i_count += CountChildren( p_tmp, i_type );
1619         }
1620     }
1621
1622     return i_count;
1623 }
1624
1625 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1626 {
1627     vlc_object_t *p_tmp;
1628     int i;
1629
1630     for( i = 0; i < p_this->i_children; i++ )
1631     {
1632         p_tmp = p_this->pp_children[i];
1633
1634         if( p_tmp->i_object_type == i_type )
1635         {
1636             ListReplace( p_list, p_tmp, p_list->i_count++ );
1637         }
1638
1639         if( p_tmp->i_children )
1640         {
1641             ListChildren( p_list, p_tmp, i_type );
1642         }
1643     }
1644 }