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

picture_pool: no longer muck with the reference counts, fix races

parent 85e5f7ca
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
struct picture_gc_sys_t { struct picture_gc_sys_t {
picture_pool_t *pool; picture_pool_t *pool;
picture_t *picture; picture_t *picture;
bool in_use;
int64_t tick; int64_t tick;
}; };
...@@ -89,6 +90,11 @@ static void picture_pool_ReleasePicture(picture_t *picture) ...@@ -89,6 +90,11 @@ static void picture_pool_ReleasePicture(picture_t *picture)
if (pool->pic_unlock != NULL) if (pool->pic_unlock != NULL)
pool->pic_unlock(picture); pool->pic_unlock(picture);
vlc_mutex_lock(&pool->lock);
assert(sys->in_use);
sys->in_use = false;
vlc_mutex_unlock(&pool->lock);
picture_pool_Release(pool); picture_pool_Release(pool);
} }
...@@ -101,6 +107,7 @@ static picture_t *picture_pool_ClonePicture(picture_pool_t *pool, ...@@ -101,6 +107,7 @@ static picture_t *picture_pool_ClonePicture(picture_pool_t *pool,
sys->pool = pool; sys->pool = pool;
sys->picture = picture; sys->picture = picture;
sys->in_use = false;
sys->tick = 0; sys->tick = 0;
picture_resource_t res = { picture_resource_t res = {
...@@ -231,62 +238,94 @@ void picture_pool_Delete(picture_pool_t *pool) ...@@ -231,62 +238,94 @@ void picture_pool_Delete(picture_pool_t *pool)
picture_t *picture_pool_Get(picture_pool_t *pool) picture_t *picture_pool_Get(picture_pool_t *pool)
{ {
vlc_mutex_lock(&pool->lock);
assert(pool->refs > 0);
for (unsigned i = 0; i < pool->picture_count; i++) { for (unsigned i = 0; i < pool->picture_count; i++) {
picture_t *picture = pool->picture[i]; picture_t *picture = pool->picture[i];
uintptr_t refs = 0; picture_gc_sys_t *sys = picture->gc.p_sys;
uint64_t tick;
if (!atomic_compare_exchange_strong(&picture->gc.refcount, &refs, 1)) if (sys->in_use)
continue; continue;
pool->refs++;
tick = ++pool->tick;
sys->in_use = true;
vlc_mutex_unlock(&pool->lock);
if (pool->pic_lock != NULL && pool->pic_lock(picture) != 0) { if (pool->pic_lock != NULL && pool->pic_lock(picture) != 0) {
atomic_store(&picture->gc.refcount, 0); vlc_mutex_lock(&pool->lock);
sys->in_use = false;
pool->refs--;
vlc_mutex_unlock(&pool->lock);
continue; continue;
} }
vlc_mutex_lock(&pool->lock); sys->tick = tick;
pool->refs++;
picture->gc.p_sys->tick = pool->tick++;
vlc_mutex_unlock(&pool->lock);
assert(atomic_load(&picture->gc.refcount) == 0);
atomic_init(&picture->gc.refcount, 1);
picture->p_next = NULL; picture->p_next = NULL;
return picture; return picture;
} }
vlc_mutex_unlock(&pool->lock);
return NULL; return NULL;
} }
void picture_pool_Reset(picture_pool_t *pool) void picture_pool_Reset(picture_pool_t *pool)
{ {
retry:
vlc_mutex_lock(&pool->lock);
assert(pool->refs > 0);
for (unsigned i = 0; i < pool->picture_count; i++) { for (unsigned i = 0; i < pool->picture_count; i++) {
picture_t *picture = pool->picture[i]; picture_t *picture = pool->picture[i];
if (atomic_load(&picture->gc.refcount) > 0) { picture_gc_sys_t *sys = picture->gc.p_sys;
if (pool->pic_unlock != NULL)
pool->pic_unlock(picture); if (sys->in_use) {
vlc_mutex_unlock(&pool->lock);
picture_Release(picture);
goto retry;
} }
atomic_store(&picture->gc.refcount, 0);
} }
vlc_mutex_unlock(&pool->lock);
} }
void picture_pool_NonEmpty(picture_pool_t *pool) void picture_pool_NonEmpty(picture_pool_t *pool)
{ {
picture_t *oldest = NULL; picture_t *oldest = NULL;
uint64_t tick = 0;
vlc_mutex_lock(&pool->lock);
assert(pool->refs > 0);
for (unsigned i = 0; i < pool->picture_count; i++) { for (unsigned i = 0; i < pool->picture_count; i++) {
picture_t *picture = pool->picture[i]; picture_t *picture = pool->picture[i];
if (atomic_load(&picture->gc.refcount) == 0) picture_gc_sys_t *sys = picture->gc.p_sys;
if (!sys->in_use) {
vlc_mutex_unlock(&pool->lock);
return; /* Nothing to do */ return; /* Nothing to do */
}
if (oldest == NULL || picture->gc.p_sys->tick < oldest->gc.p_sys->tick) if (picture->gc.p_sys->tick < tick) {
oldest = picture; oldest = picture;
tick = picture->gc.p_sys->tick;
}
} }
if (oldest == NULL) if (oldest != NULL) {
return; /* Cannot fix! */ while (oldest->gc.p_sys->in_use) {
vlc_mutex_unlock(&pool->lock);
if (atomic_load(&oldest->gc.refcount) > 0) { picture_Release(oldest);
if (pool->pic_unlock != NULL) vlc_mutex_lock(&pool->lock);
pool->pic_unlock(oldest); }
} }
atomic_store(&oldest->gc.refcount, 0);
vlc_mutex_unlock(&pool->lock);
} }
int picture_pool_GetSize(picture_pool_t *pool) int picture_pool_GetSize(picture_pool_t *pool)
......
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