Commit 327ffd12 authored by Laurent Aimar's avatar Laurent Aimar

Thread safe picture_t refcounting.

parent 7090b8ef
...@@ -56,10 +56,11 @@ typedef struct plane_t ...@@ -56,10 +56,11 @@ typedef struct plane_t
*/ */
#define PICTURE_PLANE_MAX (VOUT_MAX_PLANES) #define PICTURE_PLANE_MAX (VOUT_MAX_PLANES)
/** /**
* A private definition to help overloading picture release * A private definition to help overloading picture release
*/ */
typedef struct picture_release_sys_t picture_release_sys_t; typedef struct picture_gc_sys_t picture_gc_sys_t;
/** /**
* Video picture * Video picture
...@@ -79,7 +80,6 @@ struct picture_t ...@@ -79,7 +80,6 @@ struct picture_t
* These properties can be modified using the video output thread API, * These properties can be modified using the video output thread API,
* but should never be written directly */ * but should never be written directly */
/**@{*/ /**@{*/
unsigned i_refcount; /**< link reference counter */
mtime_t date; /**< display date */ mtime_t date; /**< display date */
bool b_force; bool b_force;
/**@}*/ /**@}*/
...@@ -101,8 +101,12 @@ struct picture_t ...@@ -101,8 +101,12 @@ struct picture_t
picture_sys_t * p_sys; picture_sys_t * p_sys;
/** This way the picture_Release can be overloaded */ /** This way the picture_Release can be overloaded */
void (*pf_release)( picture_t * ); struct
picture_release_sys_t *p_release_sys; {
vlc_atomic_t refcount;
void (*pf_destroy)( picture_t * );
picture_gc_sys_t *p_sys;
} gc;
/** Next picture in a FIFO a pictures */ /** Next picture in a FIFO a pictures */
struct picture_t *p_next; struct picture_t *p_next;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <vlc_picture.h> #include <vlc_picture.h>
#include <vlc_image.h> #include <vlc_image.h>
#include <vlc_block.h> #include <vlc_block.h>
#include <vlc_atomic.h>
/** /**
* Allocate a new picture in the heap. * Allocate a new picture in the heap.
...@@ -92,10 +93,11 @@ static int AllocatePicture( picture_t *p_pic, ...@@ -92,10 +93,11 @@ static int AllocatePicture( picture_t *p_pic,
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
static void picture_Delete( picture_t *p_picture ) static void PictureDestroy( picture_t *p_picture )
{ {
assert( p_picture && p_picture->i_refcount == 0 ); assert( p_picture &&
assert( p_picture->p_release_sys == NULL ); vlc_atomic_get( &p_picture->gc.refcount ) == 0 &&
p_picture->gc.p_sys == NULL );
free( p_picture->p_q ); free( p_picture->p_q );
vlc_free( p_picture->p_data_orig ); vlc_free( p_picture->p_data_orig );
...@@ -103,13 +105,6 @@ static void picture_Delete( picture_t *p_picture ) ...@@ -103,13 +105,6 @@ static void picture_Delete( picture_t *p_picture )
free( p_picture ); free( p_picture );
} }
static void PictureReleaseCallback( picture_t *p_picture )
{
if( --p_picture->i_refcount > 0 )
return;
picture_Delete( p_picture );
}
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
...@@ -148,9 +143,9 @@ int picture_Setup( picture_t *p_picture, vlc_fourcc_t i_chroma, ...@@ -148,9 +143,9 @@ int picture_Setup( picture_t *p_picture, vlc_fourcc_t i_chroma,
p->i_pixel_pitch = 0; p->i_pixel_pitch = 0;
} }
p_picture->pf_release = NULL; vlc_atomic_set( &p_picture->gc.refcount, 0 );
p_picture->p_release_sys = NULL; p_picture->gc.pf_destroy = NULL;
p_picture->i_refcount = 0; p_picture->gc.p_sys = NULL;
p_picture->i_nb_fields = 2; p_picture->i_nb_fields = 2;
...@@ -255,8 +250,10 @@ picture_t *picture_NewFromResource( const video_format_t *p_fmt, const picture_r ...@@ -255,8 +250,10 @@ picture_t *picture_NewFromResource( const video_format_t *p_fmt, const picture_r
} }
/* */ /* */
p_picture->format = fmt; p_picture->format = fmt;
p_picture->i_refcount = 1;
p_picture->pf_release = PictureReleaseCallback; vlc_atomic_set( &p_picture->gc.refcount, 1 );
p_picture->gc.pf_destroy = PictureDestroy;
p_picture->gc.p_sys = NULL;
return p_picture; return p_picture;
} }
...@@ -281,21 +278,20 @@ picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_ ...@@ -281,21 +278,20 @@ picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_
picture_t *picture_Hold( picture_t *p_picture ) picture_t *picture_Hold( picture_t *p_picture )
{ {
if( p_picture->pf_release ) vlc_atomic_inc( &p_picture->gc.refcount );
p_picture->i_refcount++;
return p_picture; return p_picture;
} }
void picture_Release( picture_t *p_picture ) void picture_Release( picture_t *p_picture )
{ {
/* FIXME why do we let pf_release handle the i_refcount ? */ if( vlc_atomic_dec( &p_picture->gc.refcount ) == 0 &&
if( p_picture->pf_release ) p_picture->gc.pf_destroy )
p_picture->pf_release( p_picture ); p_picture->gc.pf_destroy( p_picture );
} }
bool picture_IsReferenced( picture_t *p_picture ) bool picture_IsReferenced( picture_t *p_picture )
{ {
return p_picture->i_refcount > 1; return vlc_atomic_get( &p_picture->gc.refcount ) > 1;
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -33,14 +33,15 @@ ...@@ -33,14 +33,15 @@
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_picture_pool.h> #include <vlc_picture_pool.h>
#include <vlc_atomic.h>
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
struct picture_release_sys_t { struct picture_gc_sys_t {
/* Saved release */ /* Saved release */
void (*release)(picture_t *); void (*destroy)(picture_t *);
picture_release_sys_t *release_sys; void *destroy_sys;
/* */ /* */
int (*lock)(picture_t *); int (*lock)(picture_t *);
...@@ -60,7 +61,7 @@ struct picture_pool_t { ...@@ -60,7 +61,7 @@ struct picture_pool_t {
bool *picture_reserved; bool *picture_reserved;
}; };
static void Release(picture_t *); static void Destroy(picture_t *);
static int Lock(picture_t *); static int Lock(picture_t *);
static void Unlock(picture_t *); static void Unlock(picture_t *);
...@@ -94,22 +95,22 @@ picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg ...@@ -94,22 +95,22 @@ picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg
picture_t *picture = cfg->picture[i]; picture_t *picture = cfg->picture[i];
/* The pool must be the only owner of the picture */ /* The pool must be the only owner of the picture */
assert(picture->i_refcount == 1); assert(!picture_IsReferenced(picture));
/* Install the new release callback */ /* Install the new release callback */
picture_release_sys_t *release_sys = malloc(sizeof(*release_sys)); picture_gc_sys_t *gc_sys = malloc(sizeof(*gc_sys));
if (!release_sys) if (!gc_sys)
abort(); abort();
release_sys->release = picture->pf_release; gc_sys->destroy = picture->gc.pf_destroy;
release_sys->release_sys = picture->p_release_sys; gc_sys->destroy_sys = picture->gc.p_sys;
release_sys->lock = cfg->lock; gc_sys->lock = cfg->lock;
release_sys->unlock = cfg->unlock; gc_sys->unlock = cfg->unlock;
release_sys->tick = 0; gc_sys->tick = 0;
/* */ /* */
picture->i_refcount = 0; vlc_atomic_set(&picture->gc.refcount, 0);
picture->pf_release = Release; picture->gc.pf_destroy = Destroy;
picture->p_release_sys = release_sys; picture->gc.p_sys = gc_sys;
/* */ /* */
pool->picture[i] = picture; pool->picture[i] = picture;
...@@ -165,7 +166,7 @@ picture_pool_t *picture_pool_Reserve(picture_pool_t *master, int count) ...@@ -165,7 +166,7 @@ picture_pool_t *picture_pool_Reserve(picture_pool_t *master, int count)
if (master->picture_reserved[i]) if (master->picture_reserved[i])
continue; continue;
assert(master->picture[i]->i_refcount == 0); assert(vlc_atomic_get(&master->picture[i]->gc.refcount) == 0);
master->picture_reserved[i] = true; master->picture_reserved[i] = true;
pool->picture[found] = master->picture[i]; pool->picture[found] = master->picture[i];
...@@ -189,19 +190,19 @@ void picture_pool_Delete(picture_pool_t *pool) ...@@ -189,19 +190,19 @@ void picture_pool_Delete(picture_pool_t *pool)
pool->master->picture_reserved[j] = false; pool->master->picture_reserved[j] = false;
} }
} else { } else {
picture_release_sys_t *release_sys = picture->p_release_sys; picture_gc_sys_t *gc_sys = picture->gc.p_sys;
assert(picture->i_refcount == 0); assert(vlc_atomic_get(&picture->gc.refcount) == 0);
assert(!pool->picture_reserved[i]); assert(!pool->picture_reserved[i]);
/* Restore old release callback */ /* Restore old release callback */
picture->i_refcount = 1; vlc_atomic_set(&picture->gc.refcount, 1);
picture->pf_release = release_sys->release; picture->gc.pf_destroy = gc_sys->destroy;
picture->p_release_sys = release_sys->release_sys; picture->gc.p_sys = gc_sys->destroy_sys;
picture_Release(picture); picture_Release(picture);
free(release_sys); free(gc_sys);
} }
} }
free(pool->picture_reserved); free(pool->picture_reserved);
...@@ -216,7 +217,7 @@ picture_t *picture_pool_Get(picture_pool_t *pool) ...@@ -216,7 +217,7 @@ picture_t *picture_pool_Get(picture_pool_t *pool)
continue; continue;
picture_t *picture = pool->picture[i]; picture_t *picture = pool->picture[i];
if (picture->i_refcount > 0) if (vlc_atomic_get(&picture->gc.refcount) > 0)
continue; continue;
if (Lock(picture)) if (Lock(picture))
...@@ -224,7 +225,7 @@ picture_t *picture_pool_Get(picture_pool_t *pool) ...@@ -224,7 +225,7 @@ picture_t *picture_pool_Get(picture_pool_t *pool)
/* */ /* */
picture->p_next = NULL; picture->p_next = NULL;
picture->p_release_sys->tick = pool->tick++; picture->gc.p_sys->tick = pool->tick++;
picture_Hold(picture); picture_Hold(picture);
return picture; return picture;
} }
...@@ -241,19 +242,19 @@ void picture_pool_NonEmpty(picture_pool_t *pool, bool reset) ...@@ -241,19 +242,19 @@ void picture_pool_NonEmpty(picture_pool_t *pool, bool reset)
picture_t *picture = pool->picture[i]; picture_t *picture = pool->picture[i];
if (reset) { if (reset) {
if (picture->i_refcount > 0) if (vlc_atomic_get(&picture->gc.refcount) > 0)
Unlock(picture); Unlock(picture);
picture->i_refcount = 0; vlc_atomic_set(&picture->gc.refcount, 0);
} else if (picture->i_refcount == 0) { } else if (vlc_atomic_get(&picture->gc.refcount) == 0) {
return; return;
} else if (!old || picture->p_release_sys->tick < old->p_release_sys->tick) { } else if (!old || picture->gc.p_sys->tick < old->gc.p_sys->tick) {
old = picture; old = picture;
} }
} }
if (!reset && old) { if (!reset && old) {
if (old->i_refcount > 0) if (vlc_atomic_get(&old->gc.refcount) > 0)
Unlock(old); Unlock(old);
old->i_refcount = 0; vlc_atomic_set(&old->gc.refcount, 0);
} }
} }
int picture_pool_GetSize(picture_pool_t *pool) int picture_pool_GetSize(picture_pool_t *pool)
...@@ -261,26 +262,22 @@ int picture_pool_GetSize(picture_pool_t *pool) ...@@ -261,26 +262,22 @@ int picture_pool_GetSize(picture_pool_t *pool)
return pool->picture_count; return pool->picture_count;
} }
static void Release(picture_t *picture) static void Destroy(picture_t *picture)
{ {
assert(picture->i_refcount > 0);
if (--picture->i_refcount > 0)
return;
Unlock(picture); Unlock(picture);
} }
static int Lock(picture_t *picture) static int Lock(picture_t *picture)
{ {
picture_release_sys_t *release_sys = picture->p_release_sys; picture_gc_sys_t *gc_sys = picture->gc.p_sys;
if (release_sys->lock) if (gc_sys->lock)
return release_sys->lock(picture); return gc_sys->lock(picture);
return VLC_SUCCESS; return VLC_SUCCESS;
} }
static void Unlock(picture_t *picture) static void Unlock(picture_t *picture)
{ {
picture_release_sys_t *release_sys = picture->p_release_sys; picture_gc_sys_t *gc_sys = picture->gc.p_sys;
if (release_sys->unlock) if (gc_sys->unlock)
release_sys->unlock(picture); gc_sys->unlock(picture);
} }
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