void var_DestroyAll( vlc_object_t *obj ) { vlc_object_internals_t *priv = vlc_internals( obj ); tdestroy( priv->var_root, CleanupVar ); priv->var_root = NULL; }
int var_GetChecked( vlc_object_t *p_this, const char *psz_name, int expected_type, vlc_value_t *p_val ) { assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); variable_t *p_var; int err = VLC_SUCCESS; vlc_mutex_lock( &p_priv->var_lock ); p_var = Lookup( p_this, psz_name ); if( p_var != NULL ) { assert( expected_type == 0 || (p_var->i_type & VLC_VAR_CLASS) == expected_type ); assert ((p_var->i_type & VLC_VAR_CLASS) != VLC_VAR_VOID); /* Really get the variable */ *p_val = p_var->val; /* Duplicate value if needed */ p_var->ops->pf_dup( p_val ); } else err = VLC_ENOVAR; vlc_mutex_unlock( &p_priv->var_lock ); return err; }
/** * Register a callback in a variable * * We store a function pointer that will be called upon variable * modification. * * \param p_this The object that holds the variable * \param psz_name The name of the variable * \param pf_callback The function pointer * \param p_data A generic pointer that will be passed as the last * argument to the callback function. * * \warning The callback function is run in the thread that calls var_Set on * the variable. Use proper locking. This thread may not have much * time to spare, so keep callback functions short. */ int var_AddCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ) { variable_t *p_var; callback_entry_t entry; assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); entry.pf_callback = pf_callback; entry.p_data = p_data; vlc_mutex_lock( &p_priv->var_lock ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); msg_Err( p_this, "cannot add callback %p to nonexistent " "variable '%s'", pf_callback, psz_name ); return VLC_ENOVAR; } WaitUnused( p_this, p_var ); INSERT_ELEM( p_var->p_entries, p_var->i_entries, p_var->i_entries, entry ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS; }
static void AddCallback( vlc_object_t *p_this, const char *psz_name, callback_entry_t entry, vlc_callback_type_t i_type ) { variable_t *p_var; assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); msg_Err( p_this, "cannot add callback %p to nonexistent variable '%s'", entry.p_callback, psz_name ); return; } WaitUnused( p_this, p_var ); callback_table_t *p_table; if (i_type == vlc_value_callback) p_table = &p_var->value_callbacks; else p_table = &p_var->list_callbacks; TAB_APPEND(p_table->i_entries, p_table->p_entries, entry); vlc_mutex_unlock( &p_priv->var_lock ); }
/** * Perform a Get and Set on a variable * * \param p_this: The object that hold the variable * \param psz_name: the name of the variable * \param i_action: the action to perform * \param p_val: The action parameter * \return vlc error codes */ int var_GetAndSet( vlc_object_t *p_this, const char *psz_name, int i_action, vlc_value_t *p_val ) { variable_t *p_var; vlc_value_t oldval; assert( p_this ); assert( p_val ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } WaitUnused( p_this, p_var ); /* Duplicated data if needed */ //p_var->ops->pf_dup( &val ); /* Backup needed stuff */ oldval = p_var->val; /* depending of the action requiered */ switch( i_action ) { case VLC_VAR_BOOL_TOGGLE: assert( ( p_var->i_type & VLC_VAR_BOOL ) == VLC_VAR_BOOL ); p_var->val.b_bool = !p_var->val.b_bool; break; case VLC_VAR_INTEGER_ADD: assert( ( p_var->i_type & VLC_VAR_INTEGER ) == VLC_VAR_INTEGER ); p_var->val.i_int += p_val->i_int; break; case VLC_VAR_INTEGER_OR: assert( ( p_var->i_type & VLC_VAR_INTEGER ) == VLC_VAR_INTEGER ); p_var->val.i_int |= p_val->i_int; break; case VLC_VAR_INTEGER_NAND: assert( ( p_var->i_type & VLC_VAR_INTEGER ) == VLC_VAR_INTEGER ); p_var->val.i_int &= ~p_val->i_int; break; default: vlc_mutex_unlock( &p_priv->var_lock ); return VLC_EGENERIC; } /* Check boundaries */ CheckValue( p_var, &p_var->val ); *p_val = p_var->val; /* Deal with callbacks.*/ TriggerCallback( p_this, p_var, psz_name, oldval ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS; }
/** * Destroy a vlc variable * * Look for the variable and destroy it if it is found. As in var_Create we * do a call to memmove() but we have performance counterparts elsewhere. * * \param p_this The object that holds the variable * \param psz_name The name of the variable */ void (var_Destroy)(vlc_object_t *p_this, const char *psz_name) { variable_t *p_var; assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) msg_Dbg( p_this, "attempt to destroy nonexistent variable \"%s\"", psz_name ); else if( --p_var->i_usage == 0 ) { assert(!p_var->b_incallback); tdelete( p_var, &p_priv->var_root, varcmp ); } else { assert(p_var->i_usage != -1u); p_var = NULL; } vlc_mutex_unlock( &p_priv->var_lock ); if( p_var != NULL ) Destroy( p_var ); }
int var_GetChecked( vlc_object_t *p_this, const char *psz_name, int expected_type, vlc_value_t *p_val ) { assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); variable_t *p_var; int err = VLC_SUCCESS; vlc_mutex_lock( &p_priv->var_lock ); p_var = Lookup( p_this, psz_name ); if( p_var != NULL ) { assert( expected_type == 0 || (p_var->i_type & VLC_VAR_CLASS) == expected_type ); /* Really get the variable */ *p_val = p_var->val; #ifndef NDEBUG /* Alert if the type is VLC_VAR_VOID */ if( ( p_var->i_type & VLC_VAR_TYPE ) == VLC_VAR_VOID ) msg_Warn( p_this, "Calling var_Get on the void variable '%s' (0x%04x)", psz_name, p_var->i_type ); #endif /* Duplicate value if needed */ p_var->ops->pf_dup( p_val ); } else err = VLC_ENOVAR; vlc_mutex_unlock( &p_priv->var_lock ); return err; }
/** * Trigger callback on a variable * * \param p_this The object that hold the variable * \param psz_name The name of the variable */ int var_TriggerCallback( vlc_object_t *p_this, const char *psz_name ) { int i_ret; variable_t *p_var; assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); vlc_mutex_lock( &p_priv->var_lock ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } WaitUnused( p_this, p_var ); /* Deal with callbacks. Tell we're in a callback, release the lock, * call stored functions, retake the lock. */ i_ret = TriggerCallback( p_this, p_var, psz_name, p_var->val ); vlc_mutex_unlock( &p_priv->var_lock ); return i_ret; }
void vlc_thread_cancel (vlc_object_t *obj) { vlc_object_internals_t *priv = vlc_internals (obj); if (priv->b_thread) vlc_cancel (priv->thread_id); }
/** * Destroy a vlc variable * * Look for the variable and destroy it if it is found. As in var_Create we * do a call to memmove() but we have performance counterparts elsewhere. * * \param p_this The object that holds the variable * \param psz_name The name of the variable */ int var_Destroy( vlc_object_t *p_this, const char *psz_name ) { variable_t *p_var; assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); vlc_mutex_lock( &p_priv->var_lock ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } WaitUnused( p_this, p_var ); if( --p_var->i_usage == 0 ) tdelete( p_var, &p_priv->var_root, varcmp ); else p_var = NULL; vlc_mutex_unlock( &p_priv->var_lock ); if( p_var != NULL ) Destroy( p_var ); return VLC_SUCCESS; }
/***************************************************************************** * vlc_thread_create: create a thread ***************************************************************************** * Note that i_priority is only taken into account on platforms supporting * userland real-time priority threads. *****************************************************************************/ int vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line, const char *psz_name, void *(*func) ( vlc_object_t * ), int i_priority ) { int i_ret; vlc_object_internals_t *p_priv = vlc_internals( p_this ); struct vlc_thread_boot *boot = malloc (sizeof (*boot)); if (boot == NULL) return errno; boot->entry = func; boot->object = p_this; /* Make sure we don't re-create a thread if the object has already one */ assert( !p_priv->b_thread ); p_priv->b_thread = true; i_ret = vlc_clone( &p_priv->thread_id, thread_entry, boot, i_priority ); if( i_ret == 0 ) msg_Dbg( p_this, "thread (%s) created at priority %d (%s:%d)", psz_name, i_priority, psz_file, i_line ); else { p_priv->b_thread = false; errno = i_ret; msg_Err( p_this, "%s thread could not be created at %s:%d (%m)", psz_name, psz_file, i_line ); } return i_ret; }
/********************************************************************** * Trigger the callbacks. * Tell we're in a callback, release the lock, call stored functions, * retake the lock. **********************************************************************/ static int TriggerCallback( vlc_object_t *p_this, variable_t *p_var, const char *psz_name, vlc_value_t oldval ) { assert( p_this ); int i_entries = p_var->i_entries; if( i_entries == 0 ) return VLC_SUCCESS; callback_entry_t *p_entries = p_var->p_entries; vlc_object_internals_t *p_priv = vlc_internals( p_this ); assert( !p_var->b_incallback ); p_var->b_incallback = true; vlc_mutex_unlock( &p_priv->var_lock ); /* The real calls */ for( ; i_entries-- ; ) { p_entries[i_entries].pf_callback( p_this, psz_name, oldval, p_var->val, p_entries[i_entries].p_data ); } vlc_mutex_lock( &p_priv->var_lock ); p_var->b_incallback = false; vlc_cond_broadcast( &p_priv->var_wait ); return VLC_SUCCESS; }
/***************************************************************************** * vlc_thread_set_priority: set the priority of the current thread when we * couldn't set it in vlc_thread_create (for instance for the main thread) *****************************************************************************/ int vlc_thread_set_priority( vlc_object_t *p_this, const char * psz_file, int i_line, int i_priority ) { vlc_object_internals_t *p_priv = vlc_internals( p_this ); if( !p_priv->b_thread ) { msg_Err( p_this, "couldn't set priority of non-existent thread" ); return ESRCH; } #if defined( LIBVLC_USE_PTHREAD ) # ifndef __APPLE__ if( var_InheritBool( p_this, "rt-priority" ) ) # endif { int i_error, i_policy; struct sched_param param; memset( ¶m, 0, sizeof(struct sched_param) ); if( config_GetType( p_this, "rt-offset" ) ) i_priority += var_InheritInteger( p_this, "rt-offset" ); if( i_priority <= 0 ) { param.sched_priority = (-1) * i_priority; i_policy = SCHED_OTHER; } else { param.sched_priority = i_priority; i_policy = SCHED_RR; } if( (i_error = pthread_setschedparam( p_priv->thread_id, i_policy, ¶m )) ) { errno = i_error; msg_Warn( p_this, "couldn't set thread priority (%s:%d): %m", psz_file, i_line ); i_priority = 0; } } #elif defined( WIN32 ) || defined( UNDER_CE ) VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); #ifndef UNDER_CE if( !SetThreadPriority(p_priv->thread_id, i_priority) ) #else if( !SetThreadPriority(p_priv->thread_id->handle, i_priority) ) #endif { msg_Warn( p_this, "couldn't set a faster priority" ); return 1; } #endif return 0; }
static void DelCallback( vlc_object_t *p_this, const char *psz_name, callback_entry_t entry, vlc_callback_type_t i_type ) { int i_entry; variable_t *p_var; #ifndef NDEBUG bool b_found_similar = false; #endif assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); msg_Err( p_this, "cannot delete callback %p from nonexistent " "variable '%s'", entry.p_callback, psz_name ); return; } WaitUnused( p_this, p_var ); callback_table_t *p_table; if (i_type == vlc_value_callback) p_table = &p_var->value_callbacks; else p_table = &p_var->list_callbacks; for( i_entry = p_table->i_entries ; i_entry-- ; ) { if( p_table->p_entries[i_entry].p_callback == entry.p_callback && p_table->p_entries[i_entry].p_data == entry.p_data ) { break; } #ifndef NDEBUG else if( p_table->p_entries[i_entry].p_callback == entry.p_callback ) b_found_similar = true; #endif } if( i_entry < 0 ) { #ifndef NDEBUG if( b_found_similar ) fprintf( stderr, "Calling var_DelCallback for '%s' with the same " "function but not the same data.", psz_name ); vlc_assert_unreachable(); #endif vlc_mutex_unlock( &p_priv->var_lock ); return; } TAB_ERASE(p_table->i_entries, p_table->p_entries, i_entry); vlc_mutex_unlock( &p_priv->var_lock ); }
static vlc_object_t *ObjectExists (vlc_object_t *root, void *obj) { if (root == obj) return vlc_object_hold (root); vlc_object_internals_t *priv = vlc_internals(root); vlc_object_t *ret = NULL; /* NOTE: nested locking here (due to recursive call) */ vlc_mutex_lock (&vlc_internals(root)->tree_lock); for (priv = priv->first; priv != NULL && ret == NULL; priv = priv->next) ret = ObjectExists (vlc_externals (priv), obj); vlc_mutex_unlock (&vlc_internals(root)->tree_lock); return ret; }
/** * Destroy everything. * This function requests the running threads to finish, waits for their * termination, and destroys their structure. * It stops the thread systems: no instance can run after this has run * \param p_libvlc the instance to destroy */ void libvlc_InternalDestroy( libvlc_int_t *p_libvlc ) { libvlc_priv_t *priv = libvlc_priv( p_libvlc ); /* Destroy mutexes */ vlc_ExitDestroy( &priv->exit ); vlc_mutex_destroy( &priv->ml_lock ); #ifndef NDEBUG /* Hack to dump leaked objects tree */ if( vlc_internals( p_libvlc )->i_refcount > 1 ) while( vlc_internals( p_libvlc )->i_refcount > 0 ) vlc_object_release( p_libvlc ); #endif assert( vlc_internals( p_libvlc )->i_refcount == 1 ); vlc_object_release( p_libvlc ); }
/***************************************************************************** * find a typed object and increment its refcount ***************************************************************************** * This function recursively looks for a given object type. i_mode can be one * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE. *****************************************************************************/ void * vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode ) { vlc_object_t *p_found; /* If we are of the requested type ourselves, don't look further */ if( vlc_internals (p_this)->i_object_type == i_type ) { vlc_object_hold( p_this ); return p_this; } /* Otherwise, recursively look for the object */ if (i_mode == FIND_ANYWHERE) return vlc_object_find (VLC_OBJECT(p_this->p_libvlc), i_type, FIND_CHILD); switch (i_type) { case VLC_OBJECT_VOUT: case VLC_OBJECT_AOUT: break; case VLC_OBJECT_INPUT: /* input can only be accessed like this from children, * otherwise we could not promise that it is initialized */ if (i_mode != FIND_PARENT) return NULL; break; default: return NULL; } libvlc_lock (p_this->p_libvlc); switch (i_mode) { case FIND_PARENT: p_found = FindParent (p_this, i_type); break; case FIND_CHILD: p_found = FindChild (vlc_internals (p_this), i_type); break; default: assert (0); } libvlc_unlock (p_this->p_libvlc); return p_found; }
/** **************************************************************************** * Set the destructor of a vlc object * * This function sets the destructor of the vlc object. It will be called * when the object is destroyed when the its refcount reaches 0. * (It is called by the internal function vlc_object_destroy()) *****************************************************************************/ void vlc_object_set_destructor( vlc_object_t *p_this, vlc_destructor_t pf_destructor ) { vlc_object_internals_t *p_priv = vlc_internals(p_this ); vlc_spin_lock( &p_priv->ref_spin ); p_priv->pf_destructor = pf_destructor; vlc_spin_unlock( &p_priv->ref_spin ); }
/** * Destroy everything. * This function requests the running threads to finish, waits for their * termination, and destroys their structure. * It stops the thread systems: no instance can run after this has run * \param p_libvlc the instance to destroy */ void libvlc_InternalDestroy( libvlc_int_t *p_libvlc ) { libvlc_priv_t *priv = libvlc_priv( p_libvlc ); vlc_ExitDestroy( &priv->exit ); assert( atomic_load(&(vlc_internals(p_libvlc)->refs)) == 1 ); vlc_object_release( p_libvlc ); }
static variable_t *Lookup( vlc_object_t *obj, const char *psz_name ) { vlc_object_internals_t *priv = vlc_internals( obj ); variable_t **pp_var; vlc_mutex_lock(&priv->var_lock); pp_var = tfind( &psz_name, &priv->var_root, varcmp ); return (pp_var != NULL) ? *pp_var : NULL; }
/** * Waits until the variable is inactive (i.e. not executing a callback) */ static void WaitUnused(vlc_object_t *obj, variable_t *var) { vlc_object_internals_t *priv = vlc_internals(obj); mutex_cleanup_push(&priv->var_lock); while (var->b_incallback) vlc_cond_wait(&priv->var_wait, &priv->var_lock); vlc_cleanup_pop(); }
/***************************************************************************** * vlc_thread_join: wait until a thread exits, inner version *****************************************************************************/ void vlc_thread_join( vlc_object_t *p_this ) { vlc_object_internals_t *p_priv = vlc_internals( p_this ); #if defined( WIN32 ) && !defined( UNDER_CE ) HANDLE hThread; FILETIME create_ft, exit_ft, kernel_ft, user_ft; int64_t real_time, kernel_time, user_time; if( ! DuplicateHandle(GetCurrentProcess(), p_priv->thread_id, GetCurrentProcess(), &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS) ) { p_priv->b_thread = false; return; /* We have a problem! */ } #endif vlc_join( p_priv->thread_id, NULL ); #if defined( WIN32 ) && !defined( UNDER_CE ) /* FIXME: this could work on WinCE too... except that it seems always to * return 0 for exit_ft and kernel_ft */ if( GetThreadTimes( hThread, &create_ft, &exit_ft, &kernel_ft, &user_ft ) ) { real_time = ((((int64_t)exit_ft.dwHighDateTime)<<32)| exit_ft.dwLowDateTime) - ((((int64_t)create_ft.dwHighDateTime)<<32)| create_ft.dwLowDateTime); real_time /= 10; kernel_time = ((((int64_t)kernel_ft.dwHighDateTime)<<32)| kernel_ft.dwLowDateTime) / 10; user_time = ((((int64_t)user_ft.dwHighDateTime)<<32)| user_ft.dwLowDateTime) / 10; msg_Dbg( p_this, "thread times: " "real %"PRId64"m%fs, kernel %"PRId64"m%fs, user %"PRId64"m%fs", real_time/60/1000000, (double)((real_time%(60*1000000))/1000000.0), kernel_time/60/1000000, (double)((kernel_time%(60*1000000))/1000000.0), user_time/60/1000000, (double)((user_time%(60*1000000))/1000000.0) ); } CloseHandle( hThread ); #endif p_priv->b_thread = false; }
static void PrintObject (vlc_object_t *obj, const char *prefix) { vlc_object_internals_t *priv = vlc_internals(obj); int canc = vlc_savecancel (); printf (" %so %p %s, %u refs, parent %p\n", prefix, (void *)obj, obj->obj.object_type, atomic_load(&priv->refs), (void *)obj->obj.parent); vlc_restorecancel (canc); }
/** **************************************************************************** * attach object to a parent object ***************************************************************************** * This function sets p_this as a child of p_parent, and p_parent as a parent * of p_this. This link can be undone using vlc_object_detach. *****************************************************************************/ void vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent ) { if( !p_this ) return; vlc_object_internals_t *pap = vlc_internals (p_parent); vlc_object_internals_t *priv = vlc_internals (p_this); vlc_object_t *p_old_parent; priv->prev = NULL; vlc_object_hold (p_parent); libvlc_lock (p_this->p_libvlc); #ifndef NDEBUG /* Reparenting an object carries a risk of invalid access to the parent, * from another thread. This can happen when inheriting a variable, or * through any direct access to vlc_object_t.p_parent. Also, reparenting * brings a functional bug, whereby the reparented object uses incorrect * old values for inherited variables (as the new parent may have different * variable values, especially if it is an input). * Note that the old parent may be already destroyed. * So its pointer must not be dereferenced. */ if (priv->old_parent) msg_Info (p_this, "Reparenting an object is dangerous (%p -> %p)!", priv->old_parent, p_parent); #endif p_old_parent = p_this->p_parent; if (p_old_parent) vlc_object_detach_unlocked (p_this); /* Attach the parent to its child */ p_this->p_parent = p_parent; /* Attach the child to its parent */ priv->next = pap->first; if (priv->next != NULL) priv->next->prev = priv; pap->first = priv; libvlc_unlock (p_this->p_libvlc); if (p_old_parent) vlc_object_release (p_old_parent); }
/** * Remove a callback from a variable * * pf_callback and p_data have to be given again, because different objects * might have registered the same callback function. */ int var_DelCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ) { int i_entry; variable_t *p_var; #ifndef NDEBUG bool b_found_similar = false; #endif assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); vlc_mutex_lock( &p_priv->var_lock ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } WaitUnused( p_this, p_var ); for( i_entry = p_var->i_entries ; i_entry-- ; ) { if( p_var->p_entries[i_entry].pf_callback == pf_callback && p_var->p_entries[i_entry].p_data == p_data ) { break; } #ifndef NDEBUG else if( p_var->p_entries[i_entry].pf_callback == pf_callback ) b_found_similar = true; #endif } if( i_entry < 0 ) { #ifndef NDEBUG if( b_found_similar ) fprintf( stderr, "Calling var_DelCallback for '%s' with the same " "function but not the same data.", psz_name ); assert( 0 ); #endif vlc_mutex_unlock( &p_priv->var_lock ); return VLC_EGENERIC; } REMOVE_ELEM( p_var->p_entries, p_var->i_entries, i_entry ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS; }
static vlc_object_t *FindParent (vlc_object_t *p_this, int i_type) { for (vlc_object_t *parent = p_this->p_parent; parent != NULL; parent = parent->p_parent) { if (vlc_internals (parent)->i_object_type == i_type) return vlc_object_hold (parent); } return NULL; }
/** * Gets the list of children of an objects, and increment their reference * count. * @return a list (possibly empty) or NULL in case of error. */ vlc_list_t *vlc_list_children( vlc_object_t *obj ) { vlc_list_t *l; vlc_object_internals_t *priv; unsigned count = 0; libvlc_lock (obj->p_libvlc); for (priv = vlc_internals (obj)->first; priv; priv = priv->next) count++; l = NewList (count); if (likely(l != NULL)) { unsigned i = 0; for (priv = vlc_internals (obj)->first; priv; priv = priv->next) l->p_values[i++].p_object = vlc_object_hold (vlc_externals (priv)); } libvlc_unlock (obj->p_libvlc); return l; }
char *vlc_object_get_name(const vlc_object_t *obj) { vlc_object_internals_t *priv = vlc_internals(obj); char *name; vlc_mutex_lock (&name_lock); name = priv->psz_name ? strdup (priv->psz_name) : NULL; vlc_mutex_unlock (&name_lock); return name; }
static vlc_object_t *FindParentName (vlc_object_t *p_this, const char *name) { for (vlc_object_t *parent = p_this->p_parent; parent != NULL; parent = parent->p_parent) { const char *objname = vlc_internals (parent)->psz_name; if (objname && !strcmp (objname, name)) return vlc_object_hold (parent); } return NULL; }
static void vlc_object_detach_unlocked (vlc_object_t *p_this) { assert (p_this->p_parent != NULL); vlc_object_internals_t *pap = vlc_internals (p_this->p_parent); vlc_object_internals_t *priv = vlc_internals (p_this); /* Unlink */ if (priv->prev != NULL) priv->prev->next = priv->next; else pap->first = priv->next; if (priv->next != NULL) priv->next->prev = priv->prev; /* Remove p_this's parent */ #ifndef NDEBUG priv->old_parent = p_this->p_parent; #endif p_this->p_parent = NULL; }