Commit e3d6b0ba authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

GC: thread-safety, and offset independence

parent 45ca5cbd
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
#include <stddef.h>
#ifndef __cplusplus #ifndef __cplusplus
# include <stdbool.h> # include <stdbool.h>
...@@ -142,7 +143,6 @@ typedef struct variable_t variable_t; ...@@ -142,7 +143,6 @@ typedef struct variable_t variable_t;
typedef struct date_t date_t; typedef struct date_t date_t;
typedef struct dict_entry_t dict_entry_t; typedef struct dict_entry_t dict_entry_t;
typedef struct dict_t dict_t; typedef struct dict_t dict_t;
typedef struct gc_object_t gc_object_t ;
/* Messages */ /* Messages */
typedef struct msg_subscription_t msg_subscription_t; typedef struct msg_subscription_t msg_subscription_t;
...@@ -558,30 +558,26 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */ ...@@ -558,30 +558,26 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */
# define VLC_OBJECT( x ) ((vlc_object_t *)(x)) # define VLC_OBJECT( x ) ((vlc_object_t *)(x))
#endif #endif
#define VLC_GC_MEMBERS \ typedef struct gc_object_t
/** \name VLC_GC_MEMBERS \
* these members are common to all objects that wish to be garbage-collected \
*/ \
/**@{*/ \
int i_gc_refcount; \
void (*pf_destructor) ( gc_object_t * ); \
void *p_destructor_arg; \
/**@}*/
struct gc_object_t
{ {
VLC_GC_MEMBERS vlc_spinlock_t spin;
}; uintptr_t refs;
void (*pf_destructor) (struct gc_object_t *);
} gc_object_t;
VLC_EXPORT(void, __vlc_gc_incref, ( gc_object_t * p_gc )); /**
VLC_EXPORT(void, __vlc_gc_decref, ( gc_object_t * p_gc )); * These members are common to all objects that wish to be garbage-collected.
VLC_EXPORT(void, __vlc_gc_init, ( gc_object_t * p_gc, */
void (*pf_destructor)( gc_object_t * ), void * arg)); #define VLC_GC_MEMBERS gc_object_t vlc_gc_data;
#define vlc_gc_incref( a ) __vlc_gc_incref( (gc_object_t *)a ) VLC_EXPORT(void *, vlc_gc_init, (gc_object_t *, void (*)(gc_object_t *)));
#define vlc_gc_decref( a ) __vlc_gc_decref( (gc_object_t *)a ) VLC_EXPORT(void *, vlc_hold, (gc_object_t *));
#define vlc_gc_init( a,b,c ) __vlc_gc_init( (gc_object_t *)a,b,c ) VLC_EXPORT(void, vlc_release, (gc_object_t *));
#define vlc_gc_init( a,b ) vlc_gc_init( &(a)->vlc_gc_data, (b) )
#define vlc_gc_incref( a ) vlc_hold( &(a)->vlc_gc_data )
#define vlc_gc_decref( a ) vlc_release( &(a)->vlc_gc_data )
#define vlc_priv( gc, t ) ((t *)(((char *)(gc)) - offsetof(t, vlc_gc_data)))
/***************************************************************************** /*****************************************************************************
* Macros and inline functions * Macros and inline functions
......
...@@ -60,6 +60,7 @@ struct input_item_t ...@@ -60,6 +60,7 @@ struct input_item_t
{ {
VLC_GC_MEMBERS VLC_GC_MEMBERS
int i_id; /**< Identifier of the item */ int i_id; /**< Identifier of the item */
libvlc_int_t *p_libvlc;
char *psz_name; /**< text describing this item */ char *psz_name; /**< text describing this item */
char *psz_uri; /**< mrl of this item */ char *psz_uri; /**< mrl of this item */
......
...@@ -367,23 +367,25 @@ char *input_item_GetInfo( input_item_t *p_i, ...@@ -367,23 +367,25 @@ char *input_item_GetInfo( input_item_t *p_i,
return strdup( "" ); return strdup( "" );
} }
static void input_item_Destroy ( gc_object_t *p_this ) static void input_item_Destroy ( gc_object_t *gc )
{ {
vlc_object_t *p_obj = (vlc_object_t *)p_this->p_destructor_arg; input_item_t *p_input = vlc_priv(gc, input_item_t);
libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc); libvlc_int_t *p_libvlc = p_input->p_libvlc;
input_item_t *p_input = (input_item_t *) p_this;
int i; int i;
input_item_Clean( p_input ); input_item_Clean( p_input );
vlc_object_lock( p_obj->p_libvlc ); /* This is broken. Items must be removed from any table before their
* reference count drops to zero (unless the table is not used, but then
* why have it?). Full point, no buts. -- Courmisch */
libvlc_priv_t *priv = libvlc_priv (p_libvlc);
vlc_object_lock( p_libvlc );
ARRAY_BSEARCH( priv->input_items,->i_id, int, p_input->i_id, i); ARRAY_BSEARCH( priv->input_items,->i_id, int, p_input->i_id, i);
if( i != -1 ) if( i != -1 )
ARRAY_REMOVE( priv->input_items, i); ARRAY_REMOVE( priv->input_items, i);
vlc_object_unlock( p_obj->p_libvlc ); vlc_object_unlock( p_libvlc );
free( p_input ); free( p_input );
} }
...@@ -528,7 +530,8 @@ input_item_t *input_item_NewWithType( vlc_object_t *p_obj, const char *psz_uri, ...@@ -528,7 +530,8 @@ input_item_t *input_item_NewWithType( vlc_object_t *p_obj, const char *psz_uri,
DECMALLOC_NULL( p_input, input_item_t ); DECMALLOC_NULL( p_input, input_item_t );
input_item_Init( p_obj, p_input ); input_item_Init( p_obj, p_input );
vlc_gc_init( p_input, input_item_Destroy, (void *)p_obj->p_libvlc ); vlc_gc_init( p_input, input_item_Destroy );
p_input->p_libvlc = p_obj->p_libvlc;
vlc_object_lock( p_obj->p_libvlc ); vlc_object_lock( p_obj->p_libvlc );
p_input->i_id = ++priv->i_last_input_id; p_input->i_id = ++priv->i_last_input_id;
......
...@@ -104,39 +104,63 @@ static unsigned i_instances = 0; ...@@ -104,39 +104,63 @@ static unsigned i_instances = 0;
static bool b_daemon = false; static bool b_daemon = false;
#endif #endif
/***************************************************************************** #undef vlc_gc_init
* vlc_gc_*. #undef vlc_hold
*****************************************************************************/ #undef vlc_release
void __vlc_gc_incref( gc_object_t * p_gc )
{
assert( p_gc->i_gc_refcount > 0 );
/* FIXME: atomic version needed! */ /**
p_gc->i_gc_refcount ++; * Atomically set the reference count to 1.
* @param p_gc reference counted object
* @param pf_destruct destruction calback
* @return p_gc.
*/
void *vlc_gc_init (gc_object_t *p_gc, void (*pf_destruct) (gc_object_t *))
{
p_gc->pf_destructor = pf_destruct;
/* Nobody else can possibly lock the spin - it's there as a barrier */
vlc_spin_init (&p_gc->spin);
vlc_spin_lock (&p_gc->spin);
p_gc->refs = 1;
vlc_spin_unlock (&p_gc->spin);
return p_gc;
} }
void __vlc_gc_decref( gc_object_t *p_gc ) /**
* Atomically increment the reference count.
* @param p_gc reference counted object
* @return p_gc.
*/
void *vlc_hold (gc_object_t * p_gc)
{ {
assert( p_gc ); assert( p_gc );
assert( p_gc->i_gc_refcount > 0 );
/* FIXME: atomic version needed! */
p_gc->i_gc_refcount -- ;
if( p_gc->i_gc_refcount == 0 ) vlc_spin_lock (&p_gc->spin);
{ assert (p_gc->refs > 0);
p_gc->pf_destructor( p_gc ); p_gc->refs++;
/* Do not use the p_gc pointer from now on ! */ vlc_spin_unlock (&p_gc->spin);
} return p_gc;
} }
void /**
__vlc_gc_init( gc_object_t * p_gc, void (*pf_destructor)( gc_object_t * ), * Atomically decrement the reference count and, if it reaches zero, destroy.
void * arg) * @param p_gc reference counted object.
*/
void vlc_release (gc_object_t *p_gc)
{ {
p_gc->i_gc_refcount = 1; bool dead;
p_gc->pf_destructor = pf_destructor;
p_gc->p_destructor_arg = arg; assert( p_gc );
vlc_spin_lock (&p_gc->spin);
assert (p_gc->refs > 0);
dead = !--p_gc->refs;
vlc_spin_unlock (&p_gc->spin);
if (dead)
{
vlc_spin_destroy (&p_gc->spin);
p_gc->pf_destructor (p_gc);
}
} }
/***************************************************************************** /*****************************************************************************
...@@ -1025,8 +1049,8 @@ int libvlc_InternalCleanup( libvlc_int_t *p_libvlc ) ...@@ -1025,8 +1049,8 @@ int libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
bool b_clean = true; bool b_clean = true;
FOREACH_ARRAY( input_item_t *p_del, priv->input_items ) FOREACH_ARRAY( input_item_t *p_del, priv->input_items )
msg_Err( p_libvlc, "input item %p has not been deleted properly: refcount %d, name %s", msg_Err( p_libvlc, "input item %p has not been deleted properly: name %s",
p_del, p_del->i_gc_refcount, p_del->psz_name ? p_del->psz_name : "(null)" ); p_del, p_del->psz_name ? p_del->psz_name : "(null)" );
b_clean = false; b_clean = false;
FOREACH_END(); FOREACH_END();
assert( b_clean ); assert( b_clean );
......
...@@ -448,12 +448,11 @@ __vlc_execve ...@@ -448,12 +448,11 @@ __vlc_execve
vlc_fastmem_register vlc_fastmem_register
vlc_freeaddrinfo vlc_freeaddrinfo
vlc_gai_strerror vlc_gai_strerror
__vlc_gc_decref vlc_gc_init
__vlc_gc_incref
__vlc_gc_init
vlc_getaddrinfo vlc_getaddrinfo
vlc_getnameinfo vlc_getnameinfo
vlc_gettext vlc_gettext
vlc_hold
vlc_iconv vlc_iconv
vlc_iconv_close vlc_iconv_close
vlc_iconv_open vlc_iconv_open
...@@ -490,6 +489,7 @@ __vlc_object_yield ...@@ -490,6 +489,7 @@ __vlc_object_yield
vlc_poll vlc_poll
vlc_rand_bytes vlc_rand_bytes
vlc_recvmsg vlc_recvmsg
vlc_release
vlc_sdp_Start vlc_sdp_Start
vlc_sendmsg vlc_sendmsg
vlc_strcasestr vlc_strcasestr
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment