]> git.sesse.net Git - vlc/blob - src/misc/objects.c
Hide b_attached.
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2004-2007 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 "../libvlc.h"
40 #include <vlc_vout.h>
41 #include <vlc_aout.h>
42 #include "audio_output/aout_internal.h"
43
44 #include <vlc_access.h>
45 #include <vlc_demux.h>
46 #include <vlc_stream.h>
47
48 #include <vlc_sout.h>
49 #include "stream_output/stream_output.h"
50
51 #include "vlc_playlist.h"
52 #include "vlc_interface.h"
53 #include "vlc_codec.h"
54 #include "vlc_filter.h"
55
56 #include "vlc_httpd.h"
57 #include "vlc_vlm.h"
58 #include "input/vlm_internal.h"
59 #include "vlc_vod.h"
60 #include "vlc_tls.h"
61 #include "vlc_xml.h"
62 #include "vlc_osd.h"
63 #include "vlc_meta.h"
64
65 #include "variables.h"
66
67 /*****************************************************************************
68  * Local prototypes
69  *****************************************************************************/
70 static int  DumpCommand( vlc_object_t *, char const *,
71                          vlc_value_t, vlc_value_t, void * );
72
73 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
74 static vlc_object_t * FindObjectName( vlc_object_t *, const char *, int );
75 static void           DetachObject  ( vlc_object_t * );
76 static void           PrintObject   ( vlc_object_t *, const char * );
77 static void           DumpStructure ( vlc_object_t *, int, char * );
78 static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
79 static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
80
81 static vlc_list_t   * NewList       ( int );
82 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
83 /*static void           ListAppend    ( vlc_list_t *, vlc_object_t * );*/
84 static int            CountChildren ( vlc_object_t *, int );
85 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
86
87 /*****************************************************************************
88  * Local structure lock
89  *****************************************************************************/
90 static vlc_mutex_t    structure_lock;
91 static vlc_object_internals_t global_internals;
92
93 vlc_object_t *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
94                                  int i_type, const char *psz_type )
95 {
96     vlc_object_t *p_new;
97     vlc_object_internals_t *p_priv;
98
99     if( i_type == VLC_OBJECT_GLOBAL )
100     {
101         p_new = p_this;
102         p_priv = &global_internals;
103         memset( p_priv, 0, sizeof( *p_priv ) );
104     }
105     else
106     {
107         p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
108         if( p_priv == NULL )
109             return NULL;
110
111         p_new = (vlc_object_t *)(p_priv + 1);
112     }
113
114     p_new->p_internals = p_priv;
115     p_new->i_object_type = i_type;
116     p_new->psz_object_type = psz_type;
117
118     p_new->psz_object_name = NULL;
119
120     p_new->b_die = VLC_FALSE;
121     p_new->b_error = VLC_FALSE;
122     p_new->b_dead = VLC_FALSE;
123     p_priv->b_attached = VLC_FALSE;
124     p_new->b_force = VLC_FALSE;
125
126     p_new->psz_header = NULL;
127
128     if( p_this->i_flags & OBJECT_FLAGS_NODBG )
129         p_new->i_flags |= OBJECT_FLAGS_NODBG;
130     if( p_this->i_flags & OBJECT_FLAGS_QUIET )
131         p_new->i_flags |= OBJECT_FLAGS_QUIET;
132     if( p_this->i_flags & OBJECT_FLAGS_NOINTERACT )
133         p_new->i_flags |= OBJECT_FLAGS_NOINTERACT;
134
135     p_priv->p_vars = calloc( sizeof( variable_t ), 16 );
136
137     if( !p_priv->p_vars )
138     {
139         if( i_type != VLC_OBJECT_GLOBAL )
140             free( p_priv );
141         return NULL;
142     }
143
144     if( i_type == VLC_OBJECT_GLOBAL )
145     {
146         /* If i_type is global, then p_new is actually p_libvlc_global */
147         libvlc_global_data_t *p_libvlc_global = (libvlc_global_data_t *)p_new;
148         p_new->p_libvlc = NULL;
149
150         p_libvlc_global->i_counter = 0;
151         p_new->i_object_id = 0;
152
153         p_libvlc_global->i_objects = 1;
154         p_libvlc_global->pp_objects = malloc( sizeof(vlc_object_t *) );
155         p_libvlc_global->pp_objects[0] = p_new;
156         p_priv->b_attached = VLC_TRUE;
157     }
158     else
159     {
160         libvlc_global_data_t *p_libvlc_global = vlc_global();
161         if( i_type == VLC_OBJECT_LIBVLC )
162         {
163             p_new->p_libvlc = (libvlc_int_t*)p_new;
164             p_priv->b_attached = VLC_TRUE;
165         }
166         else
167         {
168             p_new->p_libvlc = p_this->p_libvlc;
169         }
170
171         vlc_mutex_lock( &structure_lock );
172
173         p_libvlc_global->i_counter++;
174         p_new->i_object_id = p_libvlc_global->i_counter;
175
176         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
177          * useless to try and recover anything if pp_objects gets smashed. */
178         TAB_APPEND( p_libvlc_global->i_objects, p_libvlc_global->pp_objects,
179                     p_new );
180
181         vlc_mutex_unlock( &structure_lock );
182     }
183
184     p_new->i_refcount = 0;
185     p_new->p_parent = NULL;
186     p_new->pp_children = NULL;
187     p_new->i_children = 0;
188
189     p_new->p_private = NULL;
190
191     /* Initialize mutexes and condvars */
192     vlc_mutex_init( p_new, &p_new->object_lock );
193     vlc_cond_init( p_new, &p_new->object_wait );
194     vlc_mutex_init( p_new, &p_priv->var_lock );
195
196     if( i_type == VLC_OBJECT_GLOBAL )
197     {
198         vlc_mutex_init( p_new, &structure_lock );
199
200         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
201         var_AddCallback( p_new, "list", DumpCommand, NULL );
202         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
203         var_AddCallback( p_new, "tree", DumpCommand, NULL );
204         var_Create( p_new, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
205         var_AddCallback( p_new, "vars", DumpCommand, NULL );
206     }
207
208     return p_new;
209 }
210
211
212 /**
213  * Allocates and initializes a vlc object.
214  *
215  * @param i_type known object type (all of them are negative integer values),
216  *               or object byte size (always positive).
217  *
218  * @return the new object, or NULL on error.
219  */
220 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
221 {
222     const char   * psz_type;
223     size_t         i_size;
224
225     switch( i_type )
226     {
227         case VLC_OBJECT_GLOBAL:
228             i_size = sizeof(libvlc_global_data_t);
229             psz_type = "global";
230             break;
231         case VLC_OBJECT_LIBVLC:
232             i_size = sizeof(libvlc_int_t);
233             psz_type = "libvlc";
234             break;
235         case VLC_OBJECT_INTF:
236             i_size = sizeof(intf_thread_t);
237             psz_type = "interface";
238             break;
239         case VLC_OBJECT_DIALOGS:
240             i_size = sizeof(intf_thread_t);
241             psz_type = "dialogs";
242             break;
243         case VLC_OBJECT_PLAYLIST:
244             i_size = sizeof(playlist_t);
245             psz_type = "playlist";
246             break;
247         case VLC_OBJECT_SD:
248             i_size = sizeof(services_discovery_t);
249             psz_type = "services discovery";
250             break;
251         case VLC_OBJECT_INPUT:
252             i_size = sizeof(input_thread_t);
253             psz_type = "input";
254             break;
255         case VLC_OBJECT_DEMUX:
256             i_size = sizeof(demux_t);
257             psz_type = "demux";
258             break;
259         case VLC_OBJECT_ACCESS:
260             i_size = sizeof(access_t);
261             psz_type = "access";
262             break;
263         case VLC_OBJECT_DECODER:
264             i_size = sizeof(decoder_t);
265             psz_type = "decoder";
266             break;
267         case VLC_OBJECT_PACKETIZER:
268             i_size = sizeof(decoder_t);
269             psz_type = "packetizer";
270             break;
271         case VLC_OBJECT_ENCODER:
272             i_size = sizeof(encoder_t);
273             psz_type = "encoder";
274             break;
275         case VLC_OBJECT_FILTER:
276             i_size = sizeof(filter_t);
277             psz_type = "filter";
278             break;
279         case VLC_OBJECT_VOUT:
280             i_size = sizeof(vout_thread_t);
281             psz_type = "video output";
282             break;
283         case VLC_OBJECT_SPU:
284             i_size = sizeof(spu_t);
285             psz_type = "subpicture";
286             break;
287         case VLC_OBJECT_AOUT:
288             i_size = sizeof(aout_instance_t);
289             psz_type = "audio output";
290             break;
291         case VLC_OBJECT_SOUT:
292             i_size = sizeof(sout_instance_t);
293             psz_type = "stream output";
294             break;
295         case VLC_OBJECT_VLM:
296             i_size = sizeof( vlm_t );
297             psz_type = "vlm dameon";
298             break;
299         case VLC_OBJECT_VOD:
300             i_size = sizeof( vod_t );
301             psz_type = "vod server";
302             break;
303         case VLC_OBJECT_TLS:
304             i_size = sizeof( tls_t );
305             psz_type = "tls";
306             break;
307         case VLC_OBJECT_XML:
308             i_size = sizeof( xml_t );
309             psz_type = "xml";
310             break;
311         case VLC_OBJECT_OPENGL:
312             i_size = sizeof( vout_thread_t );
313             psz_type = "opengl";
314             break;
315         case VLC_OBJECT_ANNOUNCE:
316             i_size = sizeof( announce_handler_t );
317             psz_type = "announce";
318             break;
319         case VLC_OBJECT_META_ENGINE:
320             i_size = sizeof( meta_engine_t );
321             psz_type = "meta engine";
322             break;
323         case VLC_OBJECT_OSDMENU:
324             i_size = sizeof( osd_menu_t );
325             psz_type = "osd menu";
326             break;
327         default:
328             i_size = i_type > (int)sizeof(vlc_object_t)
329                          ? i_type : (int)sizeof(vlc_object_t);
330             i_type = VLC_OBJECT_GENERIC;
331             psz_type = "generic";
332             break;
333     }
334
335     return vlc_custom_create( p_this, i_size, i_type, psz_type );
336 }
337
338
339 /**
340  ****************************************************************************
341  * Destroy a vlc object
342  *
343  * This function destroys an object that has been previously allocated with
344  * vlc_object_create. The object's refcount must be zero and it must not be
345  * attached to other objects in any way.
346  *****************************************************************************/
347 void __vlc_object_destroy( vlc_object_t *p_this )
348 {
349     vlc_object_internals_t *p_priv = vlc_internals( p_this );
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_priv->i_vars )
399     {
400         var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
401     }
402
403     free( p_priv->p_vars );
404     vlc_mutex_destroy( &p_priv->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         libvlc_global_data_t *p_global = (libvlc_global_data_t *)p_this;
411         /* We are the global object ... no need to lock. */
412         free( p_global->pp_objects );
413         p_global->pp_objects = NULL;
414         p_global->i_objects--;
415
416         vlc_mutex_destroy( &structure_lock );
417     }
418     else
419     {
420         libvlc_global_data_t *p_libvlc_global = vlc_global();
421         int i_index;
422
423         vlc_mutex_lock( &structure_lock );
424
425         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
426          * useless to try and recover anything if pp_objects gets smashed. */
427         i_index = FindIndex( p_this, p_libvlc_global->pp_objects,
428                              p_libvlc_global->i_objects );
429         REMOVE_ELEM( p_libvlc_global->pp_objects,
430                      p_libvlc_global->i_objects, i_index );
431
432         vlc_mutex_unlock( &structure_lock );
433     }
434
435 #if defined(WIN32) || defined(UNDER_CE)
436     /* if object has an associated thread, close it now */
437     if( p_priv->thread_id.hThread )
438        CloseHandle(p_priv->thread_id.hThread);
439 #endif
440
441     vlc_mutex_destroy( &p_this->object_lock );
442     vlc_cond_destroy( &p_this->object_wait );
443
444     /* global is not dynamically allocated by vlc_object_create */
445     if( p_this->i_object_type != VLC_OBJECT_GLOBAL )
446         free( p_priv );
447 }
448
449
450 void __vlc_object_kill( vlc_object_t *p_this )
451 {
452     vlc_mutex_lock( &p_this->object_lock );
453     p_this->b_die = VLC_TRUE;
454     vlc_mutex_unlock( &p_this->object_lock );
455 }
456
457
458 vlc_bool_t __vlc_object_dying_unlocked( vlc_object_t *p_this )
459 {
460     vlc_assert_locked( &p_this->object_lock );
461     return p_this->b_die;
462 }
463
464
465 vlc_bool_t __vlc_object_dying( vlc_object_t *p_this )
466 {
467      vlc_bool_t b;
468      vlc_mutex_lock( &p_this->object_lock );
469      b = __vlc_object_dying_unlocked( p_this );
470      vlc_mutex_unlock( &p_this->object_lock );
471      return b;
472 }
473
474
475 /**
476  * find an object given its ID
477  *
478  * This function looks for the object whose i_object_id field is i_id. We
479  * use a dichotomy so that lookups are in log2(n).
480  *****************************************************************************/
481 void * __vlc_object_get( vlc_object_t *p_this, int i_id )
482 {
483     int i_max, i_middle;
484     vlc_object_t **pp_objects;
485     libvlc_global_data_t *p_libvlc_global = vlc_global();
486
487     vlc_mutex_lock( &structure_lock );
488
489     pp_objects = p_libvlc_global->pp_objects;
490
491     /* Perform our dichotomy */
492     for( i_max = p_libvlc_global->i_objects - 1 ; ; )
493     {
494         i_middle = i_max / 2;
495
496         if( pp_objects[i_middle]->i_object_id > i_id )
497         {
498             i_max = i_middle;
499         }
500         else if( pp_objects[i_middle]->i_object_id < i_id )
501         {
502             if( i_middle )
503             {
504                 pp_objects += i_middle;
505                 i_max -= i_middle;
506             }
507             else
508             {
509                 /* This happens when there are only two remaining objects */
510                 if( pp_objects[i_middle+1]->i_object_id == i_id )
511                 {
512                     vlc_mutex_unlock( &structure_lock );
513                     pp_objects[i_middle+1]->i_refcount++;
514                     return pp_objects[i_middle+1];
515                 }
516                 break;
517             }
518         }
519         else
520         {
521             vlc_mutex_unlock( &structure_lock );
522             pp_objects[i_middle]->i_refcount++;
523             return pp_objects[i_middle];
524         }
525
526         if( i_max == 0 )
527         {
528             /* this means that i_max == i_middle, and since we have already
529              * tested pp_objects[i_middle]), p_found is properly set. */
530             break;
531         }
532     }
533
534     vlc_mutex_unlock( &structure_lock );
535     return NULL;
536 }
537
538 /**
539  ****************************************************************************
540  * find a typed object and increment its refcount
541  *****************************************************************************
542  * This function recursively looks for a given object type. i_mode can be one
543  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
544  *****************************************************************************/
545 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
546 {
547     vlc_object_t *p_found;
548
549     vlc_mutex_lock( &structure_lock );
550
551     /* If we are of the requested type ourselves, don't look further */
552     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
553     {
554         p_this->i_refcount++;
555         vlc_mutex_unlock( &structure_lock );
556         return p_this;
557     }
558
559     /* Otherwise, recursively look for the object */
560     if( (i_mode & 0x000f) == FIND_ANYWHERE )
561     {
562         vlc_object_t *p_root = p_this;
563
564         /* Find the root */
565         while( p_root->p_parent != NULL &&
566                p_root != VLC_OBJECT( p_this->p_libvlc ) )
567         {
568             p_root = p_root->p_parent;
569         }
570
571         p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
572         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
573         {
574             p_found = FindObject( VLC_OBJECT( p_this->p_libvlc ),
575                                   i_type, (i_mode & ~0x000f)|FIND_CHILD );
576         }
577     }
578     else
579     {
580         p_found = FindObject( p_this, i_type, i_mode );
581     }
582
583     vlc_mutex_unlock( &structure_lock );
584
585     return p_found;
586 }
587
588 /**
589  ****************************************************************************
590  * find a named object and increment its refcount
591  *****************************************************************************
592  * This function recursively looks for a given object name. i_mode can be one
593  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
594  *****************************************************************************/
595 void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
596                                int i_mode )
597 {
598     vlc_object_t *p_found;
599
600     vlc_mutex_lock( &structure_lock );
601
602     /* If have the requested name ourselves, don't look further */
603     if( !(i_mode & FIND_STRICT)
604         && p_this->psz_object_name
605         && !strcmp( p_this->psz_object_name, psz_name ) )
606     {
607         p_this->i_refcount++;
608         vlc_mutex_unlock( &structure_lock );
609         return p_this;
610     }
611
612     /* Otherwise, recursively look for the object */
613     if( (i_mode & 0x000f) == FIND_ANYWHERE )
614     {
615         vlc_object_t *p_root = p_this;
616
617         /* Find the root */
618         while( p_root->p_parent != NULL &&
619                p_root != VLC_OBJECT( p_this->p_libvlc ) )
620         {
621             p_root = p_root->p_parent;
622         }
623
624         p_found = FindObjectName( p_root, psz_name,
625                                  (i_mode & ~0x000f)|FIND_CHILD );
626         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
627         {
628             p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
629                                       psz_name, (i_mode & ~0x000f)|FIND_CHILD );
630         }
631     }
632     else
633     {
634         p_found = FindObjectName( p_this, psz_name, i_mode );
635     }
636
637     vlc_mutex_unlock( &structure_lock );
638
639     return p_found;
640 }
641
642 /**
643  ****************************************************************************
644  * increment an object refcount
645  *****************************************************************************/
646 void __vlc_object_yield( vlc_object_t *p_this )
647 {
648     vlc_mutex_lock( &structure_lock );
649     p_this->i_refcount++;
650     vlc_mutex_unlock( &structure_lock );
651 }
652
653 /**
654  ****************************************************************************
655  * decrement an object refcount
656  *****************************************************************************/
657 void __vlc_object_release( vlc_object_t *p_this )
658 {
659     vlc_mutex_lock( &structure_lock );
660     p_this->i_refcount--;
661     vlc_mutex_unlock( &structure_lock );
662 }
663
664 /**
665  ****************************************************************************
666  * attach object to a parent object
667  *****************************************************************************
668  * This function sets p_this as a child of p_parent, and p_parent as a parent
669  * of p_this. This link can be undone using vlc_object_detach.
670  *****************************************************************************/
671 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
672 {
673     if( !p_this ) return;
674
675     vlc_mutex_lock( &structure_lock );
676
677     /* Attach the parent to its child */
678     p_this->p_parent = p_parent;
679
680     /* Attach the child to its parent */
681     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
682                  p_parent->i_children, p_this );
683
684     /* Climb up the tree to see whether we are connected with the root */
685     if( p_parent->p_internals->b_attached )
686     {
687         SetAttachment( p_this, VLC_TRUE );
688     }
689
690     vlc_mutex_unlock( &structure_lock );
691 }
692
693 /**
694  ****************************************************************************
695  * detach object from its parent
696  *****************************************************************************
697  * This function removes all links between an object and its parent.
698  *****************************************************************************/
699 void __vlc_object_detach( vlc_object_t *p_this )
700 {
701     if( !p_this ) return;
702
703     vlc_mutex_lock( &structure_lock );
704     if( !p_this->p_parent )
705     {
706         msg_Err( p_this, "object is not attached" );
707         vlc_mutex_unlock( &structure_lock );
708         return;
709     }
710
711     /* Climb up the tree to see whether we are connected with the root */
712     if( p_this->p_parent->p_internals->b_attached )
713     {
714         SetAttachment( p_this, VLC_FALSE );
715     }
716
717     DetachObject( p_this );
718     vlc_mutex_unlock( &structure_lock );
719     p_this = NULL;
720 }
721
722 /**
723  ****************************************************************************
724  * find a list typed objects and increment their refcount
725  *****************************************************************************
726  * This function recursively looks for a given object type. i_mode can be one
727  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
728  *****************************************************************************/
729 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
730 {
731     vlc_list_t *p_list;
732     vlc_object_t **pp_current, **pp_end;
733     int i_count = 0, i_index = 0;
734     libvlc_global_data_t *p_libvlc_global = vlc_global();
735
736     vlc_mutex_lock( &structure_lock );
737
738     /* Look for the objects */
739     switch( i_mode & 0x000f )
740     {
741     case FIND_ANYWHERE:
742         pp_current = p_libvlc_global->pp_objects;
743         pp_end = pp_current + p_libvlc_global->i_objects;
744
745         for( ; pp_current < pp_end ; pp_current++ )
746         {
747             if( (*pp_current)->p_internals->b_attached
748                  && (*pp_current)->i_object_type == i_type )
749             {
750                 i_count++;
751             }
752         }
753
754         p_list = NewList( i_count );
755         pp_current = p_libvlc_global->pp_objects;
756
757         for( ; pp_current < pp_end ; pp_current++ )
758         {
759             if( (*pp_current)->p_internals->b_attached
760                  && (*pp_current)->i_object_type == i_type )
761             {
762                 ListReplace( p_list, *pp_current, i_index );
763                 if( i_index < i_count ) i_index++;
764             }
765         }
766     break;
767
768     case FIND_CHILD:
769         i_count = CountChildren( p_this, i_type );
770         p_list = NewList( i_count );
771
772         /* Check allocation was successful */
773         if( p_list->i_count != i_count )
774         {
775             msg_Err( p_this, "list allocation failed!" );
776             p_list->i_count = 0;
777             break;
778         }
779
780         p_list->i_count = 0;
781         ListChildren( p_list, p_this, i_type );
782         break;
783
784     default:
785         msg_Err( p_this, "unimplemented!" );
786         p_list = NewList( 0 );
787         break;
788     }
789
790     vlc_mutex_unlock( &structure_lock );
791
792     return p_list;
793 }
794
795 /*****************************************************************************
796  * DumpCommand: print the current vlc structure
797  *****************************************************************************
798  * This function prints either an ASCII tree showing the connections between
799  * vlc objects, and additional information such as their refcount, thread ID,
800  * etc. (command "tree"), or the same data as a simple list (command "list").
801  *****************************************************************************/
802 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
803                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
804 {
805     libvlc_global_data_t *p_libvlc_global = vlc_global();
806
807     (void)oldval; (void)p_data;
808     if( *psz_cmd == 'l' )
809     {
810         vlc_mutex_lock( &structure_lock );
811
812         vlc_object_t **pp_current, **pp_end;
813
814         pp_current = p_libvlc_global->pp_objects;
815         pp_end = pp_current + p_libvlc_global->i_objects;
816
817         for( ; pp_current < pp_end ; pp_current++ )
818         {
819             if( (*pp_current)->p_internals->b_attached )
820             {
821                 PrintObject( *pp_current, "" );
822             }
823             else
824             {
825                 printf( " o %.8i %s (not attached)\n",
826                         (*pp_current)->i_object_id,
827                         (*pp_current)->psz_object_type );
828             }
829         }
830
831         vlc_mutex_unlock( &structure_lock );
832     }
833     else
834     {
835         vlc_object_t *p_object = NULL;
836
837         if( *newval.psz_string )
838         {
839             char *end;
840             int i_id = strtol( newval.psz_string, &end, 0 );
841             if( end != newval.psz_string )
842                 p_object = vlc_object_get( p_this, i_id );
843             else
844             {
845                 /* try using the object's name to find it */
846                 vlc_object_t *p_libvlc = vlc_object_get( p_this, 1 );
847                 if( p_libvlc )
848                 {
849                     /* Look in p_libvlc's children tree */
850                     p_object = vlc_object_find_name( p_libvlc,
851                                                      newval.psz_string,
852                                                      FIND_CHILD );
853                     vlc_object_release( p_libvlc );
854                 }
855                 if( !p_object )
856                 {
857                     /* If it's not in libvlc, look in libvlc_global (== p_this) */
858                     p_object = vlc_object_find_name( p_this,
859                                                      newval.psz_string,
860                                                      FIND_CHILD );
861                 }
862             }
863
864             if( !p_object )
865             {
866                 return VLC_ENOOBJ;
867             }
868         }
869
870         vlc_mutex_lock( &structure_lock );
871
872         if( *psz_cmd == 't' )
873         {
874             char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
875
876             if( !p_object )
877                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
878
879             psz_foo[0] = '|';
880             DumpStructure( p_object, 0, psz_foo );
881         }
882         else if( *psz_cmd == 'v' )
883         {
884             int i;
885
886             if( !p_object )
887                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
888
889             PrintObject( p_object, "" );
890
891             if( !p_object->p_internals->i_vars )
892                 printf( " `-o No variables\n" );
893             for( i = 0; i < p_object->p_internals->i_vars; i++ )
894             {
895                 variable_t *p_var = p_object->p_internals->p_vars + i;
896
897                 const char *psz_type = "unknown";
898                 switch( p_var->i_type & VLC_VAR_TYPE )
899                 {
900 #define MYCASE( type, nice )                \
901                     case VLC_VAR_ ## type:  \
902                         psz_type = nice;    \
903                         break;
904                     MYCASE( VOID, "void" );
905                     MYCASE( BOOL, "bool" );
906                     MYCASE( INTEGER, "integer" );
907                     MYCASE( HOTKEY, "hotkey" );
908                     MYCASE( STRING, "string" );
909                     MYCASE( MODULE, "module" );
910                     MYCASE( FILE, "file" );
911                     MYCASE( DIRECTORY, "directory" );
912                     MYCASE( VARIABLE, "variable" );
913                     MYCASE( FLOAT, "float" );
914                     MYCASE( TIME, "time" );
915                     MYCASE( ADDRESS, "address" );
916                     MYCASE( MUTEX, "mutex" );
917                     MYCASE( LIST, "list" );
918 #undef MYCASE
919                 }
920                 printf( " %c-o \"%s\" (%s",
921                         i + 1 == p_object->p_internals->i_vars ? '`' : '|',
922                         p_var->psz_name, psz_type );
923                 if( p_var->psz_text )
924                     printf( ", %s", p_var->psz_text );
925                 printf( ")" );
926                 if( p_var->i_type & VLC_VAR_ISCOMMAND )
927                     printf( ", command" );
928                 if( p_var->i_entries )
929                     printf( ", %d callbacks", p_var->i_entries );
930                 switch( p_var->i_type & 0x00f0 )
931                 {
932                     case VLC_VAR_VOID:
933                     case VLC_VAR_MUTEX:
934                         break;
935                     case VLC_VAR_BOOL:
936                         printf( ": %s", p_var->val.b_bool ? "true" : "false" );
937                         break;
938                     case VLC_VAR_INTEGER:
939                         printf( ": %d", p_var->val.i_int );
940                         break;
941                     case VLC_VAR_STRING:
942                         printf( ": \"%s\"", p_var->val.psz_string );
943                         break;
944                     case VLC_VAR_FLOAT:
945                         printf( ": %f", p_var->val.f_float );
946                         break;
947                     case VLC_VAR_TIME:
948                         printf( ": " I64Fi, (int64_t)p_var->val.i_time );
949                         break;
950                     case VLC_VAR_ADDRESS:
951                         printf( ": %p", p_var->val.p_address );
952                         break;
953                     case VLC_VAR_LIST:
954                         printf( ": TODO" );
955                         break;
956                 }
957                 printf( "\n" );
958             }
959         }
960
961         vlc_mutex_unlock( &structure_lock );
962
963         if( *newval.psz_string )
964         {
965             vlc_object_release( p_object );
966         }
967     }
968
969     return VLC_SUCCESS;
970 }
971
972 /*****************************************************************************
973  * vlc_list_release: free a list previously allocated by vlc_list_find
974  *****************************************************************************
975  * This function decreases the refcount of all objects in the list and
976  * frees the list.
977  *****************************************************************************/
978 void vlc_list_release( vlc_list_t *p_list )
979 {
980     int i_index;
981
982     vlc_mutex_lock( &structure_lock );
983     for( i_index = 0; i_index < p_list->i_count; i_index++ )
984     {
985         p_list->p_values[i_index].p_object->i_refcount--;
986     }
987     vlc_mutex_unlock( &structure_lock );
988
989     free( p_list->p_values );
990     free( p_list );
991 }
992
993 /* Following functions are local */
994
995 /*****************************************************************************
996  * FindIndex: find the index of an object in an array of objects
997  *****************************************************************************
998  * This function assumes that p_this can be found in pp_objects. It will not
999  * crash if p_this cannot be found, but will return a wrong value. It is your
1000  * duty to check the return value if you are not certain that the object could
1001  * be found for sure.
1002  *****************************************************************************/
1003 static int FindIndex( vlc_object_t *p_this,
1004                       vlc_object_t **pp_objects, int i_count )
1005 {
1006     int i_middle = i_count / 2;
1007
1008     if( i_count == 0 )
1009     {
1010         return 0;
1011     }
1012
1013     if( pp_objects[i_middle] == p_this )
1014     {
1015         return i_middle;
1016     }
1017
1018     if( i_count == 1 )
1019     {
1020         return 0;
1021     }
1022
1023     /* We take advantage of the sorted array */
1024     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
1025     {
1026         return i_middle + FindIndex( p_this, pp_objects + i_middle,
1027                                              i_count - i_middle );
1028     }
1029     else
1030     {
1031         return FindIndex( p_this, pp_objects, i_middle );
1032     }
1033 }
1034
1035 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
1036 {
1037     int i;
1038     vlc_object_t *p_tmp;
1039
1040     switch( i_mode & 0x000f )
1041     {
1042     case FIND_PARENT:
1043         p_tmp = p_this->p_parent;
1044         if( p_tmp )
1045         {
1046             if( p_tmp->i_object_type == i_type )
1047             {
1048                 p_tmp->i_refcount++;
1049                 return p_tmp;
1050             }
1051             else
1052             {
1053                 return FindObject( p_tmp, i_type, i_mode );
1054             }
1055         }
1056         break;
1057
1058     case FIND_CHILD:
1059         for( i = p_this->i_children; i--; )
1060         {
1061             p_tmp = p_this->pp_children[i];
1062             if( p_tmp->i_object_type == i_type )
1063             {
1064                 p_tmp->i_refcount++;
1065                 return p_tmp;
1066             }
1067             else if( p_tmp->i_children )
1068             {
1069                 p_tmp = FindObject( p_tmp, i_type, i_mode );
1070                 if( p_tmp )
1071                 {
1072                     return p_tmp;
1073                 }
1074             }
1075         }
1076         break;
1077
1078     case FIND_ANYWHERE:
1079         /* Handled in vlc_object_find */
1080         break;
1081     }
1082
1083     return NULL;
1084 }
1085
1086 static vlc_object_t * FindObjectName( vlc_object_t *p_this,
1087                                       const char *psz_name,
1088                                       int i_mode )
1089 {
1090     int i;
1091     vlc_object_t *p_tmp;
1092
1093     switch( i_mode & 0x000f )
1094     {
1095     case FIND_PARENT:
1096         p_tmp = p_this->p_parent;
1097         if( p_tmp )
1098         {
1099             if( p_tmp->psz_object_name
1100                 && !strcmp( p_tmp->psz_object_name, psz_name ) )
1101             {
1102                 p_tmp->i_refcount++;
1103                 return p_tmp;
1104             }
1105             else
1106             {
1107                 return FindObjectName( p_tmp, psz_name, i_mode );
1108             }
1109         }
1110         break;
1111
1112     case FIND_CHILD:
1113         for( i = p_this->i_children; i--; )
1114         {
1115             p_tmp = p_this->pp_children[i];
1116             if( p_tmp->psz_object_name
1117                 && !strcmp( p_tmp->psz_object_name, psz_name ) )
1118             {
1119                 p_tmp->i_refcount++;
1120                 return p_tmp;
1121             }
1122             else if( p_tmp->i_children )
1123             {
1124                 p_tmp = FindObjectName( p_tmp, psz_name, i_mode );
1125                 if( p_tmp )
1126                 {
1127                     return p_tmp;
1128                 }
1129             }
1130         }
1131         break;
1132
1133     case FIND_ANYWHERE:
1134         /* Handled in vlc_object_find */
1135         break;
1136     }
1137
1138     return NULL;
1139 }
1140
1141 static void DetachObject( vlc_object_t *p_this )
1142 {
1143     vlc_object_t *p_parent = p_this->p_parent;
1144     int i_index, i;
1145
1146     /* Remove p_this's parent */
1147     p_this->p_parent = NULL;
1148
1149     /* Remove all of p_parent's children which are p_this */
1150     for( i_index = p_parent->i_children ; i_index-- ; )
1151     {
1152         if( p_parent->pp_children[i_index] == p_this )
1153         {
1154             p_parent->i_children--;
1155             for( i = i_index ; i < p_parent->i_children ; i++ )
1156             {
1157                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
1158             }
1159         }
1160     }
1161
1162     if( p_parent->i_children )
1163     {
1164         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
1165                                p_parent->i_children * sizeof(vlc_object_t *) );
1166     }
1167     else
1168     {
1169         free( p_parent->pp_children );
1170         p_parent->pp_children = NULL;
1171     }
1172 }
1173
1174 /*****************************************************************************
1175  * SetAttachment: recursively set the b_attached flag of a subtree.
1176  *****************************************************************************
1177  * This function is used by the attach and detach functions to propagate
1178  * the b_attached flag in a subtree.
1179  *****************************************************************************/
1180 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
1181 {
1182     int i_index;
1183
1184     for( i_index = p_this->i_children ; i_index-- ; )
1185     {
1186         SetAttachment( p_this->pp_children[i_index], b_attached );
1187     }
1188
1189     p_this->p_internals->b_attached = b_attached;
1190 }
1191
1192 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
1193 {
1194     char psz_children[20], psz_refcount[20], psz_thread[30], psz_name[50],
1195          psz_parent[20];
1196
1197     psz_name[0] = '\0';
1198     if( p_this->psz_object_name )
1199     {
1200         snprintf( psz_name, 49, " \"%s\"", p_this->psz_object_name );
1201         if( psz_name[48] )
1202             psz_name[48] = '\"';
1203     }
1204
1205     psz_children[0] = '\0';
1206     switch( p_this->i_children )
1207     {
1208         case 0:
1209             break;
1210         case 1:
1211             strcpy( psz_children, ", 1 child" );
1212             break;
1213         default:
1214             snprintf( psz_children, 19, ", %i children", p_this->i_children );
1215             break;
1216     }
1217
1218     psz_refcount[0] = '\0';
1219     if( p_this->i_refcount )
1220         snprintf( psz_refcount, 19, ", refcount %i", p_this->i_refcount );
1221
1222     psz_thread[0] = '\0';
1223     if( p_this->p_internals->b_thread )
1224         snprintf( psz_thread, 29, " (thread %u)",
1225 #if defined(WIN32) || defined(UNDER_CE)
1226                   (unsigned)p_this->p_internals->thread_id.id );
1227 #else
1228                   (unsigned)p_this->p_internals->thread_id );
1229 #endif
1230
1231     psz_parent[0] = '\0';
1232     if( p_this->p_parent )
1233         snprintf( psz_parent, 19, ", parent %i", p_this->p_parent->i_object_id );
1234
1235     printf( " %so %.8i %s%s%s%s%s%s\n", psz_prefix,
1236             p_this->i_object_id, p_this->psz_object_type,
1237             psz_name, psz_thread, psz_refcount, psz_children,
1238             psz_parent );
1239 }
1240
1241 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
1242 {
1243     int i;
1244     char i_back = psz_foo[i_level];
1245     psz_foo[i_level] = '\0';
1246
1247     PrintObject( p_this, psz_foo );
1248
1249     psz_foo[i_level] = i_back;
1250
1251     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
1252     {
1253         msg_Warn( p_this, "structure tree is too deep" );
1254         return;
1255     }
1256
1257     for( i = 0 ; i < p_this->i_children ; i++ )
1258     {
1259         if( i_level )
1260         {
1261             psz_foo[i_level-1] = ' ';
1262
1263             if( psz_foo[i_level-2] == '`' )
1264             {
1265                 psz_foo[i_level-2] = ' ';
1266             }
1267         }
1268
1269         if( i == p_this->i_children - 1 )
1270         {
1271             psz_foo[i_level] = '`';
1272         }
1273         else
1274         {
1275             psz_foo[i_level] = '|';
1276         }
1277
1278         psz_foo[i_level+1] = '-';
1279         psz_foo[i_level+2] = '\0';
1280
1281         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
1282     }
1283 }
1284
1285 static vlc_list_t * NewList( int i_count )
1286 {
1287     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
1288     if( p_list == NULL )
1289     {
1290         return NULL;
1291     }
1292
1293     p_list->i_count = i_count;
1294
1295     if( i_count == 0 )
1296     {
1297         p_list->p_values = NULL;
1298         return p_list;
1299     }
1300
1301     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
1302     if( p_list->p_values == NULL )
1303     {
1304         p_list->i_count = 0;
1305         return p_list;
1306     }
1307
1308     return p_list;
1309 }
1310
1311 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
1312                          int i_index )
1313 {
1314     if( p_list == NULL || i_index >= p_list->i_count )
1315     {
1316         return;
1317     }
1318
1319     p_object->i_refcount++;
1320
1321     p_list->p_values[i_index].p_object = p_object;
1322
1323     return;
1324 }
1325
1326 /*static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
1327 {
1328     if( p_list == NULL )
1329     {
1330         return;
1331     }
1332
1333     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1334                                 * sizeof( vlc_value_t ) );
1335     if( p_list->p_values == NULL )
1336     {
1337         p_list->i_count = 0;
1338         return;
1339     }
1340
1341     p_object->i_refcount++;
1342
1343     p_list->p_values[p_list->i_count].p_object = p_object;
1344     p_list->i_count++;
1345
1346     return;
1347 }*/
1348
1349 static int CountChildren( vlc_object_t *p_this, int i_type )
1350 {
1351     vlc_object_t *p_tmp;
1352     int i, i_count = 0;
1353
1354     for( i = 0; i < p_this->i_children; i++ )
1355     {
1356         p_tmp = p_this->pp_children[i];
1357
1358         if( p_tmp->i_object_type == i_type )
1359         {
1360             i_count++;
1361         }
1362
1363         if( p_tmp->i_children )
1364         {
1365             i_count += CountChildren( p_tmp, i_type );
1366         }
1367     }
1368
1369     return i_count;
1370 }
1371
1372 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1373 {
1374     vlc_object_t *p_tmp;
1375     int i;
1376
1377     for( i = 0; i < p_this->i_children; i++ )
1378     {
1379         p_tmp = p_this->pp_children[i];
1380
1381         if( p_tmp->i_object_type == i_type )
1382         {
1383             ListReplace( p_list, p_tmp, p_list->i_count++ );
1384         }
1385
1386         if( p_tmp->i_children )
1387         {
1388             ListChildren( p_list, p_tmp, i_type );
1389         }
1390     }
1391 }