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