]> git.sesse.net Git - vlc/blob - src/misc/objects.c
Remove VOD object type - not actually needed
[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_tls.h"
60 #include "vlc_xml.h"
61 #include "vlc_osd.h"
62 #include "vlc_meta.h"
63
64 #include "variables.h"
65 #ifndef WIN32
66 # include <unistd.h>
67 #else
68 # include <io.h>
69 # include <fcntl.h>
70 # include <errno.h> /* ENOSYS */
71 #endif
72 #include <assert.h>
73
74 /*****************************************************************************
75  * Constants
76  *****************************************************************************/
77
78 const vlc_destructor_t kVLCDestructor = NULL;
79
80 /*****************************************************************************
81  * Local prototypes
82  *****************************************************************************/
83 static int  DumpCommand( vlc_object_t *, char const *,
84                          vlc_value_t, vlc_value_t, void * );
85
86 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
87 static vlc_object_t * FindObjectName( vlc_object_t *, const char *, int );
88 static void           DetachObject  ( vlc_object_t * );
89 static void           PrintObject   ( vlc_object_t *, const char * );
90 static void           DumpStructure ( vlc_object_t *, int, char * );
91 static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
92 static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
93
94 static vlc_list_t   * NewList       ( int );
95 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
96 /*static void           ListAppend    ( vlc_list_t *, vlc_object_t * );*/
97 static int            CountChildren ( vlc_object_t *, int );
98 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
99
100 static void vlc_object_destroy( vlc_object_t *p_this );
101 static void vlc_object_yield_locked( vlc_object_t *p_this );
102
103 /*****************************************************************************
104  * Local structure lock
105  *****************************************************************************/
106 static vlc_mutex_t    structure_lock;
107 static vlc_object_internals_t global_internals;
108
109 vlc_object_t *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
110                                  int i_type, const char *psz_type )
111 {
112     vlc_object_t *p_new;
113     vlc_object_internals_t *p_priv;
114
115     if( i_type == VLC_OBJECT_GLOBAL )
116     {
117         p_new = p_this;
118         p_priv = &global_internals;
119         memset( p_priv, 0, sizeof( *p_priv ) );
120     }
121     else
122     {
123         p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
124         if( p_priv == NULL )
125             return NULL;
126
127         p_new = (vlc_object_t *)(p_priv + 1);
128     }
129
130     p_new->p_internals = p_priv;
131     p_new->i_object_type = i_type;
132     p_new->psz_object_type = psz_type;
133
134     p_new->psz_object_name = NULL;
135
136     p_new->b_die = VLC_FALSE;
137     p_new->b_error = VLC_FALSE;
138     p_new->b_dead = VLC_FALSE;
139     p_priv->b_attached = VLC_FALSE;
140     p_new->b_force = VLC_FALSE;
141
142     p_new->psz_header = NULL;
143
144     if( p_this->i_flags & OBJECT_FLAGS_NODBG )
145         p_new->i_flags |= OBJECT_FLAGS_NODBG;
146     if( p_this->i_flags & OBJECT_FLAGS_QUIET )
147         p_new->i_flags |= OBJECT_FLAGS_QUIET;
148     if( p_this->i_flags & OBJECT_FLAGS_NOINTERACT )
149         p_new->i_flags |= OBJECT_FLAGS_NOINTERACT;
150
151     p_priv->p_vars = calloc( sizeof( variable_t ), 16 );
152
153     if( !p_priv->p_vars )
154     {
155         if( i_type != VLC_OBJECT_GLOBAL )
156             free( p_priv );
157         return NULL;
158     }
159
160     if( i_type == VLC_OBJECT_GLOBAL )
161     {
162         /* If i_type is global, then p_new is actually p_libvlc_global */
163         libvlc_global_data_t *p_libvlc_global = (libvlc_global_data_t *)p_new;
164         p_new->p_libvlc = NULL;
165
166         p_libvlc_global->i_counter = 0;
167         p_new->i_object_id = 0;
168
169         p_libvlc_global->i_objects = 1;
170         p_libvlc_global->pp_objects = malloc( sizeof(vlc_object_t *) );
171         p_libvlc_global->pp_objects[0] = p_new;
172         p_priv->b_attached = VLC_TRUE;
173     }
174     else
175     {
176         libvlc_global_data_t *p_libvlc_global = vlc_global();
177         if( i_type == VLC_OBJECT_LIBVLC )
178         {
179             p_new->p_libvlc = (libvlc_int_t*)p_new;
180             p_priv->b_attached = VLC_TRUE;
181         }
182         else
183         {
184             p_new->p_libvlc = p_this->p_libvlc;
185         }
186
187         vlc_mutex_lock( &structure_lock );
188
189         p_libvlc_global->i_counter++;
190         p_new->i_object_id = p_libvlc_global->i_counter;
191
192         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
193          * useless to try and recover anything if pp_objects gets smashed. */
194         TAB_APPEND( p_libvlc_global->i_objects, p_libvlc_global->pp_objects,
195                     p_new );
196
197         vlc_mutex_unlock( &structure_lock );
198     }
199
200     p_priv->i_refcount = 1;
201     p_priv->pf_destructor = kVLCDestructor;
202     p_priv->b_thread = VLC_FALSE;
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_XML:
323             i_size = sizeof( xml_t );
324             psz_type = "xml";
325             break;
326         case VLC_OBJECT_OPENGL:
327             i_size = sizeof( vout_thread_t );
328             psz_type = "opengl";
329             break;
330         case VLC_OBJECT_ANNOUNCE:
331             i_size = sizeof( announce_handler_t );
332             psz_type = "announce";
333             break;
334         case VLC_OBJECT_META_ENGINE:
335             i_size = sizeof( meta_engine_t );
336             psz_type = "meta engine";
337             break;
338         case VLC_OBJECT_OSDMENU:
339             i_size = sizeof( osd_menu_t );
340             psz_type = "osd menu";
341             break;
342         case VLC_OBJECT_INTERACTION:
343             i_size = sizeof( interaction_t );
344             psz_type = "interaction";
345             break;
346         default:
347             i_size = i_type > (int)sizeof(vlc_object_t)
348                          ? i_type : (int)sizeof(vlc_object_t);
349             i_type = VLC_OBJECT_GENERIC;
350             psz_type = "generic";
351             break;
352     }
353
354     return vlc_custom_create( p_this, i_size, i_type, psz_type );
355 }
356
357
358 /**
359  ****************************************************************************
360  * Set the destructor of a vlc object
361  *
362  * This function sets the destructor of the vlc object. It will be called
363  * when the object is destroyed when the its refcount reaches 0.
364  * (It is called by the internal function vlc_object_destroy())
365  *****************************************************************************/
366 void __vlc_object_set_destructor( vlc_object_t *p_this,
367                                   vlc_destructor_t pf_destructor )
368 {
369     vlc_object_internals_t *p_priv = vlc_internals(p_this );
370
371     vlc_mutex_lock( &structure_lock );
372     p_priv->pf_destructor = pf_destructor;
373     vlc_mutex_unlock( &structure_lock );
374 }
375
376 /**
377  ****************************************************************************
378  * Destroy a vlc object (Internal)
379  *
380  * This function destroys an object that has been previously allocated with
381  * vlc_object_create. The object's refcount must be zero and it must not be
382  * attached to other objects in any way.
383  *****************************************************************************/
384 static void vlc_object_destroy( vlc_object_t *p_this )
385 {
386     vlc_object_internals_t *p_priv = vlc_internals( p_this );
387
388     /* Automatically detach the object from its parents */
389     if( p_this->p_parent ) vlc_object_detach( p_this );
390
391
392     /* Send a kill to the object's thread if applicable */
393     vlc_object_kill( p_this );
394
395     /* If we are running on a thread, wait until it ends */
396     if( p_priv->b_thread )
397         vlc_thread_join( p_this );
398
399     /* Call the custom "subclass" destructor */
400     if( p_priv->pf_destructor )
401         p_priv->pf_destructor( p_this );
402
403     /* Sanity checks */
404     if( p_this->i_children )
405     {
406         int i;
407
408         fprintf( stderr,
409                  "ERROR: cannot delete object (%i, %s) with %d children\n",
410                  p_this->i_object_id, p_this->psz_object_name,
411                  p_this->i_children );
412
413         for( i = 0; i < p_this->i_children; i++ )
414         {
415             fprintf( stderr,
416                      "ERROR: Remaining children object "
417                      "(id:%i, type:%s, name:%s)\n",
418                      p_this->pp_children[i]->i_object_id,
419                      p_this->pp_children[i]->psz_object_type,
420                      p_this->pp_children[i]->psz_object_name );
421         }
422         fflush(stderr);
423         abort();
424     }
425
426     /* Destroy the associated variables, starting from the end so that
427      * no memmove calls have to be done. */
428     while( p_priv->i_vars )
429     {
430         var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
431     }
432
433     free( p_priv->p_vars );
434     vlc_mutex_destroy( &p_priv->var_lock );
435
436     free( p_this->psz_header );
437
438     if( p_this->i_object_type == VLC_OBJECT_GLOBAL )
439     {
440         libvlc_global_data_t *p_global = (libvlc_global_data_t *)p_this;
441
442         /* Test for leaks */
443         if( p_global->i_objects > 0 )
444         {
445             int i;
446             for( i = 0; i < p_global->i_objects; i++ )
447             {
448                 /* We are leaking this object */
449                 fprintf( stderr,
450                          "ERROR: leaking object (id:%i, type:%s, name:%s)\n",
451                          p_global->pp_objects[i]->i_object_id,
452                          p_global->pp_objects[i]->psz_object_type,
453                          p_global->pp_objects[i]->psz_object_name );
454                 fflush(stderr);
455             }
456             /* Strongly abort, cause we want these to be fixed */
457             abort();
458         }
459
460         /* We are the global object ... no need to lock. */
461         free( p_global->pp_objects );
462         p_global->pp_objects = NULL;
463
464         vlc_mutex_destroy( &structure_lock );
465     }
466
467 #if defined(WIN32) || defined(UNDER_CE)
468     /* if object has an associated thread, close it now */
469     if( p_priv->thread_id.hThread )
470        CloseHandle(p_priv->thread_id.hThread);
471 #endif
472
473     vlc_mutex_destroy( &p_this->object_lock );
474     vlc_cond_destroy( &p_this->object_wait );
475     vlc_spin_destroy( &p_priv->spin );
476     if( p_priv->pipes[1] != -1 )
477         close( p_priv->pipes[1] );
478     if( p_priv->pipes[0] != -1 )
479         close( p_priv->pipes[0] );
480
481     /* global is not dynamically allocated by vlc_object_create */
482     if( p_this->i_object_type != VLC_OBJECT_GLOBAL )
483         free( p_priv );
484 }
485
486
487 /** Inter-object signaling */
488
489 void __vlc_object_lock( vlc_object_t *obj )
490 {
491     vlc_mutex_lock( &obj->object_lock );
492 }
493
494 void __vlc_object_unlock( vlc_object_t *obj )
495 {
496     vlc_assert_locked( &obj->object_lock );
497     vlc_mutex_unlock( &obj->object_lock );
498 }
499
500 #ifdef WIN32
501 # include <winsock2.h>
502 # include <ws2tcpip.h>
503
504 /**
505  * select()-able pipes emulated using Winsock
506  */
507 static int pipe (int fd[2])
508 {
509     SOCKADDR_IN addr;
510     int addrlen = sizeof (addr);
511
512     SOCKET l = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP), a,
513            c = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
514     if ((l == INVALID_SOCKET) || (c == INVALID_SOCKET))
515         goto error;
516
517     memset (&addr, 0, sizeof (addr));
518     addr.sin_family = AF_INET;
519     addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
520     if (bind (l, (PSOCKADDR)&addr, sizeof (addr))
521      || getsockname (l, (PSOCKADDR)&addr, &addrlen)
522      || listen (l, 1)
523      || connect (c, (PSOCKADDR)&addr, addrlen))
524         goto error;
525
526     a = accept (l, NULL, NULL);
527     if (a == INVALID_SOCKET)
528         goto error;
529
530     closesocket (l);
531     //shutdown (a, 0);
532     //shutdown (c, 1);
533     fd[0] = c;
534     fd[1] = a;
535     return 0;
536
537 error:
538     if (l != INVALID_SOCKET)
539         closesocket (l);
540     if (c != INVALID_SOCKET)
541         closesocket (c);
542     return -1;
543 }
544
545 #undef  read
546 #define read( a, b, c )  recv (a, b, c, 0)
547 #undef  write
548 #define write( a, b, c ) send (a, b, c, 0)
549 #undef  close
550 #define close( a )       closesocket (a)
551 #endif /* WIN32 */
552
553 /**
554  * Returns the readable end of a pipe that becomes readable once termination
555  * of the object is requested (vlc_object_kill()).
556  * This can be used to wake-up out of a select() or poll() event loop, such
557  * typically when doing network I/O.
558  *
559  * Note that the pipe will remain the same for the lifetime of the object.
560  * DO NOT read the pipe nor close it yourself. Ever.
561  *
562  * @param obj object that would be "killed"
563  * @return a readable pipe descriptor, or -1 on error.
564  */
565 int __vlc_object_waitpipe( vlc_object_t *obj )
566 {
567     int pfd[2] = { -1, -1 };
568     struct vlc_object_internals_t *internals = obj->p_internals;
569     vlc_bool_t killed = VLC_FALSE;
570
571     vlc_spin_lock (&internals->spin);
572     if (internals->pipes[0] == -1)
573     {
574         /* This can only ever happen if someone killed us without locking: */
575         assert (internals->pipes[1] == -1);
576         vlc_spin_unlock (&internals->spin);
577
578         if (pipe (pfd))
579             return -1;
580
581         vlc_spin_lock (&internals->spin);
582         if (internals->pipes[0] == -1)
583         {
584             internals->pipes[0] = pfd[0];
585             internals->pipes[1] = pfd[1];
586             pfd[0] = pfd[1] = -1;
587         }
588         killed = obj->b_die;
589     }
590     vlc_spin_unlock (&internals->spin);
591
592     if (killed)
593     {
594         /* Race condition: vlc_object_kill() already invoked! */
595         int fd;
596
597         vlc_spin_lock (&internals->spin);
598         fd = internals->pipes[1];
599         internals->pipes[1] = -1;
600         vlc_spin_unlock (&internals->spin);
601
602         msg_Dbg (obj, "waitpipe: object already dying");
603         if (fd != -1)
604             close (fd);
605     }
606
607     /* Race condition: two threads call pipe() - unlikely */
608     if (pfd[0] != -1)
609         close (pfd[0]);
610     if (pfd[1] != -1)
611         close (pfd[1]);
612
613     return internals->pipes[0];
614 }
615
616
617 /**
618  * Waits for the object to be signaled (using vlc_object_signal()).
619  * If the object already has a signal pending, this function will return
620  * immediately. It is asserted that the caller holds the object lock.
621  *
622  * @return true if the object is dying and should terminate.
623  */
624 vlc_bool_t __vlc_object_wait( vlc_object_t *obj )
625 {
626     vlc_assert_locked( &obj->object_lock );
627     vlc_cond_wait( &obj->object_wait, &obj->object_lock );
628     return obj->b_die;
629 }
630
631
632 /**
633  * Waits for the object to be signaled (using vlc_object_signal()), or for
634  * a timer to expire.
635  * If the object already has a signal pending, this function will return
636  * immediately. It is asserted that the caller holds the object lock.
637  *
638  * @return negative if the object is dying and should terminate,
639  * positive if the the object has been signaled but is not dying,
640  * 0 if timeout has been reached.
641  */
642 int __vlc_object_timedwait( vlc_object_t *obj, mtime_t deadline )
643 {
644     int v;
645
646     vlc_assert_locked( &obj->object_lock );
647     v = vlc_cond_timedwait( &obj->object_wait, &obj->object_lock, deadline );
648     if( v == 0 ) /* signaled */
649         return obj->b_die ? -1 : 1;
650     return 0;
651 }
652
653
654 /**
655  * Checks whether an object has been "killed".
656  * The object lock must be held.
657  *
658  * Typical code for an object thread could be:
659  *
660    vlc_object_lock (self);
661    ...initialization...
662    while (vlc_object_alive (self))
663    {
664        ...preprocessing...
665
666        if (vlc_object_wait (self))
667            continue;
668
669        ...postprocessing...
670    }
671    ...deinitialization...
672    vlc_object_unlock (self);
673  *
674  *
675  * @return true iff the object has not been killed yet
676  */
677 vlc_bool_t __vlc_object_alive( vlc_object_t *obj )
678 {
679     vlc_assert_locked( &obj->object_lock );
680     return !obj->b_die;
681 }
682
683
684 /**
685  * Signals an object for which the lock is held.
686  */
687 void __vlc_object_signal_unlocked( vlc_object_t *obj )
688 {
689     vlc_assert_locked (&obj->object_lock);
690     vlc_cond_signal( &obj->object_wait );
691 }
692
693
694 /**
695  * Requests termination of an object.
696  * If the object is LibVLC, also request to terminate all its children.
697  */
698 void __vlc_object_kill( vlc_object_t *p_this )
699 {
700     struct vlc_object_internals_t *internals = p_this->p_internals;
701     int fd;
702
703     vlc_mutex_lock( &p_this->object_lock );
704     p_this->b_die = VLC_TRUE;
705
706     vlc_spin_lock (&internals->spin);
707     fd = internals->pipes[1];
708     internals->pipes[1] = -1;
709     vlc_spin_unlock (&internals->spin);
710
711     if( fd != -1 )
712     {
713         msg_Dbg (p_this, "waitpipe: object killed");
714         close (fd);
715     }
716
717     if( p_this->i_object_type == VLC_OBJECT_LIBVLC )
718         for( int i = 0; i < p_this->i_children ; i++ )
719             vlc_object_kill( p_this->pp_children[i] );
720
721     vlc_object_signal_unlocked( p_this );
722     vlc_mutex_unlock( &p_this->object_lock );
723 }
724
725
726 /**
727  * find an object given its ID
728  *
729  * This function looks for the object whose i_object_id field is i_id. We
730  * use a dichotomy so that lookups are in log2(n).
731  *****************************************************************************/
732 void * vlc_object_get( int i_id )
733 {
734     int i_max, i_middle;
735     vlc_object_t **pp_objects;
736     libvlc_global_data_t *p_libvlc_global = vlc_global();
737
738     vlc_mutex_lock( &structure_lock );
739
740     pp_objects = p_libvlc_global->pp_objects;
741
742     /* Perform our dichotomy */
743     for( i_max = p_libvlc_global->i_objects - 1 ; ; )
744     {
745         i_middle = i_max / 2;
746
747         if( pp_objects[i_middle]->i_object_id > i_id )
748         {
749             i_max = i_middle;
750         }
751         else if( pp_objects[i_middle]->i_object_id < i_id )
752         {
753             if( i_middle )
754             {
755                 pp_objects += i_middle;
756                 i_max -= i_middle;
757             }
758             else
759             {
760                 /* This happens when there are only two remaining objects */
761                 if( pp_objects[i_middle+1]->i_object_id == i_id
762                     && pp_objects[i_middle+1]->p_internals->i_refcount > 0 )
763                 {
764                     vlc_object_yield_locked( pp_objects[i_middle+1] );
765                     vlc_mutex_unlock( &structure_lock );
766                     return pp_objects[i_middle+1];
767                 }
768                 break;
769             }
770         }
771         else if( pp_objects[i_middle]->p_internals->i_refcount > 0 )
772         {
773             vlc_object_yield_locked( pp_objects[i_middle] );
774             vlc_mutex_unlock( &structure_lock );
775             return pp_objects[i_middle];
776         }
777
778         if( i_max == 0 )
779         {
780             /* this means that i_max == i_middle, and since we have already
781              * tested pp_objects[i_middle]), p_found is properly set. */
782             break;
783         }
784     }
785
786     vlc_mutex_unlock( &structure_lock );
787     return NULL;
788 }
789
790 /**
791  ****************************************************************************
792  * find a typed object and increment its refcount
793  *****************************************************************************
794  * This function recursively looks for a given object type. i_mode can be one
795  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
796  *****************************************************************************/
797 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
798 {
799     vlc_object_t *p_found;
800
801     vlc_mutex_lock( &structure_lock );
802
803     /* If we are of the requested type ourselves, don't look further */
804     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type
805         && p_this->p_internals->i_refcount > 0 )
806     {
807         vlc_object_yield_locked( p_this );
808         vlc_mutex_unlock( &structure_lock );
809         return p_this;
810     }
811
812     /* Otherwise, recursively look for the object */
813     if( (i_mode & 0x000f) == FIND_ANYWHERE )
814     {
815         vlc_object_t *p_root = p_this;
816
817         /* Find the root */
818         while( p_root->p_parent != NULL &&
819                p_root != VLC_OBJECT( p_this->p_libvlc ) )
820         {
821             p_root = p_root->p_parent;
822         }
823
824         p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
825         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
826         {
827             p_found = FindObject( VLC_OBJECT( p_this->p_libvlc ),
828                                   i_type, (i_mode & ~0x000f)|FIND_CHILD );
829         }
830     }
831     else
832     {
833         p_found = FindObject( p_this, i_type, i_mode );
834     }
835
836     vlc_mutex_unlock( &structure_lock );
837
838     return p_found;
839 }
840
841 /**
842  ****************************************************************************
843  * find a named object and increment its refcount
844  *****************************************************************************
845  * This function recursively looks for a given object name. i_mode can be one
846  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
847  *****************************************************************************/
848 void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
849                                int i_mode )
850 {
851     vlc_object_t *p_found;
852
853     vlc_mutex_lock( &structure_lock );
854
855     /* Avoid obvious freed object uses */
856     assert( p_this->p_internals->i_refcount > 0 );
857
858     /* If have the requested name ourselves, don't look further */
859     if( !(i_mode & FIND_STRICT)
860         && p_this->psz_object_name
861         && !strcmp( p_this->psz_object_name, psz_name )
862         && p_this->p_internals->i_refcount > 0 )
863     {
864         vlc_object_yield_locked( p_this );
865         vlc_mutex_unlock( &structure_lock );
866         return p_this;
867     }
868
869     /* Otherwise, recursively look for the object */
870     if( (i_mode & 0x000f) == FIND_ANYWHERE )
871     {
872         vlc_object_t *p_root = p_this;
873
874         /* Find the root */
875         while( p_root->p_parent != NULL &&
876                p_root != VLC_OBJECT( p_this->p_libvlc ) )
877         {
878             p_root = p_root->p_parent;
879         }
880
881         p_found = FindObjectName( p_root, psz_name,
882                                  (i_mode & ~0x000f)|FIND_CHILD );
883         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
884         {
885             p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
886                                       psz_name, (i_mode & ~0x000f)|FIND_CHILD );
887         }
888     }
889     else
890     {
891         p_found = FindObjectName( p_this, psz_name, i_mode );
892     }
893
894     vlc_mutex_unlock( &structure_lock );
895
896     return p_found;
897 }
898
899 /**
900  ****************************************************************************
901  * increment an object refcount
902  *****************************************************************************/
903
904 /* When the structure_lock is locked */
905 static void vlc_object_yield_locked( vlc_object_t *p_this )
906 {
907     vlc_assert_locked (&structure_lock);
908
909     /* Avoid obvious freed object uses */
910     assert( p_this->p_internals->i_refcount > 0 );
911
912     /* Increment the counter */
913     p_this->p_internals->i_refcount++;
914 }
915
916 /* Public function */
917 void __vlc_object_yield( vlc_object_t *p_this )
918 {
919     vlc_mutex_lock( &structure_lock );
920     vlc_object_yield_locked( p_this );
921     vlc_mutex_unlock( &structure_lock );
922 }
923
924
925 /*****************************************************************************
926  * decrement an object refcount
927  * And destroy the object if its refcount reach zero.
928  *****************************************************************************/
929 void __vlc_object_release( vlc_object_t *p_this )
930 {
931     vlc_bool_t b_should_destroy;
932
933     vlc_mutex_lock( &structure_lock );
934
935     assert( p_this->p_internals->i_refcount > 0 );
936     p_this->p_internals->i_refcount--;
937     b_should_destroy = (p_this->p_internals->i_refcount == 0);
938
939     if( b_should_destroy )
940     {
941         /* Make sure this object can't be obtained via vlc_find_object now that
942          * it is freed */
943         libvlc_global_data_t *p_libvlc_global = vlc_global();
944         int i_index;
945
946         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
947          * useless to try and recover anything if pp_objects gets smashed. */
948         i_index = FindIndex( p_this, p_libvlc_global->pp_objects,
949                              p_libvlc_global->i_objects );
950         REMOVE_ELEM( p_libvlc_global->pp_objects,
951                      p_libvlc_global->i_objects, i_index );
952     }
953
954     vlc_mutex_unlock( &structure_lock );
955
956     if( b_should_destroy )
957         vlc_object_destroy( p_this );
958 }
959
960 /**
961  ****************************************************************************
962  * attach object to a parent object
963  *****************************************************************************
964  * This function sets p_this as a child of p_parent, and p_parent as a parent
965  * of p_this. This link can be undone using vlc_object_detach.
966  *****************************************************************************/
967 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
968 {
969     if( !p_this ) return;
970
971     vlc_mutex_lock( &structure_lock );
972
973     /* Avoid obvious freed object uses */
974     assert( p_this->p_internals->i_refcount > 0 );
975
976     /* Attach the parent to its child */
977     p_this->p_parent = p_parent;
978
979     /* Attach the child to its parent */
980     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
981                  p_parent->i_children, p_this );
982
983     /* Climb up the tree to see whether we are connected with the root */
984     if( p_parent->p_internals->b_attached )
985     {
986         SetAttachment( p_this, VLC_TRUE );
987     }
988
989     vlc_mutex_unlock( &structure_lock );
990 }
991
992 /**
993  ****************************************************************************
994  * detach object from its parent
995  *****************************************************************************
996  * This function removes all links between an object and its parent.
997  *****************************************************************************/
998 void __vlc_object_detach( vlc_object_t *p_this )
999 {
1000     if( !p_this ) return;
1001
1002     vlc_mutex_lock( &structure_lock );
1003
1004     if( !p_this->p_parent )
1005     {
1006         msg_Err( p_this, "object is not attached" );
1007         vlc_mutex_unlock( &structure_lock );
1008         return;
1009     }
1010
1011     /* Climb up the tree to see whether we are connected with the root */
1012     if( p_this->p_parent->p_internals->b_attached )
1013     {
1014         SetAttachment( p_this, VLC_FALSE );
1015     }
1016
1017     DetachObject( p_this );
1018     vlc_mutex_unlock( &structure_lock );
1019     p_this = NULL;
1020 }
1021
1022 /**
1023  ****************************************************************************
1024  * find a list typed objects and increment their refcount
1025  *****************************************************************************
1026  * This function recursively looks for a given object type. i_mode can be one
1027  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
1028  *****************************************************************************/
1029 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
1030 {
1031     vlc_list_t *p_list;
1032     vlc_object_t **pp_current, **pp_end;
1033     int i_count = 0, i_index = 0;
1034     libvlc_global_data_t *p_libvlc_global = vlc_global();
1035
1036     vlc_mutex_lock( &structure_lock );
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                 && p_tmp->p_internals->i_refcount > 0 )
1346             {
1347                 vlc_object_yield_locked( p_tmp );
1348                 return p_tmp;
1349             }
1350             else
1351             {
1352                 return FindObject( p_tmp, i_type, i_mode );
1353             }
1354         }
1355         break;
1356
1357     case FIND_CHILD:
1358         for( i = p_this->i_children; i--; )
1359         {
1360             p_tmp = p_this->pp_children[i];
1361             if( p_tmp->i_object_type == i_type
1362                 && p_tmp->p_internals->i_refcount > 0 )
1363             {
1364                 vlc_object_yield_locked( p_tmp );
1365                 return p_tmp;
1366             }
1367             else if( p_tmp->i_children )
1368             {
1369                 p_tmp = FindObject( p_tmp, i_type, i_mode );
1370                 if( p_tmp )
1371                 {
1372                     return p_tmp;
1373                 }
1374             }
1375         }
1376         break;
1377
1378     case FIND_ANYWHERE:
1379         /* Handled in vlc_object_find */
1380         break;
1381     }
1382
1383     return NULL;
1384 }
1385
1386 static vlc_object_t * FindObjectName( vlc_object_t *p_this,
1387                                       const char *psz_name,
1388                                       int i_mode )
1389 {
1390     int i;
1391     vlc_object_t *p_tmp;
1392
1393     switch( i_mode & 0x000f )
1394     {
1395     case FIND_PARENT:
1396         p_tmp = p_this->p_parent;
1397         if( p_tmp )
1398         {
1399             if( p_tmp->psz_object_name
1400                 && !strcmp( p_tmp->psz_object_name, psz_name )
1401                 && p_tmp->p_internals->i_refcount > 0 )
1402             {
1403                 vlc_object_yield_locked( p_tmp );
1404                 return p_tmp;
1405             }
1406             else
1407             {
1408                 return FindObjectName( p_tmp, psz_name, i_mode );
1409             }
1410         }
1411         break;
1412
1413     case FIND_CHILD:
1414         for( i = p_this->i_children; i--; )
1415         {
1416             p_tmp = p_this->pp_children[i];
1417             if( p_tmp->psz_object_name
1418                 && !strcmp( p_tmp->psz_object_name, psz_name )
1419                 && p_tmp->p_internals->i_refcount > 0 )
1420             {
1421                 vlc_object_yield_locked( p_tmp );
1422                 return p_tmp;
1423             }
1424             else if( p_tmp->i_children )
1425             {
1426                 p_tmp = FindObjectName( p_tmp, psz_name, i_mode );
1427                 if( p_tmp )
1428                 {
1429                     return p_tmp;
1430                 }
1431             }
1432         }
1433         break;
1434
1435     case FIND_ANYWHERE:
1436         /* Handled in vlc_object_find */
1437         break;
1438     }
1439
1440     return NULL;
1441 }
1442
1443 static void DetachObject( vlc_object_t *p_this )
1444 {
1445     vlc_object_t *p_parent = p_this->p_parent;
1446     int i_index, i;
1447
1448     /* Remove p_this's parent */
1449     p_this->p_parent = NULL;
1450
1451     /* Remove all of p_parent's children which are p_this */
1452     for( i_index = p_parent->i_children ; i_index-- ; )
1453     {
1454         if( p_parent->pp_children[i_index] == p_this )
1455         {
1456             p_parent->i_children--;
1457             for( i = i_index ; i < p_parent->i_children ; i++ )
1458             {
1459                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
1460             }
1461         }
1462     }
1463
1464     if( p_parent->i_children )
1465     {
1466         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
1467                                p_parent->i_children * sizeof(vlc_object_t *) );
1468     }
1469     else
1470     {
1471         free( p_parent->pp_children );
1472         p_parent->pp_children = NULL;
1473     }
1474 }
1475
1476 /*****************************************************************************
1477  * SetAttachment: recursively set the b_attached flag of a subtree.
1478  *****************************************************************************
1479  * This function is used by the attach and detach functions to propagate
1480  * the b_attached flag in a subtree.
1481  *****************************************************************************/
1482 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
1483 {
1484     int i_index;
1485
1486     for( i_index = p_this->i_children ; i_index-- ; )
1487     {
1488         SetAttachment( p_this->pp_children[i_index], b_attached );
1489     }
1490
1491     p_this->p_internals->b_attached = b_attached;
1492 }
1493
1494 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
1495 {
1496     char psz_children[20], psz_refcount[20], psz_thread[30], psz_name[50],
1497          psz_parent[20];
1498
1499     psz_name[0] = '\0';
1500     if( p_this->psz_object_name )
1501     {
1502         snprintf( psz_name, 49, " \"%s\"", p_this->psz_object_name );
1503         if( psz_name[48] )
1504             psz_name[48] = '\"';
1505     }
1506
1507     psz_children[0] = '\0';
1508     switch( p_this->i_children )
1509     {
1510         case 0:
1511             break;
1512         case 1:
1513             strcpy( psz_children, ", 1 child" );
1514             break;
1515         default:
1516             snprintf( psz_children, 19, ", %i children", p_this->i_children );
1517             break;
1518     }
1519
1520     psz_refcount[0] = '\0';
1521     if( p_this->p_internals->i_refcount > 0 )
1522         snprintf( psz_refcount, 19, ", refcount %u",
1523                   p_this->p_internals->i_refcount );
1524
1525     psz_thread[0] = '\0';
1526     if( p_this->p_internals->b_thread )
1527         snprintf( psz_thread, 29, " (thread %u)",
1528 #if defined(WIN32) || defined(UNDER_CE)
1529                   (unsigned)p_this->p_internals->thread_id.id );
1530 #else
1531                   (unsigned)p_this->p_internals->thread_id );
1532 #endif
1533
1534     psz_parent[0] = '\0';
1535     if( p_this->p_parent )
1536         snprintf( psz_parent, 19, ", parent %i", p_this->p_parent->i_object_id );
1537
1538     printf( " %so %.8i %s%s%s%s%s%s\n", psz_prefix,
1539             p_this->i_object_id, p_this->psz_object_type,
1540             psz_name, psz_thread, psz_refcount, psz_children,
1541             psz_parent );
1542 }
1543
1544 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
1545 {
1546     int i;
1547     char i_back = psz_foo[i_level];
1548     psz_foo[i_level] = '\0';
1549
1550     PrintObject( p_this, psz_foo );
1551
1552     psz_foo[i_level] = i_back;
1553
1554     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
1555     {
1556         msg_Warn( p_this, "structure tree is too deep" );
1557         return;
1558     }
1559
1560     for( i = 0 ; i < p_this->i_children ; i++ )
1561     {
1562         if( i_level )
1563         {
1564             psz_foo[i_level-1] = ' ';
1565
1566             if( psz_foo[i_level-2] == '`' )
1567             {
1568                 psz_foo[i_level-2] = ' ';
1569             }
1570         }
1571
1572         if( i == p_this->i_children - 1 )
1573         {
1574             psz_foo[i_level] = '`';
1575         }
1576         else
1577         {
1578             psz_foo[i_level] = '|';
1579         }
1580
1581         psz_foo[i_level+1] = '-';
1582         psz_foo[i_level+2] = '\0';
1583
1584         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
1585     }
1586 }
1587
1588 static vlc_list_t * NewList( int i_count )
1589 {
1590     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
1591     if( p_list == NULL )
1592     {
1593         return NULL;
1594     }
1595
1596     p_list->i_count = i_count;
1597
1598     if( i_count == 0 )
1599     {
1600         p_list->p_values = NULL;
1601         return p_list;
1602     }
1603
1604     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
1605     if( p_list->p_values == NULL )
1606     {
1607         p_list->i_count = 0;
1608         return p_list;
1609     }
1610
1611     return p_list;
1612 }
1613
1614 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
1615                          int i_index )
1616 {
1617     if( p_list == NULL || i_index >= p_list->i_count )
1618     {
1619         return;
1620     }
1621
1622     vlc_object_yield_locked( p_object );
1623
1624     p_list->p_values[i_index].p_object = p_object;
1625
1626     return;
1627 }
1628
1629 /*static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
1630 {
1631     if( p_list == NULL )
1632     {
1633         return;
1634     }
1635
1636     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1637                                 * sizeof( vlc_value_t ) );
1638     if( p_list->p_values == NULL )
1639     {
1640         p_list->i_count = 0;
1641         return;
1642     }
1643
1644     vlc_object_yield_locked( p_object );
1645
1646     p_list->p_values[p_list->i_count].p_object = p_object;
1647     p_list->i_count++;
1648
1649     return;
1650 }*/
1651
1652 static int CountChildren( vlc_object_t *p_this, int i_type )
1653 {
1654     vlc_object_t *p_tmp;
1655     int i, i_count = 0;
1656
1657     for( i = 0; i < p_this->i_children; i++ )
1658     {
1659         p_tmp = p_this->pp_children[i];
1660
1661         if( p_tmp->i_object_type == i_type )
1662         {
1663             i_count++;
1664         }
1665
1666         if( p_tmp->i_children )
1667         {
1668             i_count += CountChildren( p_tmp, i_type );
1669         }
1670     }
1671
1672     return i_count;
1673 }
1674
1675 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1676 {
1677     vlc_object_t *p_tmp;
1678     int i;
1679
1680     for( i = 0; i < p_this->i_children; i++ )
1681     {
1682         p_tmp = p_this->pp_children[i];
1683
1684         if( p_tmp->i_object_type == i_type )
1685         {
1686             ListReplace( p_list, p_tmp, p_list->i_count++ );
1687         }
1688
1689         if( p_tmp->i_children )
1690         {
1691             ListChildren( p_list, p_tmp, i_type );
1692         }
1693     }
1694 }