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