]> git.sesse.net Git - vlc/blob - src/misc/objects.c
Allow setting the name of an object at any time...
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2004-2008 the VideoLAN team
5  *
6  * Authors: Samuel Hocevar <sam@zoy.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 /**
24  * \file
25  * This file contains the functions to handle the vlc_object_t type
26  *
27  * Unless otherwise stated, functions in this file are not cancellation point.
28  * All functions in this file are safe w.r.t. deferred cancellation.
29  */
30
31
32 /*****************************************************************************
33  * Preamble
34  *****************************************************************************/
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #include <vlc_common.h>
40
41 #include "../libvlc.h"
42 #include <vlc_aout.h>
43 #include "audio_output/aout_internal.h"
44
45 #include "vlc_interface.h"
46 #include "vlc_codec.h"
47
48 #include "variables.h"
49 #ifndef WIN32
50 # include <unistd.h>
51 #else
52 # include <io.h>
53 # include <fcntl.h>
54 # include <errno.h> /* ENOSYS */
55 #endif
56
57 #include <limits.h>
58 #include <assert.h>
59
60 #if defined (HAVE_SYS_EVENTFD_H)
61 # include <sys/eventfd.h>
62 #endif
63
64
65 /*****************************************************************************
66  * Local prototypes
67  *****************************************************************************/
68 static int  DumpCommand( vlc_object_t *, char const *,
69                          vlc_value_t, vlc_value_t, void * );
70
71 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
72 static vlc_object_t * FindObjectName( vlc_object_t *, const char *, int );
73 static void           PrintObject   ( vlc_object_t *, const char * );
74 static void           DumpStructure ( vlc_object_t *, int, char * );
75
76 static vlc_list_t   * NewList       ( int );
77 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
78 /*static void           ListAppend    ( vlc_list_t *, vlc_object_t * );*/
79 static int            CountChildren ( vlc_object_t *, int );
80 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
81
82 static void vlc_object_destroy( vlc_object_t *p_this );
83 static void vlc_object_detach_unlocked (vlc_object_t *p_this);
84 #ifndef NDEBUG
85 static void vlc_object_dump( vlc_object_t *p_this );
86 #endif
87
88 /*****************************************************************************
89  * Local structure lock
90  *****************************************************************************/
91 static void libvlc_lock (libvlc_int_t *p_libvlc)
92 {
93     vlc_mutex_lock (&(libvlc_priv (p_libvlc)->structure_lock));
94 }
95
96 static void libvlc_unlock (libvlc_int_t *p_libvlc)
97 {
98     vlc_mutex_unlock (&(libvlc_priv (p_libvlc)->structure_lock));
99 }
100
101 void *__vlc_custom_create( vlc_object_t *p_this, size_t i_size,
102                            int i_type, const char *psz_type )
103 {
104     vlc_object_t *p_new;
105     vlc_object_internals_t *p_priv;
106
107     /* NOTE:
108      * VLC objects are laid out as follow:
109      * - first the LibVLC-private per-object data,
110      * - then VLC_COMMON members from vlc_object_t,
111      * - finally, the type-specific data (if any).
112      *
113      * This function initializes the LibVLC and common data,
114      * and zeroes the rest.
115      */
116     p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
117     if( p_priv == NULL )
118         return NULL;
119
120     assert (i_size >= sizeof (vlc_object_t));
121     p_new = (vlc_object_t *)(p_priv + 1);
122
123     p_priv->i_object_type = i_type;
124     p_new->psz_object_type = psz_type;
125     p_priv->psz_name = NULL;
126
127     p_new->b_die = false;
128     p_new->b_error = false;
129     p_new->b_force = false;
130
131     p_new->psz_header = NULL;
132
133     if (p_this)
134         p_new->i_flags = p_this->i_flags
135             & (OBJECT_FLAGS_NODBG|OBJECT_FLAGS_QUIET|OBJECT_FLAGS_NOINTERACT);
136
137     p_priv->p_vars = calloc( 16, sizeof( variable_t ) );
138
139     if( !p_priv->p_vars )
140     {
141         free( p_priv );
142         return NULL;
143     }
144
145     if( p_this == NULL )
146     {
147         libvlc_int_t *self = (libvlc_int_t*)p_new;
148         p_new->p_libvlc = self;
149         vlc_mutex_init (&(libvlc_priv (self)->structure_lock));
150         p_this = p_priv->next = p_priv->prev = p_new;
151     }
152     else
153         p_new->p_libvlc = p_this->p_libvlc;
154
155     vlc_spin_init( &p_priv->ref_spin );
156     p_priv->i_refcount = 1;
157     p_priv->pf_destructor = NULL;
158     p_priv->b_thread = false;
159     p_new->p_parent = NULL;
160     p_priv->pp_children = NULL;
161     p_priv->i_children = 0;
162
163     /* Initialize mutexes and condvars */
164     vlc_mutex_init( &p_priv->var_lock );
165     vlc_cond_init( &p_priv->var_wait );
166     p_priv->pipes[0] = p_priv->pipes[1] = -1;
167
168     p_priv->next = p_this;
169     libvlc_lock (p_new->p_libvlc);
170     p_priv->prev = vlc_internals (p_this)->prev;
171     vlc_internals (p_this)->prev = p_new;
172     vlc_internals (p_priv->prev)->next = p_new;
173     libvlc_unlock (p_new->p_libvlc);
174
175     if (p_new == VLC_OBJECT(p_new->p_libvlc))
176     {   /* TODO: should be in src/libvlc.c */
177         int canc = vlc_savecancel ();
178         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
179         var_AddCallback( p_new, "list", DumpCommand, NULL );
180         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
181         var_AddCallback( p_new, "tree", DumpCommand, NULL );
182         var_Create( p_new, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
183         var_AddCallback( p_new, "vars", DumpCommand, NULL );
184         vlc_restorecancel (canc);
185     }
186
187     return p_new;
188 }
189
190
191 /**
192  * Allocates and initializes a vlc object.
193  *
194  * @param i_type known object type (all of them are negative integer values),
195  *               or object byte size (always positive).
196  *
197  * @return the new object, or NULL on error.
198  */
199 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
200 {
201     const char   * psz_type;
202     size_t         i_size;
203
204     switch( i_type )
205     {
206         case VLC_OBJECT_DECODER:
207             i_size = sizeof(decoder_t);
208             psz_type = "decoder";
209             break;
210         case VLC_OBJECT_AOUT:
211             i_size = sizeof(aout_instance_t);
212             psz_type = "audio output";
213             break;
214         default:
215             assert( i_type > 0 ); /* unknown type?! */
216             i_size = i_type;
217             i_type = VLC_OBJECT_GENERIC;
218             psz_type = "generic";
219             break;
220     }
221
222     return vlc_custom_create( p_this, i_size, i_type, psz_type );
223 }
224
225
226 /**
227  ****************************************************************************
228  * Set the destructor of a vlc object
229  *
230  * This function sets the destructor of the vlc object. It will be called
231  * when the object is destroyed when the its refcount reaches 0.
232  * (It is called by the internal function vlc_object_destroy())
233  *****************************************************************************/
234 void __vlc_object_set_destructor( vlc_object_t *p_this,
235                                   vlc_destructor_t pf_destructor )
236 {
237     vlc_object_internals_t *p_priv = vlc_internals(p_this );
238
239     vlc_spin_lock( &p_priv->ref_spin );
240     p_priv->pf_destructor = pf_destructor;
241     vlc_spin_unlock( &p_priv->ref_spin );
242 }
243
244 static vlc_mutex_t name_lock = VLC_STATIC_MUTEX;
245
246 #undef vlc_object_set_name
247 int vlc_object_set_name(vlc_object_t *obj, const char *name)
248 {
249     vlc_object_internals_t *priv = vlc_internals(obj);
250     char *newname = name ? strdup (name) : NULL;
251     char *oldname;
252
253     vlc_mutex_lock (&name_lock);
254     oldname = priv->psz_name;
255     priv->psz_name = newname;
256     vlc_mutex_unlock (&name_lock);
257
258     free (oldname);
259     return (priv->psz_name || !name) ? VLC_SUCCESS : VLC_ENOMEM;
260 }
261
262 #undef vlc_object_get_name
263 char *vlc_object_get_name(const vlc_object_t *obj)
264 {
265     vlc_object_internals_t *priv = vlc_internals(obj);
266     char *name;
267
268     vlc_mutex_lock (&name_lock);
269     name = priv->psz_name ? strdup (priv->psz_name) : NULL;
270     vlc_mutex_unlock (&name_lock);
271
272     return name;
273 }
274
275 /**
276  ****************************************************************************
277  * Destroy a vlc object (Internal)
278  *
279  * This function destroys an object that has been previously allocated with
280  * vlc_object_create. The object's refcount must be zero and it must not be
281  * attached to other objects in any way.
282  *
283  * This function must be called with cancellation disabled (currently).
284  *****************************************************************************/
285 static void vlc_object_destroy( vlc_object_t *p_this )
286 {
287     vlc_object_internals_t *p_priv = vlc_internals( p_this );
288
289     /* Objects are always detached beforehand */
290     assert( !p_this->p_parent );
291
292     /* Send a kill to the object's thread if applicable */
293     vlc_object_kill( p_this );
294
295     /* Call the custom "subclass" destructor */
296     if( p_priv->pf_destructor )
297         p_priv->pf_destructor( p_this );
298
299     /* Any thread must have been cleaned up at this point. */
300     assert( !p_priv->b_thread );
301
302     /* Destroy the associated variables, starting from the end so that
303      * no memmove calls have to be done. */
304     while( p_priv->i_vars )
305     {
306         var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
307     }
308
309     free( p_priv->p_vars );
310     vlc_cond_destroy( &p_priv->var_wait );
311     vlc_mutex_destroy( &p_priv->var_lock );
312
313     free( p_this->psz_header );
314
315     free( p_priv->psz_name );
316
317     vlc_spin_destroy( &p_priv->ref_spin );
318     if( p_priv->pipes[1] != -1 && p_priv->pipes[1] != p_priv->pipes[0] )
319         close( p_priv->pipes[1] );
320     if( p_priv->pipes[0] != -1 )
321         close( p_priv->pipes[0] );
322     if( VLC_OBJECT(p_this->p_libvlc) == p_this )
323         vlc_mutex_destroy (&(libvlc_priv ((libvlc_int_t *)p_this)->structure_lock));
324
325     free( p_priv );
326 }
327
328
329 #ifdef WIN32
330 # include <winsock2.h>
331 # include <ws2tcpip.h>
332
333 /**
334  * select()-able pipes emulated using Winsock
335  */
336 static int pipe (int fd[2])
337 {
338     SOCKADDR_IN addr;
339     int addrlen = sizeof (addr);
340
341     SOCKET l = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP), a,
342            c = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
343     if ((l == INVALID_SOCKET) || (c == INVALID_SOCKET))
344         goto error;
345
346     memset (&addr, 0, sizeof (addr));
347     addr.sin_family = AF_INET;
348     addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
349     if (bind (l, (PSOCKADDR)&addr, sizeof (addr))
350      || getsockname (l, (PSOCKADDR)&addr, &addrlen)
351      || listen (l, 1)
352      || connect (c, (PSOCKADDR)&addr, addrlen))
353         goto error;
354
355     a = accept (l, NULL, NULL);
356     if (a == INVALID_SOCKET)
357         goto error;
358
359     closesocket (l);
360     //shutdown (a, 0);
361     //shutdown (c, 1);
362     fd[0] = c;
363     fd[1] = a;
364     return 0;
365
366 error:
367     if (l != INVALID_SOCKET)
368         closesocket (l);
369     if (c != INVALID_SOCKET)
370         closesocket (c);
371     return -1;
372 }
373
374 #undef  read
375 #define read( a, b, c )  recv (a, b, c, 0)
376 #undef  write
377 #define write( a, b, c ) send (a, b, c, 0)
378 #undef  close
379 #define close( a )       closesocket (a)
380 #endif /* WIN32 */
381
382 static vlc_mutex_t pipe_lock = VLC_STATIC_MUTEX;
383
384 /**
385  * Returns the readable end of a pipe that becomes readable once termination
386  * of the object is requested (vlc_object_kill()).
387  * This can be used to wake-up out of a select() or poll() event loop, such
388  * typically when doing network I/O.
389  *
390  * Note that the pipe will remain the same for the lifetime of the object.
391  * DO NOT read the pipe nor close it yourself. Ever.
392  *
393  * @param obj object that would be "killed"
394  * @return a readable pipe descriptor, or -1 on error.
395  */
396 int vlc_object_waitpipe( vlc_object_t *obj )
397 {
398     vlc_object_internals_t *internals = vlc_internals( obj );
399
400     vlc_mutex_lock (&pipe_lock);
401     if (internals->pipes[0] == -1)
402     {
403         /* This can only ever happen if someone killed us without locking: */
404         assert (internals->pipes[1] == -1);
405
406 #ifdef HAVE_EVENTFD
407         internals->pipes[0] = internals->pipes[1] = eventfd (0, 0);
408         if (internals->pipes[0] == -1)
409 #endif
410         {
411             if (pipe (internals->pipes))
412                 internals->pipes[0] = internals->pipes[1] = -1;
413         }
414
415         if (internals->pipes[0] != -1 && obj->b_die)
416         {   /* Race condition: vlc_object_kill() already invoked! */
417             msg_Dbg (obj, "waitpipe: object already dying");
418             write (internals->pipes[1], &(uint64_t){ 1 }, sizeof (uint64_t));
419         }
420     }
421     vlc_mutex_unlock (&pipe_lock);
422     return internals->pipes[0];
423 }
424
425
426 /**
427  * Requests termination of an object, cancels the object thread, and make the
428  * object wait pipe (if it exists) readable. Not a cancellation point.
429  */
430 void __vlc_object_kill( vlc_object_t *p_this )
431 {
432     vlc_object_internals_t *priv = vlc_internals( p_this );
433     int fd = -1;
434
435     vlc_thread_cancel( p_this );
436     vlc_mutex_lock( &pipe_lock );
437     if( !p_this->b_die )
438     {
439         fd = priv->pipes[1];
440         p_this->b_die = true;
441     }
442
443     /* This also serves as a memory barrier toward vlc_object_alive(): */
444     vlc_mutex_unlock( &pipe_lock );
445
446     if (fd != -1)
447     {
448         int canc = vlc_savecancel ();
449
450         /* write _after_ setting b_die, so vlc_object_alive() returns false */
451         write (fd, &(uint64_t){ 1 }, sizeof (uint64_t));
452         msg_Dbg (p_this, "waitpipe: object killed");
453         vlc_restorecancel (canc);
454     }
455 }
456
457
458 /*****************************************************************************
459  * find a typed object and increment its refcount
460  *****************************************************************************
461  * This function recursively looks for a given object type. i_mode can be one
462  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
463  *****************************************************************************/
464 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
465 {
466     vlc_object_t *p_found;
467
468     /* If we are of the requested type ourselves, don't look further */
469     if( !(i_mode & FIND_STRICT)
470      && vlc_internals (p_this)->i_object_type == i_type )
471     {
472         vlc_object_hold( p_this );
473         return p_this;
474     }
475
476     /* Otherwise, recursively look for the object */
477     if ((i_mode & 0x000f) == FIND_ANYWHERE)
478         return vlc_object_find (p_this->p_libvlc, i_type,
479                                 (i_mode & ~0x000f)|FIND_CHILD);
480
481     libvlc_lock (p_this->p_libvlc);
482     p_found = FindObject( p_this, i_type, i_mode );
483     libvlc_unlock (p_this->p_libvlc);
484     return p_found;
485 }
486
487
488 static int objnamecmp(const vlc_object_t *obj, const char *name)
489 {
490     char *objname = vlc_object_get_name(obj);
491     if (objname == NULL)
492         return INT_MIN;
493
494     int ret = strcmp (objname, name);
495     free (objname);
496     return ret;
497 }
498
499 #undef vlc_object_find_name
500 /**
501  * Finds a named object and increment its reference count.
502  * Beware that objects found in this manner can be "owned" by another thread,
503  * be of _any_ type, and be attached to any module (if any). With such an
504  * object reference, you can set or get object variables, emit log messages,
505  * and read write-once object parameters (psz_object_type, etc).
506  * You CANNOT cast the object to a more specific object type, and you
507  * definitely cannot invoke object type-specific callbacks with this.
508  *
509  * @param p_this object to search from
510  * @param psz_name name of the object to search for
511  * @param i_mode search direction: FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
512  *
513  * @return a matching object (must be released by the caller),
514  * or NULL on error.
515  */
516 vlc_object_t *vlc_object_find_name( vlc_object_t *p_this,
517                                     const char *psz_name, int i_mode )
518 {
519     vlc_object_t *p_found;
520
521     /* Reading psz_object_name from a separate inhibits thread-safety.
522      * Use a libvlc address variable instead for that sort of things! */
523     msg_Warn( p_this, "%s(%s) is not safe!", __func__, psz_name );
524     /* If have the requested name ourselves, don't look further */
525     if( !(i_mode & FIND_STRICT) && !objnamecmp(p_this, psz_name) )
526     {
527         vlc_object_hold( p_this );
528         return p_this;
529     }
530
531     libvlc_lock (p_this->p_libvlc);
532
533     /* Otherwise, recursively look for the object */
534     if( (i_mode & 0x000f) == FIND_ANYWHERE )
535     {
536         vlc_object_t *p_root = p_this;
537
538         /* Find the root */
539         while( p_root->p_parent != NULL &&
540                p_root != VLC_OBJECT( p_this->p_libvlc ) )
541         {
542             p_root = p_root->p_parent;
543         }
544
545         p_found = FindObjectName( p_root, psz_name,
546                                  (i_mode & ~0x000f)|FIND_CHILD );
547         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
548         {
549             p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
550                                       psz_name, (i_mode & ~0x000f)|FIND_CHILD );
551         }
552     }
553     else
554     {
555         p_found = FindObjectName( p_this, psz_name, i_mode );
556     }
557
558     libvlc_unlock (p_this->p_libvlc);
559     return p_found;
560 }
561
562 /**
563  * Increment an object reference counter.
564  */
565 void * __vlc_object_hold( vlc_object_t *p_this )
566 {
567     vlc_object_internals_t *internals = vlc_internals( p_this );
568
569     vlc_spin_lock( &internals->ref_spin );
570     /* Avoid obvious freed object uses */
571     assert( internals->i_refcount > 0 );
572     /* Increment the counter */
573     internals->i_refcount++;
574     vlc_spin_unlock( &internals->ref_spin );
575     return p_this;
576 }
577
578 /*****************************************************************************
579  * Decrement an object refcount
580  * And destroy the object if its refcount reach zero.
581  *****************************************************************************/
582 void __vlc_object_release( vlc_object_t *p_this )
583 {
584     vlc_object_internals_t *internals = vlc_internals( p_this );
585     vlc_object_t *parent = NULL;
586     bool b_should_destroy;
587
588     vlc_spin_lock( &internals->ref_spin );
589     assert( internals->i_refcount > 0 );
590
591     if( internals->i_refcount > 1 )
592     {
593         /* Fast path */
594         /* There are still other references to the object */
595         internals->i_refcount--;
596         vlc_spin_unlock( &internals->ref_spin );
597         return;
598     }
599     vlc_spin_unlock( &internals->ref_spin );
600
601     /* Slow path */
602     /* Remember that we cannot hold the spin while waiting on the mutex */
603     libvlc_lock (p_this->p_libvlc);
604     /* Take the spin again. Note that another thread may have held the
605      * object in the (very short) mean time. */
606     vlc_spin_lock( &internals->ref_spin );
607     b_should_destroy = --internals->i_refcount == 0;
608     vlc_spin_unlock( &internals->ref_spin );
609
610     if( b_should_destroy )
611     {
612         parent = p_this->p_parent;
613
614 #ifndef NDEBUG
615         if( VLC_OBJECT(p_this->p_libvlc) == p_this )
616         {
617             /* Test for leaks */
618             vlc_object_t *leaked = internals->next;
619             while( leaked != p_this )
620             {
621                 /* We are leaking this object */
622                 fprintf( stderr,
623                          "ERROR: leaking object (%p, type:%s)\n",
624                          leaked, leaked->psz_object_type );
625                 /* Dump object to ease debugging */
626                 vlc_object_dump( leaked );
627                 fflush(stderr);
628                 leaked = vlc_internals (leaked)->next;
629             }
630
631             if( internals->next != p_this )
632                 /* Dump libvlc object to ease debugging */
633                 vlc_object_dump( p_this );
634         }
635 #endif
636         /* Remove the object from object list
637          * so that it cannot be encountered by vlc_object_get() */
638         vlc_internals (internals->next)->prev = internals->prev;
639         vlc_internals (internals->prev)->next = internals->next;
640
641         if (parent)
642             /* Detach from parent to protect against FIND_CHILDREN */
643             vlc_object_detach_unlocked (p_this);
644
645         /* We have no children */
646         assert (internals->i_children == 0);
647     }
648     libvlc_unlock (p_this->p_libvlc);
649
650     if( b_should_destroy )
651     {
652         int canc;
653
654         canc = vlc_savecancel ();
655         vlc_object_destroy( p_this );
656         vlc_restorecancel (canc);
657         if (parent)
658             vlc_object_release (parent);
659     }
660 }
661
662 /**
663  ****************************************************************************
664  * attach object to a parent object
665  *****************************************************************************
666  * This function sets p_this as a child of p_parent, and p_parent as a parent
667  * of p_this. This link can be undone using vlc_object_detach.
668  *****************************************************************************/
669 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
670 {
671     if( !p_this ) return;
672
673     vlc_object_hold (p_parent);
674     libvlc_lock (p_this->p_libvlc);
675
676     /* Attach the parent to its child */
677     assert (!p_this->p_parent);
678     p_this->p_parent = p_parent;
679
680     /* Attach the child to its parent */
681     vlc_object_internals_t *priv = vlc_internals( p_parent );
682     INSERT_ELEM( priv->pp_children, priv->i_children, priv->i_children,
683                  p_this );
684     libvlc_unlock (p_this->p_libvlc);
685 }
686
687
688 static void vlc_object_detach_unlocked (vlc_object_t *p_this)
689 {
690     if (p_this->p_parent == NULL)
691         return;
692
693     vlc_object_internals_t *priv = vlc_internals( p_this->p_parent );
694
695     int i_index, i;
696
697     /* Remove p_this's parent */
698     p_this->p_parent = NULL;
699
700     /* Remove all of p_parent's children which are p_this */
701     for( i_index = priv->i_children ; i_index-- ; )
702     {
703         if( priv->pp_children[i_index] == p_this )
704         {
705             priv->i_children--;
706             for( i = i_index ; i < priv->i_children ; i++ )
707                 priv->pp_children[i] = priv->pp_children[i+1];
708         }
709     }
710
711     if( priv->i_children )
712     {
713         vlc_object_t **pp_children = (vlc_object_t **)
714             realloc( priv->pp_children,
715                      priv->i_children * sizeof(vlc_object_t *) );
716         if( pp_children )
717             priv->pp_children = pp_children;
718     }
719     else
720     {
721         /* Special case - don't realloc() to zero to avoid leaking */
722         free( priv->pp_children );
723         priv->pp_children = NULL;
724     }
725 }
726
727
728 /**
729  ****************************************************************************
730  * detach object from its parent
731  *****************************************************************************
732  * This function removes all links between an object and its parent.
733  *****************************************************************************/
734 void __vlc_object_detach( vlc_object_t *p_this )
735 {
736     vlc_object_t *p_parent;
737     if( !p_this ) return;
738
739     libvlc_lock (p_this->p_libvlc);
740     p_parent = p_this->p_parent;
741     if (p_parent)
742         vlc_object_detach_unlocked( p_this );
743     libvlc_unlock (p_this->p_libvlc);
744
745     if (p_parent)
746         vlc_object_release (p_parent);
747 }
748
749
750 /**
751  ****************************************************************************
752  * find a list typed objects and increment their refcount
753  *****************************************************************************
754  * This function recursively looks for a given object type. i_mode can be one
755  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
756  *****************************************************************************/
757 vlc_list_t * vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
758 {
759     vlc_list_t *p_list;
760     int i_count = 0;
761
762     /* Look for the objects */
763     switch( i_mode & 0x000f )
764     {
765     case FIND_ANYWHERE:
766         return vlc_list_find (VLC_OBJECT(p_this->p_libvlc), i_type, FIND_CHILD);
767
768     case FIND_CHILD:
769         libvlc_lock (p_this->p_libvlc);
770         i_count = CountChildren( p_this, i_type );
771         p_list = NewList( i_count );
772
773         /* Check allocation was successful */
774         if( p_list->i_count != i_count )
775         {
776             libvlc_unlock (p_this->p_libvlc);
777             p_list->i_count = 0;
778             break;
779         }
780
781         p_list->i_count = 0;
782         ListChildren( p_list, p_this, i_type );
783         libvlc_unlock (p_this->p_libvlc);
784         break;
785
786     default:
787         msg_Err( p_this, "unimplemented!" );
788         p_list = NewList( 0 );
789         break;
790     }
791
792     return p_list;
793 }
794
795 /**
796  * Gets the list of children of an objects, and increment their reference
797  * count.
798  * @return a list (possibly empty) or NULL in case of error.
799  */
800 vlc_list_t *__vlc_list_children( vlc_object_t *obj )
801 {
802     vlc_list_t *l;
803     vlc_object_internals_t *priv = vlc_internals( obj );
804
805     libvlc_lock (obj->p_libvlc);
806     l = NewList( priv->i_children );
807     for (int i = 0; i < l->i_count; i++)
808     {
809         vlc_object_hold( priv->pp_children[i] );
810         l->p_values[i].p_object = priv->pp_children[i];
811     }
812     libvlc_unlock (obj->p_libvlc);
813     return l;
814 }
815
816 /*****************************************************************************
817  * DumpCommand: print the current vlc structure
818  *****************************************************************************
819  * This function prints either an ASCII tree showing the connections between
820  * vlc objects, and additional information such as their refcount, thread ID,
821  * etc. (command "tree"), or the same data as a simple list (command "list").
822  *****************************************************************************/
823 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
824                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
825 {
826     libvlc_int_t *p_libvlc = p_this->p_libvlc;
827
828     (void)oldval; (void)p_data;
829     if( *psz_cmd == 'l' )
830     {
831         vlc_object_t *cur = VLC_OBJECT (p_libvlc);
832
833         libvlc_lock (p_this->p_libvlc);
834         do
835         {
836             PrintObject (cur, "");
837             cur = vlc_internals (cur)->next;
838         }
839         while (cur != VLC_OBJECT(p_libvlc));
840         libvlc_unlock (p_this->p_libvlc);
841     }
842     else
843     {
844         vlc_object_t *p_object = NULL;
845
846         if( *newval.psz_string )
847         {
848             /* try using the object's name to find it */
849             p_object = vlc_object_find_name( p_this, newval.psz_string,
850                                              FIND_ANYWHERE );
851             if( !p_object )
852             {
853                 return VLC_ENOOBJ;
854             }
855         }
856
857         libvlc_lock (p_this->p_libvlc);
858         if( *psz_cmd == 't' )
859         {
860             char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
861
862             if( !p_object )
863                 p_object = VLC_OBJECT(p_this->p_libvlc);
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( !vlc_internals( p_object )->i_vars )
878                 printf( " `-o No variables\n" );
879             for( i = 0; i < vlc_internals( p_object )->i_vars; i++ )
880             {
881                 variable_t *p_var = vlc_internals( 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 == vlc_internals( 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_HASCHOICE )
913                     printf( ", has choices" );
914                 if( p_var->i_type & VLC_VAR_ISCOMMAND )
915                     printf( ", command" );
916                 if( p_var->i_entries )
917                     printf( ", %d callbacks", p_var->i_entries );
918                 switch( p_var->i_type & VLC_VAR_CLASS )
919                 {
920                     case VLC_VAR_VOID:
921                     case VLC_VAR_MUTEX:
922                         break;
923                     case VLC_VAR_BOOL:
924                         printf( ": %s", p_var->val.b_bool ? "true" : "false" );
925                         break;
926                     case VLC_VAR_INTEGER:
927                         printf( ": %d", p_var->val.i_int );
928                         break;
929                     case VLC_VAR_STRING:
930                         printf( ": \"%s\"", p_var->val.psz_string );
931                         break;
932                     case VLC_VAR_FLOAT:
933                         printf( ": %f", p_var->val.f_float );
934                         break;
935                     case VLC_VAR_TIME:
936                         printf( ": %"PRIi64, (int64_t)p_var->val.i_time );
937                         break;
938                     case VLC_VAR_ADDRESS:
939                         printf( ": %p", p_var->val.p_address );
940                         break;
941                     case VLC_VAR_LIST:
942                         printf( ": TODO" );
943                         break;
944                 }
945                 printf( "\n" );
946             }
947         }
948         libvlc_unlock (p_this->p_libvlc);
949
950         if( *newval.psz_string )
951         {
952             vlc_object_release( p_object );
953         }
954     }
955
956     return VLC_SUCCESS;
957 }
958
959 /*****************************************************************************
960  * vlc_list_release: free a list previously allocated by vlc_list_find
961  *****************************************************************************
962  * This function decreases the refcount of all objects in the list and
963  * frees the list.
964  *****************************************************************************/
965 void vlc_list_release( vlc_list_t *p_list )
966 {
967     int i_index;
968
969     for( i_index = 0; i_index < p_list->i_count; i_index++ )
970     {
971         vlc_object_release( p_list->p_values[i_index].p_object );
972     }
973
974     free( p_list->p_values );
975     free( p_list );
976 }
977
978 /*****************************************************************************
979  * dump an object. (Debug function)
980  *****************************************************************************/
981 #ifndef NDEBUG
982 static void vlc_object_dump( vlc_object_t *p_this )
983 {
984     char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
985     psz_foo[0] = '|';
986
987     DumpStructure( p_this, 0, psz_foo );
988 }
989 #endif
990
991 /* Following functions are local */
992
993 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
994 {
995     int i;
996     vlc_object_t *p_tmp;
997
998     switch( i_mode & 0x000f )
999     {
1000     case FIND_PARENT:
1001         p_tmp = p_this->p_parent;
1002         if( p_tmp )
1003         {
1004             if( vlc_internals( p_tmp )->i_object_type == i_type )
1005             {
1006                 vlc_object_hold( p_tmp );
1007                 return p_tmp;
1008             }
1009             else
1010             {
1011                 return FindObject( p_tmp, i_type, i_mode );
1012             }
1013         }
1014         break;
1015
1016     case FIND_CHILD:
1017         for( i = vlc_internals( p_this )->i_children; i--; )
1018         {
1019             p_tmp = vlc_internals( p_this )->pp_children[i];
1020             if( vlc_internals( p_tmp )->i_object_type == i_type )
1021             {
1022                 vlc_object_hold( p_tmp );
1023                 return p_tmp;
1024             }
1025             else if( vlc_internals( p_tmp )->i_children )
1026             {
1027                 p_tmp = FindObject( p_tmp, i_type, i_mode );
1028                 if( p_tmp )
1029                 {
1030                     return p_tmp;
1031                 }
1032             }
1033         }
1034         break;
1035
1036     case FIND_ANYWHERE:
1037         /* Handled in vlc_object_find */
1038         break;
1039     }
1040
1041     return NULL;
1042 }
1043
1044 static vlc_object_t * FindObjectName( vlc_object_t *p_this,
1045                                       const char *psz_name,
1046                                       int i_mode )
1047 {
1048     int i;
1049     vlc_object_t *p_tmp;
1050
1051     switch( i_mode & 0x000f )
1052     {
1053     case FIND_PARENT:
1054         p_tmp = p_this->p_parent;
1055         if( p_tmp )
1056         {
1057             if( !objnamecmp(p_tmp, psz_name) )
1058             {
1059                 vlc_object_hold( p_tmp );
1060                 return p_tmp;
1061             }
1062             else
1063             {
1064                 return FindObjectName( p_tmp, psz_name, i_mode );
1065             }
1066         }
1067         break;
1068
1069     case FIND_CHILD:
1070         for( i = vlc_internals( p_this )->i_children; i--; )
1071         {
1072             p_tmp = vlc_internals( p_this )->pp_children[i];
1073             if( !objnamecmp(p_tmp, psz_name ) )
1074             {
1075                 vlc_object_hold( p_tmp );
1076                 return p_tmp;
1077             }
1078             else if( vlc_internals( p_tmp )->i_children )
1079             {
1080                 p_tmp = FindObjectName( p_tmp, psz_name, i_mode );
1081                 if( p_tmp )
1082                 {
1083                     return p_tmp;
1084                 }
1085             }
1086         }
1087         break;
1088
1089     case FIND_ANYWHERE:
1090         /* Handled in vlc_object_find */
1091         break;
1092     }
1093
1094     return NULL;
1095 }
1096
1097
1098 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
1099 {
1100     char psz_children[20], psz_refcount[20], psz_thread[30], psz_name[50],
1101          psz_parent[20];
1102
1103     int canc = vlc_savecancel ();
1104     memset( &psz_name, 0, sizeof(psz_name) );
1105     char *name = vlc_object_get_name(p_this);
1106     if( name )
1107     {
1108         snprintf( psz_name, 49, " \"%s\"", name );
1109         free( name );
1110         if( psz_name[48] )
1111             psz_name[48] = '\"';
1112     }
1113
1114     psz_children[0] = '\0';
1115     switch( vlc_internals( p_this )->i_children )
1116     {
1117         case 0:
1118             break;
1119         case 1:
1120             strcpy( psz_children, ", 1 child" );
1121             break;
1122         default:
1123             snprintf( psz_children, 19, ", %i children",
1124                       vlc_internals( p_this )->i_children );
1125             break;
1126     }
1127
1128     psz_refcount[0] = '\0';
1129     if( vlc_internals( p_this )->i_refcount > 0 )
1130         snprintf( psz_refcount, 19, ", refcount %u",
1131                   vlc_internals( p_this )->i_refcount );
1132
1133     psz_thread[0] = '\0';
1134     if( vlc_internals( p_this )->b_thread )
1135         snprintf( psz_thread, 29, " (thread %lu)",
1136                   (unsigned long)vlc_internals( p_this )->thread_id );
1137
1138     psz_parent[0] = '\0';
1139     if( p_this->p_parent )
1140         snprintf( psz_parent, 19, ", parent %p", p_this->p_parent );
1141
1142     printf( " %so %p %s%s%s%s%s%s\n", psz_prefix,
1143             p_this, p_this->psz_object_type,
1144             psz_name, psz_thread, psz_refcount, psz_children,
1145             psz_parent );
1146     vlc_restorecancel (canc);
1147 }
1148
1149 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
1150 {
1151     int i;
1152     char i_back = psz_foo[i_level];
1153     psz_foo[i_level] = '\0';
1154
1155     PrintObject( p_this, psz_foo );
1156
1157     psz_foo[i_level] = i_back;
1158
1159     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
1160     {
1161         msg_Warn( p_this, "structure tree is too deep" );
1162         return;
1163     }
1164
1165     for( i = 0 ; i < vlc_internals( p_this )->i_children ; i++ )
1166     {
1167         if( i_level )
1168         {
1169             psz_foo[i_level-1] = ' ';
1170
1171             if( psz_foo[i_level-2] == '`' )
1172             {
1173                 psz_foo[i_level-2] = ' ';
1174             }
1175         }
1176
1177         if( i == vlc_internals( p_this )->i_children - 1 )
1178         {
1179             psz_foo[i_level] = '`';
1180         }
1181         else
1182         {
1183             psz_foo[i_level] = '|';
1184         }
1185
1186         psz_foo[i_level+1] = '-';
1187         psz_foo[i_level+2] = '\0';
1188
1189         DumpStructure( vlc_internals( p_this )->pp_children[i], i_level + 2,
1190                        psz_foo );
1191     }
1192 }
1193
1194 static vlc_list_t * NewList( int i_count )
1195 {
1196     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
1197     if( p_list == NULL )
1198     {
1199         return NULL;
1200     }
1201
1202     p_list->i_count = i_count;
1203
1204     if( i_count == 0 )
1205     {
1206         p_list->p_values = NULL;
1207         return p_list;
1208     }
1209
1210     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
1211     if( p_list->p_values == NULL )
1212     {
1213         p_list->i_count = 0;
1214         return p_list;
1215     }
1216
1217     return p_list;
1218 }
1219
1220 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
1221                          int i_index )
1222 {
1223     if( p_list == NULL || i_index >= p_list->i_count )
1224     {
1225         return;
1226     }
1227
1228     vlc_object_hold( p_object );
1229
1230     p_list->p_values[i_index].p_object = p_object;
1231
1232     return;
1233 }
1234
1235 /*static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
1236 {
1237     if( p_list == NULL )
1238     {
1239         return;
1240     }
1241
1242     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1243                                 * sizeof( vlc_value_t ) );
1244     if( p_list->p_values == NULL )
1245     {
1246         p_list->i_count = 0;
1247         return;
1248     }
1249
1250     vlc_object_hold( p_object );
1251
1252     p_list->p_values[p_list->i_count].p_object = p_object;
1253     p_list->i_count++;
1254
1255     return;
1256 }*/
1257
1258 static int CountChildren( vlc_object_t *p_this, int i_type )
1259 {
1260     vlc_object_t *p_tmp;
1261     int i, i_count = 0;
1262
1263     for( i = 0; i < vlc_internals( p_this )->i_children; i++ )
1264     {
1265         p_tmp = vlc_internals( p_this )->pp_children[i];
1266
1267         if( vlc_internals( p_tmp )->i_object_type == i_type )
1268         {
1269             i_count++;
1270         }
1271         i_count += CountChildren( p_tmp, i_type );
1272     }
1273
1274     return i_count;
1275 }
1276
1277 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1278 {
1279     vlc_object_t *p_tmp;
1280     int i;
1281
1282     for( i = 0; i < vlc_internals( p_this )->i_children; i++ )
1283     {
1284         p_tmp = vlc_internals( p_this )->pp_children[i];
1285
1286         if( vlc_internals( p_tmp )->i_object_type == i_type )
1287             ListReplace( p_list, p_tmp, p_list->i_count++ );
1288
1289         ListChildren( p_list, p_tmp, i_type );
1290     }
1291 }