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