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