[vlc-devel] commit: GC: thread-safety, and offset independence ( Rémi Denis-Courmont )
git version control
git at videolan.org
Fri Sep 19 16:25:23 CEST 2008
vlc | branch: master | Rémi Denis-Courmont <rdenis at simphalempin.com> | Fri Sep 19 16:49:29 2008 +0300| [e3d6b0ba195ffbdf2b5eee1df90bb5240da60c2c] | committer: Rémi Denis-Courmont
GC: thread-safety, and offset independence
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e3d6b0ba195ffbdf2b5eee1df90bb5240da60c2c
---
include/vlc_common.h | 38 +++++++++++--------------
include/vlc_input.h | 1 +
src/input/item.c | 19 +++++++-----
src/libvlc.c | 76 +++++++++++++++++++++++++++++++++-----------------
src/libvlccore.sym | 6 ++--
5 files changed, 82 insertions(+), 58 deletions(-)
diff --git a/include/vlc_common.h b/include/vlc_common.h
index 4ba2ab3..d0efdf0 100644
--- a/include/vlc_common.h
+++ b/include/vlc_common.h
@@ -50,6 +50,7 @@
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
+#include <stddef.h>
#ifndef __cplusplus
# include <stdbool.h>
@@ -142,7 +143,6 @@ typedef struct variable_t variable_t;
typedef struct date_t date_t;
typedef struct dict_entry_t dict_entry_t;
typedef struct dict_t dict_t;
-typedef struct gc_object_t gc_object_t ;
/* Messages */
typedef struct msg_subscription_t msg_subscription_t;
@@ -558,30 +558,26 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */
# define VLC_OBJECT( x ) ((vlc_object_t *)(x))
#endif
-#define VLC_GC_MEMBERS \
-/** \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
+typedef 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 ));
-VLC_EXPORT(void, __vlc_gc_init, ( gc_object_t * p_gc,
- void (*pf_destructor)( gc_object_t * ), void * arg));
+/**
+ * These members are common to all objects that wish to be garbage-collected.
+ */
+#define VLC_GC_MEMBERS gc_object_t vlc_gc_data;
-#define vlc_gc_incref( a ) __vlc_gc_incref( (gc_object_t *)a )
-#define vlc_gc_decref( a ) __vlc_gc_decref( (gc_object_t *)a )
-#define vlc_gc_init( a,b,c ) __vlc_gc_init( (gc_object_t *)a,b,c )
+VLC_EXPORT(void *, vlc_gc_init, (gc_object_t *, void (*)(gc_object_t *)));
+VLC_EXPORT(void *, vlc_hold, (gc_object_t *));
+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
diff --git a/include/vlc_input.h b/include/vlc_input.h
index 6eeeb05..dc81248 100644
--- a/include/vlc_input.h
+++ b/include/vlc_input.h
@@ -60,6 +60,7 @@ struct input_item_t
{
VLC_GC_MEMBERS
int i_id; /**< Identifier of the item */
+ libvlc_int_t *p_libvlc;
char *psz_name; /**< text describing this item */
char *psz_uri; /**< mrl of this item */
diff --git a/src/input/item.c b/src/input/item.c
index 91d30de..4dc62c5 100644
--- a/src/input/item.c
+++ b/src/input/item.c
@@ -367,23 +367,25 @@ char *input_item_GetInfo( input_item_t *p_i,
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;
- libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
- input_item_t *p_input = (input_item_t *) p_this;
+ input_item_t *p_input = vlc_priv(gc, input_item_t);
+ libvlc_int_t *p_libvlc = p_input->p_libvlc;
int i;
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);
if( i != -1 )
ARRAY_REMOVE( priv->input_items, i);
- vlc_object_unlock( p_obj->p_libvlc );
-
+ vlc_object_unlock( p_libvlc );
free( p_input );
}
@@ -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 );
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 );
p_input->i_id = ++priv->i_last_input_id;
diff --git a/src/libvlc.c b/src/libvlc.c
index f1d42d8..87920fb 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -104,39 +104,63 @@ static unsigned i_instances = 0;
static bool b_daemon = false;
#endif
-/*****************************************************************************
- * vlc_gc_*.
- *****************************************************************************/
-void __vlc_gc_incref( gc_object_t * p_gc )
-{
- assert( p_gc->i_gc_refcount > 0 );
+#undef vlc_gc_init
+#undef vlc_hold
+#undef vlc_release
- /* 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->i_gc_refcount > 0 );
-
- /* FIXME: atomic version needed! */
- p_gc->i_gc_refcount -- ;
- if( p_gc->i_gc_refcount == 0 )
- {
- p_gc->pf_destructor( p_gc );
- /* Do not use the p_gc pointer from now on ! */
- }
+ vlc_spin_lock (&p_gc->spin);
+ assert (p_gc->refs > 0);
+ p_gc->refs++;
+ vlc_spin_unlock (&p_gc->spin);
+ return p_gc;
}
-void
-__vlc_gc_init( gc_object_t * p_gc, void (*pf_destructor)( gc_object_t * ),
- void * arg)
+/**
+ * Atomically decrement the reference count and, if it reaches zero, destroy.
+ * @param p_gc reference counted object.
+ */
+void vlc_release (gc_object_t *p_gc)
{
- p_gc->i_gc_refcount = 1;
- p_gc->pf_destructor = pf_destructor;
- p_gc->p_destructor_arg = arg;
+ bool dead;
+
+ 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 )
bool b_clean = true;
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",
- p_del, p_del->i_gc_refcount, p_del->psz_name ? p_del->psz_name : "(null)" );
+ msg_Err( p_libvlc, "input item %p has not been deleted properly: name %s",
+ p_del, p_del->psz_name ? p_del->psz_name : "(null)" );
b_clean = false;
FOREACH_END();
assert( b_clean );
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index c39770c..7760fef 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -448,12 +448,11 @@ __vlc_execve
vlc_fastmem_register
vlc_freeaddrinfo
vlc_gai_strerror
-__vlc_gc_decref
-__vlc_gc_incref
-__vlc_gc_init
+vlc_gc_init
vlc_getaddrinfo
vlc_getnameinfo
vlc_gettext
+vlc_hold
vlc_iconv
vlc_iconv_close
vlc_iconv_open
@@ -490,6 +489,7 @@ __vlc_object_yield
vlc_poll
vlc_rand_bytes
vlc_recvmsg
+vlc_release
vlc_sdp_Start
vlc_sendmsg
vlc_strcasestr
More information about the vlc-devel
mailing list