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