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