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