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