]> git.sesse.net Git - vlc/blobdiff - src/misc/picture_pool.c
build: create a macro to check for, and replace, possibly-inline functions.
[vlc] / src / misc / picture_pool.c
index 64ddf2e0630411bf866ca4188f14473aaa8b9df3..98e093f130bee4d084ba11327b43baa4599768f8 100644 (file)
 struct picture_gc_sys_t {
     picture_pool_t *pool;
     picture_t *picture;
-    atomic_bool zombie;
-    int64_t tick;
+    bool in_use;
+    uint64_t tick;
 };
 
 struct picture_pool_t {
-    /* */
-    picture_pool_t *master;
-    int64_t        tick;
+    uint64_t       tick;
     /* */
     unsigned       picture_count;
     picture_t      **picture;
-    bool           *picture_reserved;
 
     int       (*pic_lock)(picture_t *);
     void      (*pic_unlock)(picture_t *);
@@ -59,20 +56,28 @@ struct picture_pool_t {
     vlc_mutex_t lock;
 };
 
-static void Release(picture_pool_t *pool)
+void picture_pool_Release(picture_pool_t *pool)
 {
     bool destroy;
 
     vlc_mutex_lock(&pool->lock);
     assert(pool->refs > 0);
-    destroy = !--pool->refs;
+    destroy = --pool->refs == 0;
     vlc_mutex_unlock(&pool->lock);
 
-    if (!destroy)
+    if (likely(!destroy))
         return;
 
+    for (unsigned i = 0; i < pool->picture_count; i++) {
+        picture_t *picture = pool->picture[i];
+        picture_gc_sys_t *sys = picture->gc.p_sys;
+
+        picture_Release(sys->picture);
+        free(sys);
+        free(picture);
+    }
+
     vlc_mutex_destroy(&pool->lock);
-    free(pool->picture_reserved);
     free(pool->picture);
     free(pool);
 }
@@ -85,15 +90,12 @@ static void picture_pool_ReleasePicture(picture_t *picture)
     if (pool->pic_unlock != NULL)
         pool->pic_unlock(picture);
 
-    if (!atomic_load(&sys->zombie))
-        return;
-
-    /* Picture from an already destroyed pool */
-    picture_Release(sys->picture);
-    free(sys);
-    free(picture);
+    vlc_mutex_lock(&pool->lock);
+    assert(sys->in_use);
+    sys->in_use = false;
+    vlc_mutex_unlock(&pool->lock);
 
-    Release(pool);
+    picture_pool_Release(pool);
 }
 
 static picture_t *picture_pool_ClonePicture(picture_pool_t *pool,
@@ -105,7 +107,7 @@ static picture_t *picture_pool_ClonePicture(picture_pool_t *pool,
 
     sys->pool = pool;
     sys->picture = picture;
-    atomic_init(&sys->zombie, false);
+    sys->in_use = false;
     sys->tick = 0;
 
     picture_resource_t res = {
@@ -128,20 +130,17 @@ static picture_t *picture_pool_ClonePicture(picture_pool_t *pool,
     return clone;
 }
 
-static picture_pool_t *Create(picture_pool_t *master, int picture_count)
+static picture_pool_t *Create(int picture_count)
 {
     picture_pool_t *pool = calloc(1, sizeof(*pool));
     if (!pool)
         return NULL;
 
-    pool->master = master;
-    pool->tick = master ? master->tick : 1;
+    pool->tick = 1;
     pool->picture_count = picture_count;
     pool->picture = calloc(pool->picture_count, sizeof(*pool->picture));
-    pool->picture_reserved = calloc(pool->picture_count, sizeof(*pool->picture_reserved));
-    if (!pool->picture || !pool->picture_reserved) {
+    if (!pool->picture) {
         free(pool->picture);
-        free(pool->picture_reserved);
         free(pool);
         return NULL;
     }
@@ -152,7 +151,7 @@ static picture_pool_t *Create(picture_pool_t *master, int picture_count)
 
 picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg)
 {
-    picture_pool_t *pool = Create(NULL, cfg->picture_count);
+    picture_pool_t *pool = Create(cfg->picture_count);
     if (!pool)
         return NULL;
 
@@ -167,8 +166,6 @@ picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg
         atomic_init(&picture->gc.refcount, 0);
 
         pool->picture[i] = picture;
-        pool->picture_reserved[i] = false;
-        pool->refs++;
     }
     return pool;
 
@@ -211,126 +208,131 @@ error:
 
 picture_pool_t *picture_pool_Reserve(picture_pool_t *master, unsigned count)
 {
-    picture_pool_t *pool = Create(master, count);
-    if (!pool)
-        return NULL;
-
-    pool->pic_lock   = master->pic_lock;
-    pool->pic_unlock = master->pic_unlock;
+    picture_t *picture[count ? count : 1];
+    unsigned i;
 
-    unsigned found = 0;
-    for (unsigned i = 0; i < master->picture_count && found < count; i++) {
-        if (master->picture_reserved[i])
-            continue;
+    for (i = 0; i < count; i++) {
+        picture[i] = picture_pool_Get(master);
+        if (picture[i] == NULL)
+            goto error;
+    }
 
-        assert(atomic_load(&master->picture[i]->gc.refcount) == 0);
-        master->picture_reserved[i] = true;
+    picture_pool_t *pool = picture_pool_New(count, picture);
+    if (!pool)
+        goto error;
 
-        pool->picture[found]          = master->picture[i];
-        pool->picture_reserved[found] = false;
-        found++;
-    }
-    if (found < count) {
-        picture_pool_Delete(pool);
-        return NULL;
-    }
     return pool;
-}
-
-void picture_pool_Delete(picture_pool_t *pool)
-{
-    for (unsigned i = 0; i < pool->picture_count; i++) {
-        picture_t *picture = pool->picture[i];
-        if (pool->master) {
-            for (unsigned j = 0; j < pool->master->picture_count; j++) {
-                if (pool->master->picture[j] == picture)
-                    pool->master->picture_reserved[j] = false;
-            }
-        } else {
-            picture_gc_sys_t *gc_sys = picture->gc.p_sys;
-
-            assert(!pool->picture_reserved[i]);
-
-            /* Restore the initial reference that was cloberred in
-             * picture_pool_NewExtended(). */
-            atomic_fetch_add(&picture->gc.refcount, 1);
-            /* The picture might still locked and then the G.C. state cannot be
-             * modified (w/o memory synchronization). */
-            atomic_store(&gc_sys->zombie, true);
 
-            picture_Release(picture);
-        }
-    }
-    Release(pool);
+error:
+    while (i > 0)
+        picture_Release(picture[--i]);
+    return NULL;
 }
 
 picture_t *picture_pool_Get(picture_pool_t *pool)
 {
-    for (unsigned i = 0; i < pool->picture_count; i++) {
-        if (pool->picture_reserved[i])
-            continue;
+    vlc_mutex_lock(&pool->lock);
+    assert(pool->refs > 0);
 
+    for (unsigned i = 0; i < pool->picture_count; 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;
 
+        pool->refs++;
+        tick = ++pool->tick;
+        sys->in_use = true;
+        vlc_mutex_unlock(&pool->lock);
+
         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--;
             continue;
         }
 
-        /* */
+        sys->tick = tick;
+
+        assert(atomic_load(&picture->gc.refcount) == 0);
+        atomic_init(&picture->gc.refcount, 1);
         picture->p_next = NULL;
-        picture->gc.p_sys->tick = pool->tick++;
         return picture;
     }
+
+    vlc_mutex_unlock(&pool->lock);
     return NULL;
 }
 
-void picture_pool_Reset(picture_pool_t *pool)
+unsigned picture_pool_Reset(picture_pool_t *pool)
 {
-    for (unsigned i = 0; i < pool->picture_count; i++) {
-        if (pool->picture_reserved[i])
-            continue;
+    unsigned ret = 0;
+retry:
+    vlc_mutex_lock(&pool->lock);
+    assert(pool->refs > 0);
 
+    for (unsigned i = 0; i < pool->picture_count; i++) {
         picture_t *picture = pool->picture[i];
-        if (atomic_load(&picture->gc.refcount) > 0) {
-            if (pool->pic_unlock != NULL)
-                pool->pic_unlock(picture);
+        picture_gc_sys_t *sys = picture->gc.p_sys;
+
+        if (sys->in_use) {
+            vlc_mutex_unlock(&pool->lock);
+            picture_Release(picture);
+            ret++;
+            goto retry;
         }
-        atomic_store(&picture->gc.refcount, 0);
     }
+    vlc_mutex_unlock(&pool->lock);
+
+    return ret;
 }
 
 void picture_pool_NonEmpty(picture_pool_t *pool)
 {
     picture_t *oldest = NULL;
+    uint64_t tick = 0;
 
-    for (unsigned i = 0; i < pool->picture_count; i++) {
-        if (pool->picture_reserved[i])
-            continue;
+    vlc_mutex_lock(&pool->lock);
+    assert(pool->refs > 0);
 
+    for (unsigned i = 0; i < pool->picture_count; 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 */
+        }
 
-        if (oldest == NULL || picture->gc.p_sys->tick < oldest->gc.p_sys->tick)
+        if (picture->gc.p_sys->tick < tick) {
             oldest = picture;
+            tick = picture->gc.p_sys->tick;
+        }
     }
 
-    if (oldest == NULL)
-        return; /* Cannot fix! */
-
-    if (atomic_load(&oldest->gc.refcount) > 0) {
-        if (pool->pic_unlock != NULL)
-            pool->pic_unlock(oldest);
+    if (oldest != NULL) {
+        while (oldest->gc.p_sys->in_use) {
+            vlc_mutex_unlock(&pool->lock);
+            picture_Release(oldest);
+            vlc_mutex_lock(&pool->lock);
+        }
     }
-    atomic_store(&oldest->gc.refcount, 0);
+
+    vlc_mutex_unlock(&pool->lock);
 }
 
-int picture_pool_GetSize(picture_pool_t *pool)
+unsigned picture_pool_GetSize(const picture_pool_t *pool)
 {
     return pool->picture_count;
 }
+
+void picture_pool_Enum(picture_pool_t *pool, void (*cb)(void *, picture_t *),
+                       void *opaque)
+{
+    /* NOTE: So far, the pictures table cannot change after the pool is created
+     * so there is no need to lock the pool mutex here. */
+    for (unsigned i = 0; i < pool->picture_count; i++)
+        cb(opaque, pool->picture[i]);
+}