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