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