objects.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:37k
源码类别:

midi

开发平台:

Unix_Linux

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