+static vlc_mutex_t structure_lock;
+
+void *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
+ int i_type, const char *psz_type )
+{
+ vlc_object_t *p_new;
+ vlc_object_internals_t *p_priv;
+
+ /* NOTE:
+ * VLC objects are laid out as follow:
+ * - first the LibVLC-private per-object data,
+ * - then VLC_COMMON members from vlc_object_t,
+ * - finally, the type-specific data (if any).
+ *
+ * This function initializes the LibVLC and common data,
+ * and zeroes the rest.
+ */
+ p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
+ if( p_priv == NULL )
+ return NULL;
+
+ assert (i_size >= sizeof (vlc_object_t));
+ p_new = (vlc_object_t *)(p_priv + 1);
+
+ p_new->i_object_type = i_type;
+ p_new->psz_object_type = psz_type;
+ p_new->psz_object_name = NULL;
+
+ p_new->b_die = false;
+ p_new->b_error = false;
+ p_new->b_dead = false;
+ p_new->b_force = false;
+
+ p_new->psz_header = NULL;
+
+ if (p_this)
+ p_new->i_flags = p_this->i_flags
+ & (OBJECT_FLAGS_NODBG|OBJECT_FLAGS_QUIET|OBJECT_FLAGS_NOINTERACT);
+
+ p_priv->p_vars = calloc( sizeof( variable_t ), 16 );
+
+ if( !p_priv->p_vars )
+ {
+ free( p_priv );
+ return NULL;
+ }
+
+ libvlc_global_data_t *p_libvlc_global;
+ if( p_this == NULL )
+ {
+ /* Only the global root object is created out of the blue */
+ p_libvlc_global = (libvlc_global_data_t *)p_new;
+ p_new->p_libvlc = NULL;
+
+ p_libvlc_global->i_counter = 0;
+ p_priv->next = p_priv->prev = p_new;
+ vlc_mutex_init( &structure_lock );
+#ifdef LIBVLC_REFCHECK
+ /* TODO: use the destruction callback to track ref leaks */
+ vlc_threadvar_create( &held_objects, held_objects_destroy );
+#endif
+ }
+ else
+ {
+ p_libvlc_global = vlc_global();
+ if( i_type == VLC_OBJECT_LIBVLC )
+ p_new->p_libvlc = (libvlc_int_t*)p_new;
+ else
+ p_new->p_libvlc = p_this->p_libvlc;
+ }
+
+ vlc_spin_init( &p_priv->ref_spin );
+ p_priv->i_refcount = 1;
+ p_priv->pf_destructor = NULL;
+ p_priv->b_thread = false;
+ p_new->p_parent = NULL;
+ p_priv->pp_children = NULL;
+ p_priv->i_children = 0;
+
+ p_new->p_private = NULL;
+
+ /* Initialize mutexes and condvars */
+ vlc_mutex_init( &p_priv->lock );
+ vlc_cond_init( p_new, &p_priv->wait );
+ vlc_mutex_init( &p_priv->var_lock );
+ vlc_spin_init( &p_priv->spin );
+ p_priv->pipes[0] = p_priv->pipes[1] = -1;
+
+ p_priv->next = VLC_OBJECT (p_libvlc_global);
+#if !defined (LIBVLC_REFCHECK)
+ /* ... */
+#elif defined (LIBVLC_USE_PTHREAD)
+ p_priv->creator_id = pthread_self ();
+#elif defined (WIN32)
+ p_priv->creator_id = GetCurrentThreadId ();
+#endif
+ vlc_mutex_lock( &structure_lock );
+ p_priv->prev = vlc_internals (p_libvlc_global)->prev;
+ vlc_internals (p_libvlc_global)->prev = p_new;
+ vlc_internals (p_priv->prev)->next = p_new;
+ p_new->i_object_id = p_libvlc_global->i_counter++;
+ vlc_mutex_unlock( &structure_lock );
+
+ if( i_type == VLC_OBJECT_LIBVLC )
+ {
+ var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
+ var_AddCallback( p_new, "list", DumpCommand, NULL );
+ var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
+ var_AddCallback( p_new, "tree", DumpCommand, NULL );
+ var_Create( p_new, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
+ var_AddCallback( p_new, "vars", DumpCommand, NULL );
+ }
+
+ return p_new;
+}