]> git.sesse.net Git - vlc/blob - src/misc/objects.c
Hide httpd_t and httpd_host_t within httpd.c
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2004 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 #include <vlc/vlc.h>
34
35 #ifdef HAVE_STDLIB_H
36 #   include <stdlib.h>                                          /* realloc() */
37 #endif
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 "vlc_vod.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
66 /*****************************************************************************
67  * Local prototypes
68  *****************************************************************************/
69 static int  DumpCommand( vlc_object_t *, char const *,
70                          vlc_value_t, vlc_value_t, void * );
71
72 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
73 static void           DetachObject  ( vlc_object_t * );
74 static void           PrintObject   ( vlc_object_t *, const char * );
75 static void           DumpStructure ( vlc_object_t *, int, char * );
76 static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
77 static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
78
79 static vlc_list_t   * NewList       ( int );
80 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
81 /*static void           ListAppend    ( vlc_list_t *, vlc_object_t * );*/
82 static int            CountChildren ( vlc_object_t *, int );
83 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
84
85 /*****************************************************************************
86  * Local structure lock
87  *****************************************************************************/
88 static vlc_mutex_t    structure_lock;
89
90 vlc_object_t *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
91                                  int i_type, const char *psz_type )
92 {
93     vlc_object_t * p_new;
94
95     if( i_type == VLC_OBJECT_GLOBAL )
96     {
97         p_new = p_this;
98     }
99     else
100     {
101         p_new = malloc( i_size );
102         if( !p_new ) return NULL;
103         memset( p_new, 0, i_size );
104     }
105
106     p_new->i_object_type = i_type;
107     p_new->psz_object_type = psz_type;
108
109     p_new->psz_object_name = NULL;
110
111     p_new->b_die = VLC_FALSE;
112     p_new->b_error = VLC_FALSE;
113     p_new->b_dead = VLC_FALSE;
114     p_new->b_attached = VLC_FALSE;
115     p_new->b_force = VLC_FALSE;
116
117     p_new->psz_header = NULL;
118
119     p_new->i_flags = 0;
120     if( p_this->i_flags & OBJECT_FLAGS_NODBG )
121         p_new->i_flags |= OBJECT_FLAGS_NODBG;
122     if( p_this->i_flags & OBJECT_FLAGS_QUIET )
123         p_new->i_flags |= OBJECT_FLAGS_QUIET;
124     if( p_this->i_flags & OBJECT_FLAGS_NOINTERACT )
125         p_new->i_flags |= OBJECT_FLAGS_NOINTERACT;
126
127     p_new->i_vars = 0;
128     p_new->p_vars = (variable_t *)malloc( 16 * sizeof( variable_t ) );
129
130     if( !p_new->p_vars )
131     {
132         if( i_type != VLC_OBJECT_GLOBAL )
133             free( p_new );
134         return NULL;
135     }
136
137     if( i_type == VLC_OBJECT_GLOBAL )
138     {
139         /* If i_type is global, then p_new is actually p_libvlc_global */
140         p_new->p_libvlc_global = (libvlc_global_data_t*)p_new;
141         p_new->p_libvlc = NULL;
142
143         p_new->p_libvlc_global->i_counter = 0;
144         p_new->i_object_id = 0;
145
146         p_new->p_libvlc_global->i_objects = 1;
147         p_new->p_libvlc_global->pp_objects = malloc( sizeof(vlc_object_t *) );
148         p_new->p_libvlc_global->pp_objects[0] = p_new;
149         p_new->b_attached = VLC_TRUE;
150     }
151     else
152     {
153         p_new->p_libvlc_global = p_this->p_libvlc_global;
154         p_new->p_libvlc = ( i_type == VLC_OBJECT_LIBVLC ) ? (libvlc_int_t*)p_new
155                                                        : p_this->p_libvlc;
156
157         vlc_mutex_lock( &structure_lock );
158
159         p_new->p_libvlc_global->i_counter++;
160         p_new->i_object_id = p_new->p_libvlc_global->i_counter;
161
162         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
163          * useless to try and recover anything if pp_objects gets smashed. */
164         TAB_APPEND( p_new->p_libvlc_global->i_objects,
165                     p_new->p_libvlc_global->pp_objects,
166                     p_new );
167
168         vlc_mutex_unlock( &structure_lock );
169     }
170
171     p_new->i_refcount = 0;
172     p_new->p_parent = NULL;
173     p_new->pp_children = NULL;
174     p_new->i_children = 0;
175
176     p_new->p_private = NULL;
177
178     /* Initialize mutexes and condvars */
179     vlc_mutex_init( p_new, &p_new->object_lock );
180     vlc_cond_init( p_new, &p_new->object_wait );
181     vlc_mutex_init( p_new, &p_new->var_lock );
182
183     if( i_type == VLC_OBJECT_GLOBAL )
184     {
185         vlc_mutex_init( p_new, &structure_lock );
186
187         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
188         var_AddCallback( p_new, "list", DumpCommand, NULL );
189         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
190         var_AddCallback( p_new, "tree", DumpCommand, NULL );
191     }
192
193     return p_new;
194 }
195
196
197 /**
198  * Allocates and initializes a vlc object.
199  *
200  * @param i_type known object type (all of them are negative integer values),
201  *               or object byte size (always positive).
202  *
203  * @return the new object, or NULL on error.
204  */
205 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
206 {
207     const char   * psz_type;
208     size_t         i_size;
209
210     switch( i_type )
211     {
212         case VLC_OBJECT_GLOBAL:
213             i_size = sizeof(libvlc_global_data_t);
214             psz_type = "global";
215             break;
216         case VLC_OBJECT_LIBVLC:
217             i_size = sizeof(libvlc_int_t);
218             psz_type = "libvlc";
219             break;
220         case VLC_OBJECT_MODULE:
221             i_size = sizeof(module_t);
222             psz_type = "module";
223             break;
224         case VLC_OBJECT_INTF:
225             i_size = sizeof(intf_thread_t);
226             psz_type = "interface";
227             break;
228         case VLC_OBJECT_DIALOGS:
229             i_size = sizeof(intf_thread_t);
230             psz_type = "dialogs";
231             break;
232         case VLC_OBJECT_PLAYLIST:
233             i_size = sizeof(playlist_t);
234             psz_type = "playlist";
235             break;
236         case VLC_OBJECT_SD:
237             i_size = sizeof(services_discovery_t);
238             psz_type = "services discovery";
239             break;
240         case VLC_OBJECT_INPUT:
241             i_size = sizeof(input_thread_t);
242             psz_type = "input";
243             break;
244         case VLC_OBJECT_DEMUX:
245             i_size = sizeof(demux_t);
246             psz_type = "demux";
247             break;
248         case VLC_OBJECT_STREAM:
249             i_size = sizeof(stream_t);
250             psz_type = "stream";
251             break;
252         case VLC_OBJECT_ACCESS:
253             i_size = sizeof(access_t);
254             psz_type = "access";
255             break;
256         case VLC_OBJECT_DECODER:
257             i_size = sizeof(decoder_t);
258             psz_type = "decoder";
259             break;
260         case VLC_OBJECT_PACKETIZER:
261             i_size = sizeof(decoder_t);
262             psz_type = "packetizer";
263             break;
264         case VLC_OBJECT_ENCODER:
265             i_size = sizeof(encoder_t);
266             psz_type = "encoder";
267             break;
268         case VLC_OBJECT_FILTER:
269             i_size = sizeof(filter_t);
270             psz_type = "filter";
271             break;
272         case VLC_OBJECT_VOUT:
273             i_size = sizeof(vout_thread_t);
274             psz_type = "video output";
275             break;
276         case VLC_OBJECT_SPU:
277             i_size = sizeof(spu_t);
278             psz_type = "subpicture";
279             break;
280         case VLC_OBJECT_AOUT:
281             i_size = sizeof(aout_instance_t);
282             psz_type = "audio output";
283             break;
284         case VLC_OBJECT_SOUT:
285             i_size = sizeof(sout_instance_t);
286             psz_type = "stream output";
287             break;
288         case VLC_OBJECT_VLM:
289             i_size = sizeof( vlm_t );
290             psz_type = "vlm dameon";
291             break;
292         case VLC_OBJECT_VOD:
293             i_size = sizeof( vod_t );
294             psz_type = "vod server";
295             break;
296         case VLC_OBJECT_TLS:
297             i_size = sizeof( tls_t );
298             psz_type = "tls";
299             break;
300         case VLC_OBJECT_XML:
301             i_size = sizeof( xml_t );
302             psz_type = "xml";
303             break;
304         case VLC_OBJECT_OPENGL:
305             i_size = sizeof( vout_thread_t );
306             psz_type = "opengl";
307             break;
308         case VLC_OBJECT_ANNOUNCE:
309             i_size = sizeof( announce_handler_t );
310             psz_type = "announce";
311             break;
312         case VLC_OBJECT_META_ENGINE:
313             i_size = sizeof( meta_engine_t );
314             psz_type = "meta engine";
315             break;
316         case VLC_OBJECT_OSDMENU:
317             i_size = sizeof( osd_menu_t );
318             psz_type = "osd menu";
319             break;
320         default:
321             i_size = i_type > (int)sizeof(vlc_object_t)
322                          ? i_type : (int)sizeof(vlc_object_t);
323             i_type = VLC_OBJECT_GENERIC;
324             psz_type = "generic";
325             break;
326     }
327
328     return vlc_custom_create( p_this, i_size, i_type, psz_type );
329 }
330
331
332 /**
333  ****************************************************************************
334  * Destroy a vlc object
335  *
336  * This function destroys an object that has been previously allocated with
337  * vlc_object_create. The object's refcount must be zero and it must not be
338  * attached to other objects in any way.
339  *****************************************************************************/
340 void __vlc_object_destroy( vlc_object_t *p_this )
341 {
342     int i_delay = 0;
343
344     if( p_this->i_children )
345     {
346         msg_Err( p_this, "cannot delete object (%i, %s) with children" ,
347                  p_this->i_object_id, p_this->psz_object_name );
348         return;
349     }
350
351     if( p_this->p_parent )
352     {
353         msg_Err( p_this, "cannot delete object (%i, %s) with a parent",
354                  p_this->i_object_id, p_this->psz_object_name );
355         return;
356     }
357
358     while( p_this->i_refcount )
359     {
360         i_delay++;
361
362         /* Don't warn immediately ... 100ms seems OK */
363         if( i_delay == 2 )
364         {
365             msg_Warn( p_this,
366                   "refcount is %i, delaying before deletion (id=%d,type=%d)",
367                   p_this->i_refcount, p_this->i_object_id,
368                   p_this->i_object_type );
369         }
370         else if( i_delay == 10 )
371         {
372             msg_Err( p_this,
373                   "refcount is %i, delaying again (id=%d,type=%d)",
374                   p_this->i_refcount, p_this->i_object_id,
375                   p_this->i_object_type );
376         }
377         else if( i_delay == 20 )
378         {
379             msg_Err( p_this,
380                   "waited too long, cancelling destruction (id=%d,type=%d)",
381                   p_this->i_object_id, p_this->i_object_type );
382             return;
383         }
384
385         msleep( 100000 );
386     }
387
388     /* Destroy the associated variables, starting from the end so that
389      * no memmove calls have to be done. */
390     while( p_this->i_vars )
391     {
392         var_Destroy( p_this, p_this->p_vars[p_this->i_vars - 1].psz_name );
393     }
394
395     free( p_this->p_vars );
396     vlc_mutex_destroy( &p_this->var_lock );
397
398     if( p_this->psz_header ) free( p_this->psz_header );
399
400     if( p_this->i_object_type == VLC_OBJECT_GLOBAL )
401     {
402         /* We are the global object ... no need to lock. */
403         free( p_this->p_libvlc_global->pp_objects );
404         p_this->p_libvlc_global->pp_objects = NULL;
405         p_this->p_libvlc_global->i_objects--;
406
407         vlc_mutex_destroy( &structure_lock );
408     }
409     else
410     {
411         int i_index;
412
413         vlc_mutex_lock( &structure_lock );
414
415         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
416          * useless to try and recover anything if pp_objects gets smashed. */
417         i_index = FindIndex( p_this, p_this->p_libvlc_global->pp_objects,
418                              p_this->p_libvlc_global->i_objects );
419         REMOVE_ELEM( p_this->p_libvlc_global->pp_objects,
420                      p_this->p_libvlc_global->i_objects, i_index );
421
422         vlc_mutex_unlock( &structure_lock );
423     }
424
425     vlc_mutex_destroy( &p_this->object_lock );
426     vlc_cond_destroy( &p_this->object_wait );
427
428     /* global is not dynamically allocated by vlc_object_create */
429     if( p_this->i_object_type != VLC_OBJECT_GLOBAL )
430         free( p_this );
431 }
432
433 /**
434  * find an object given its ID
435  *
436  * This function looks for the object whose i_object_id field is i_id. We
437  * use a dichotomy so that lookups are in log2(n).
438  *****************************************************************************/
439 void * __vlc_object_get( vlc_object_t *p_this, int i_id )
440 {
441     int i_max, i_middle;
442     vlc_object_t **pp_objects;
443
444     vlc_mutex_lock( &structure_lock );
445
446     pp_objects = p_this->p_libvlc_global->pp_objects;
447
448     /* Perform our dichotomy */
449     for( i_max = p_this->p_libvlc_global->i_objects - 1 ; ; )
450     {
451         i_middle = i_max / 2;
452
453         if( pp_objects[i_middle]->i_object_id > i_id )
454         {
455             i_max = i_middle;
456         }
457         else if( pp_objects[i_middle]->i_object_id < i_id )
458         {
459             if( i_middle )
460             {
461                 pp_objects += i_middle;
462                 i_max -= i_middle;
463             }
464             else
465             {
466                 /* This happens when there are only two remaining objects */
467                 if( pp_objects[i_middle+1]->i_object_id == i_id )
468                 {
469                     vlc_mutex_unlock( &structure_lock );
470                     pp_objects[i_middle+1]->i_refcount++;
471                     return pp_objects[i_middle+1];
472                 }
473                 break;
474             }
475         }
476         else
477         {
478             vlc_mutex_unlock( &structure_lock );
479             pp_objects[i_middle]->i_refcount++;
480             return pp_objects[i_middle];
481         }
482
483         if( i_max == 0 )
484         {
485             /* this means that i_max == i_middle, and since we have already
486              * tested pp_objects[i_middle]), p_found is properly set. */
487             break;
488         }
489     }
490
491     vlc_mutex_unlock( &structure_lock );
492     return NULL;
493 }
494
495 /**
496  ****************************************************************************
497  * find a typed object and increment its refcount
498  *****************************************************************************
499  * This function recursively looks for a given object type. i_mode can be one
500  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
501  *****************************************************************************/
502 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
503 {
504     vlc_object_t *p_found;
505
506     vlc_mutex_lock( &structure_lock );
507
508     /* If we are of the requested type ourselves, don't look further */
509     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
510     {
511         p_this->i_refcount++;
512         vlc_mutex_unlock( &structure_lock );
513         return p_this;
514     }
515
516     /* Otherwise, recursively look for the object */
517     if( (i_mode & 0x000f) == FIND_ANYWHERE )
518     {
519         vlc_object_t *p_root = p_this;
520
521         /* Find the root */
522         while( p_root->p_parent != NULL &&
523                p_root != VLC_OBJECT( p_this->p_libvlc ) )
524         {
525             p_root = p_root->p_parent;
526         }
527
528         p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
529         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
530         {
531             p_found = FindObject( VLC_OBJECT( p_this->p_libvlc ),
532                                   i_type, (i_mode & ~0x000f)|FIND_CHILD );
533         }
534     }
535     else
536     {
537         p_found = FindObject( p_this, i_type, i_mode );
538     }
539
540     vlc_mutex_unlock( &structure_lock );
541
542     return p_found;
543 }
544
545 /**
546  ****************************************************************************
547  * increment an object refcount
548  *****************************************************************************/
549 void __vlc_object_yield( vlc_object_t *p_this )
550 {
551     vlc_mutex_lock( &structure_lock );
552     p_this->i_refcount++;
553     vlc_mutex_unlock( &structure_lock );
554 }
555
556 /**
557  ****************************************************************************
558  * decrement an object refcount
559  *****************************************************************************/
560 void __vlc_object_release( vlc_object_t *p_this )
561 {
562     vlc_mutex_lock( &structure_lock );
563     p_this->i_refcount--;
564     vlc_mutex_unlock( &structure_lock );
565 }
566
567 /**
568  ****************************************************************************
569  * attach object to a parent object
570  *****************************************************************************
571  * This function sets p_this as a child of p_parent, and p_parent as a parent
572  * of p_this. This link can be undone using vlc_object_detach.
573  *****************************************************************************/
574 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
575 {
576     vlc_mutex_lock( &structure_lock );
577
578     /* Attach the parent to its child */
579     p_this->p_parent = p_parent;
580
581     /* Attach the child to its parent */
582     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
583                  p_parent->i_children, p_this );
584
585     /* Climb up the tree to see whether we are connected with the root */
586     if( p_parent->b_attached )
587     {
588         SetAttachment( p_this, VLC_TRUE );
589     }
590
591     vlc_mutex_unlock( &structure_lock );
592 }
593
594 /**
595  ****************************************************************************
596  * detach object from its parent
597  *****************************************************************************
598  * This function removes all links between an object and its parent.
599  *****************************************************************************/
600 void __vlc_object_detach( vlc_object_t *p_this )
601 {
602     vlc_mutex_lock( &structure_lock );
603     if( !p_this->p_parent )
604     {
605         msg_Err( p_this, "object is not attached" );
606         vlc_mutex_unlock( &structure_lock );
607         return;
608     }
609
610     /* Climb up the tree to see whether we are connected with the root */
611     if( p_this->p_parent->b_attached )
612     {
613         SetAttachment( p_this, VLC_FALSE );
614     }
615
616     DetachObject( p_this );
617     vlc_mutex_unlock( &structure_lock );
618 }
619
620 /**
621  ****************************************************************************
622  * find a list typed objects and increment their refcount
623  *****************************************************************************
624  * This function recursively looks for a given object type. i_mode can be one
625  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
626  *****************************************************************************/
627 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
628 {
629     vlc_list_t *p_list;
630     vlc_object_t **pp_current, **pp_end;
631     int i_count = 0, i_index = 0;
632
633     vlc_mutex_lock( &structure_lock );
634
635     /* Look for the objects */
636     switch( i_mode & 0x000f )
637     {
638     case FIND_ANYWHERE:
639         pp_current = p_this->p_libvlc_global->pp_objects;
640         pp_end = pp_current + p_this->p_libvlc_global->i_objects;
641
642         for( ; pp_current < pp_end ; pp_current++ )
643         {
644             if( (*pp_current)->b_attached
645                  && (*pp_current)->i_object_type == i_type )
646             {
647                 i_count++;
648             }
649         }
650
651         p_list = NewList( i_count );
652         pp_current = p_this->p_libvlc_global->pp_objects;
653
654         for( ; pp_current < pp_end ; pp_current++ )
655         {
656             if( (*pp_current)->b_attached
657                  && (*pp_current)->i_object_type == i_type )
658             {
659                 ListReplace( p_list, *pp_current, i_index );
660                 if( i_index < i_count ) i_index++;
661             }
662         }
663     break;
664
665     case FIND_CHILD:
666         i_count = CountChildren( p_this, i_type );
667         p_list = NewList( i_count );
668
669         /* Check allocation was successful */
670         if( p_list->i_count != i_count )
671         {
672             msg_Err( p_this, "list allocation failed!" );
673             p_list->i_count = 0;
674             break;
675         }
676
677         p_list->i_count = 0;
678         ListChildren( p_list, p_this, i_type );
679         break;
680
681     default:
682         msg_Err( p_this, "unimplemented!" );
683         p_list = NewList( 0 );
684         break;
685     }
686
687     vlc_mutex_unlock( &structure_lock );
688
689     return p_list;
690 }
691
692 /*****************************************************************************
693  * DumpCommand: print the current vlc structure
694  *****************************************************************************
695  * This function prints either an ASCII tree showing the connections between
696  * vlc objects, and additional information such as their refcount, thread ID,
697  * etc. (command "tree"), or the same data as a simple list (command "list").
698  *****************************************************************************/
699 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
700                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
701 {
702     if( *psz_cmd == 't' )
703     {
704         char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
705         vlc_object_t *p_object;
706
707         if( *newval.psz_string )
708         {
709             p_object = vlc_object_get( p_this, atoi(newval.psz_string) );
710
711             if( !p_object )
712             {
713                 return VLC_ENOOBJ;
714             }
715         }
716         else
717         {
718             p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
719         }
720
721         vlc_mutex_lock( &structure_lock );
722
723         psz_foo[0] = '|';
724         DumpStructure( p_object, 0, psz_foo );
725
726         vlc_mutex_unlock( &structure_lock );
727
728         if( *newval.psz_string )
729         {
730             vlc_object_release( p_this );
731         }
732     }
733     else if( *psz_cmd == 'l' )
734     {
735         vlc_object_t **pp_current, **pp_end;
736
737         vlc_mutex_lock( &structure_lock );
738
739         pp_current = p_this->p_libvlc_global->pp_objects;
740         pp_end = pp_current + p_this->p_libvlc_global->i_objects;
741
742         for( ; pp_current < pp_end ; pp_current++ )
743         {
744             if( (*pp_current)->b_attached )
745             {
746                 PrintObject( *pp_current, "" );
747             }
748             else
749             {
750                 printf( " o %.8i %s (not attached)\n",
751                         (*pp_current)->i_object_id,
752                         (*pp_current)->psz_object_type );
753             }
754         }
755
756         vlc_mutex_unlock( &structure_lock );
757     }
758
759     return VLC_SUCCESS;
760 }
761
762 /*****************************************************************************
763  * vlc_list_release: free a list previously allocated by vlc_list_find
764  *****************************************************************************
765  * This function decreases the refcount of all objects in the list and
766  * frees the list.
767  *****************************************************************************/
768 void vlc_list_release( vlc_list_t *p_list )
769 {
770     int i_index;
771
772     for( i_index = 0; i_index < p_list->i_count; i_index++ )
773     {
774         vlc_mutex_lock( &structure_lock );
775
776         p_list->p_values[i_index].p_object->i_refcount--;
777
778         vlc_mutex_unlock( &structure_lock );
779     }
780
781     free( p_list->p_values );
782     free( p_list );
783 }
784
785 /* Following functions are local */
786
787 /*****************************************************************************
788  * FindIndex: find the index of an object in an array of objects
789  *****************************************************************************
790  * This function assumes that p_this can be found in pp_objects. It will not
791  * crash if p_this cannot be found, but will return a wrong value. It is your
792  * duty to check the return value if you are not certain that the object could
793  * be found for sure.
794  *****************************************************************************/
795 static int FindIndex( vlc_object_t *p_this,
796                       vlc_object_t **pp_objects, int i_count )
797 {
798     int i_middle = i_count / 2;
799
800     if( i_count == 0 )
801     {
802         return 0;
803     }
804
805     if( pp_objects[i_middle] == p_this )
806     {
807         return i_middle;
808     }
809
810     if( i_count == 1 )
811     {
812         return 0;
813     }
814
815     /* We take advantage of the sorted array */
816     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
817     {
818         return i_middle + FindIndex( p_this, pp_objects + i_middle,
819                                              i_count - i_middle );
820     }
821     else
822     {
823         return FindIndex( p_this, pp_objects, i_middle );
824     }
825 }
826
827 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
828 {
829     int i;
830     vlc_object_t *p_tmp;
831
832     switch( i_mode & 0x000f )
833     {
834     case FIND_PARENT:
835         p_tmp = p_this->p_parent;
836         if( p_tmp )
837         {
838             if( p_tmp->i_object_type == i_type )
839             {
840                 p_tmp->i_refcount++;
841                 return p_tmp;
842             }
843             else
844             {
845                 return FindObject( p_tmp, i_type, i_mode );
846             }
847         }
848         break;
849
850     case FIND_CHILD:
851         for( i = p_this->i_children; i--; )
852         {
853             p_tmp = p_this->pp_children[i];
854             if( p_tmp->i_object_type == i_type )
855             {
856                 p_tmp->i_refcount++;
857                 return p_tmp;
858             }
859             else if( p_tmp->i_children )
860             {
861                 p_tmp = FindObject( p_tmp, i_type, i_mode );
862                 if( p_tmp )
863                 {
864                     return p_tmp;
865                 }
866             }
867         }
868         break;
869
870     case FIND_ANYWHERE:
871         /* Handled in vlc_object_find */
872         break;
873     }
874
875     return NULL;
876 }
877
878 static void DetachObject( vlc_object_t *p_this )
879 {
880     vlc_object_t *p_parent = p_this->p_parent;
881     int i_index, i;
882
883     /* Remove p_this's parent */
884     p_this->p_parent = NULL;
885
886     /* Remove all of p_parent's children which are p_this */
887     for( i_index = p_parent->i_children ; i_index-- ; )
888     {
889         if( p_parent->pp_children[i_index] == p_this )
890         {
891             p_parent->i_children--;
892             for( i = i_index ; i < p_parent->i_children ; i++ )
893             {
894                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
895             }
896         }
897     }
898
899     if( p_parent->i_children )
900     {
901         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
902                                p_parent->i_children * sizeof(vlc_object_t *) );
903     }
904     else
905     {
906         free( p_parent->pp_children );
907         p_parent->pp_children = NULL;
908     }
909 }
910
911 /*****************************************************************************
912  * SetAttachment: recursively set the b_attached flag of a subtree.
913  *****************************************************************************
914  * This function is used by the attach and detach functions to propagate
915  * the b_attached flag in a subtree.
916  *****************************************************************************/
917 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
918 {
919     int i_index;
920
921     for( i_index = p_this->i_children ; i_index-- ; )
922     {
923         SetAttachment( p_this->pp_children[i_index], b_attached );
924     }
925
926     p_this->b_attached = b_attached;
927 }
928
929 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
930 {
931     char psz_children[20], psz_refcount[20], psz_thread[20], psz_name[50];
932
933     psz_name[0] = '\0';
934     if( p_this->psz_object_name )
935     {
936         snprintf( psz_name, 50, " \"%s\"", p_this->psz_object_name );
937         psz_name[48] = '\"';
938         psz_name[49] = '\0';
939     }
940
941     psz_children[0] = '\0';
942     switch( p_this->i_children )
943     {
944         case 0:
945             break;
946         case 1:
947             strcpy( psz_children, ", 1 child" );
948             break;
949         default:
950             snprintf( psz_children, 20,
951                       ", %i children", p_this->i_children );
952             psz_children[19] = '\0';
953             break;
954     }
955
956     psz_refcount[0] = '\0';
957     if( p_this->i_refcount )
958     {
959         snprintf( psz_refcount, 20, ", refcount %i", p_this->i_refcount );
960         psz_refcount[19] = '\0';
961     }
962
963     psz_thread[0] = '\0';
964     if( p_this->b_thread )
965     {
966         snprintf( psz_thread, 20, " (thread %d)", (int)p_this->thread_id );
967         psz_thread[19] = '\0';
968     }
969
970     printf( " %so %.8i %s%s%s%s%s\n", psz_prefix,
971             p_this->i_object_id, p_this->psz_object_type,
972             psz_name, psz_thread, psz_refcount, psz_children );
973 }
974
975 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
976 {
977     int i;
978     char i_back = psz_foo[i_level];
979     psz_foo[i_level] = '\0';
980
981     PrintObject( p_this, psz_foo );
982
983     psz_foo[i_level] = i_back;
984
985     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
986     {
987         msg_Warn( p_this, "structure tree is too deep" );
988         return;
989     }
990
991     for( i = 0 ; i < p_this->i_children ; i++ )
992     {
993         if( i_level )
994         {
995             psz_foo[i_level-1] = ' ';
996
997             if( psz_foo[i_level-2] == '`' )
998             {
999                 psz_foo[i_level-2] = ' ';
1000             }
1001         }
1002
1003         if( i == p_this->i_children - 1 )
1004         {
1005             psz_foo[i_level] = '`';
1006         }
1007         else
1008         {
1009             psz_foo[i_level] = '|';
1010         }
1011
1012         psz_foo[i_level+1] = '-';
1013         psz_foo[i_level+2] = '\0';
1014
1015         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
1016     }
1017 }
1018
1019 static vlc_list_t * NewList( int i_count )
1020 {
1021     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
1022     if( p_list == NULL )
1023     {
1024         return NULL;
1025     }
1026
1027     p_list->i_count = i_count;
1028
1029     if( i_count == 0 )
1030     {
1031         p_list->p_values = NULL;
1032         return p_list;
1033     }
1034
1035     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
1036     if( p_list->p_values == NULL )
1037     {
1038         p_list->i_count = 0;
1039         return p_list;
1040     }
1041
1042     return p_list;
1043 }
1044
1045 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
1046                          int i_index )
1047 {
1048     if( p_list == NULL || i_index >= p_list->i_count )
1049     {
1050         return;
1051     }
1052
1053     p_object->i_refcount++;
1054
1055     p_list->p_values[i_index].p_object = p_object;
1056
1057     return;
1058 }
1059
1060 /*static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
1061 {
1062     if( p_list == NULL )
1063     {
1064         return;
1065     }
1066
1067     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1068                                 * sizeof( vlc_value_t ) );
1069     if( p_list->p_values == NULL )
1070     {
1071         p_list->i_count = 0;
1072         return;
1073     }
1074
1075     p_object->i_refcount++;
1076
1077     p_list->p_values[p_list->i_count].p_object = p_object;
1078     p_list->i_count++;
1079
1080     return;
1081 }*/
1082
1083 static int CountChildren( vlc_object_t *p_this, int i_type )
1084 {
1085     vlc_object_t *p_tmp;
1086     int i, i_count = 0;
1087
1088     for( i = 0; i < p_this->i_children; i++ )
1089     {
1090         p_tmp = p_this->pp_children[i];
1091
1092         if( p_tmp->i_object_type == i_type )
1093         {
1094             i_count++;
1095         }
1096
1097         if( p_tmp->i_children )
1098         {
1099             i_count += CountChildren( p_tmp, i_type );
1100         }
1101     }
1102
1103     return i_count;
1104 }
1105
1106 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1107 {
1108     vlc_object_t *p_tmp;
1109     int i;
1110
1111     for( i = 0; i < p_this->i_children; i++ )
1112     {
1113         p_tmp = p_this->pp_children[i];
1114
1115         if( p_tmp->i_object_type == i_type )
1116         {
1117             ListReplace( p_list, p_tmp, p_list->i_count++ );
1118         }
1119
1120         if( p_tmp->i_children )
1121         {
1122             ListChildren( p_list, p_tmp, i_type );
1123         }
1124     }
1125 }