tbm_surface_queue: notify reset callback in free_flush
[platform/core/uifw/libtbm.git] / src / tbm_surface_queue.c
index 9fc33a5..ef63887 100644 (file)
@@ -33,13 +33,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #include "tbm_bufmgr_int.h"
 #include "list.h"
+#include <time.h>
 
 #define FREE_QUEUE     1
 #define DIRTY_QUEUE    2
 #define NODE_LIST      4
 
 static tbm_bufmgr g_surf_queue_bufmgr;
-static pthread_mutex_t tbm_surf_queue_lock;
+static pthread_mutex_t tbm_surf_queue_lock = PTHREAD_MUTEX_INITIALIZER;
 void _tbm_surface_queue_mutex_unlock(void);
 
 /* check condition */
@@ -119,6 +120,7 @@ struct _tbm_surface_queue {
        int height;
        int format;
        int queue_size;
+       int flags;
        int num_attached;
 
        queue free_queue;
@@ -152,32 +154,9 @@ struct _tbm_surface_queue {
        unsigned int acquire_sync_count;
 };
 
-static bool
-_tbm_surf_queue_mutex_init(void)
-{
-       static bool tbm_surf_queue_mutex_init = false;
-
-       if (tbm_surf_queue_mutex_init)
-               return true;
-
-       if (pthread_mutex_init(&tbm_surf_queue_lock, NULL)) {
-               TBM_ERR("fail: pthread_mutex_init\n");
-               return false;
-       }
-
-       tbm_surf_queue_mutex_init = true;
-
-       return true;
-}
-
 static void
 _tbm_surf_queue_mutex_lock(void)
 {
-       if (!_tbm_surf_queue_mutex_init()) {
-               TBM_ERR("fail: _tbm_surf_queue_mutex_init\n");
-               return;
-       }
-
        pthread_mutex_lock(&tbm_surf_queue_lock);
 }
 
@@ -225,10 +204,8 @@ _tbm_surface_queue_is_valid(tbm_surface_queue_h surface_queue)
 
        LIST_FOR_EACH_ENTRY(old_data, &g_surf_queue_bufmgr->surf_queue_list,
                                item_link) {
-               if (old_data == surface_queue) {
-                       TBM_TRACE_SURFACE_QUEUE("tbm_surface_queue(%p)\n", surface_queue);
+               if (old_data == surface_queue)
                        return 1;
-               }
        }
 
        TBM_ERR("error: Invalid tbm_surface_queue(%p)\n", surface_queue);
@@ -529,6 +506,34 @@ _tbm_surface_queue_attach(tbm_surface_queue_h surface_queue,
 }
 
 static void
+_tbm_surface_queue_need_attach(tbm_surface_queue_h surface_queue)
+{
+       tbm_surface_h surface;
+
+       if (surface_queue->queue_size == surface_queue->num_attached)
+               return;
+
+       if (surface_queue->alloc_cb) {
+               surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
+
+               /* silent return */
+               if (!surface)
+                       return;
+
+               tbm_surface_internal_ref(surface);
+       } else {
+               surface = tbm_surface_internal_create_with_flags(surface_queue->width,
+                               surface_queue->height,
+                               surface_queue->format,
+                               surface_queue->flags);
+               TBM_RETURN_IF_FAIL(surface != NULL);
+       }
+
+       _tbm_surface_queue_attach(surface_queue, surface);
+       tbm_surface_internal_unref(surface);
+}
+
+static void
 _tbm_surface_queue_detach(tbm_surface_queue_h surface_queue,
                          tbm_surface_h surface)
 {
@@ -588,9 +593,11 @@ _tbm_surface_queue_release(tbm_surface_queue_h surface_queue,
 static void
 _tbm_surface_queue_init(tbm_surface_queue_h surface_queue,
                        int queue_size,
-                       int width, int height, int format,
+                       int width, int height, int format, int flags,
                        const tbm_surface_queue_interface *impl, void *data)
 {
+       pthread_condattr_t free_attr, dirty_attr;
+
        TBM_RETURN_IF_FAIL(surface_queue != NULL);
        TBM_RETURN_IF_FAIL(impl != NULL);
 
@@ -598,13 +605,22 @@ _tbm_surface_queue_init(tbm_surface_queue_h surface_queue,
                _init_tbm_surf_queue_bufmgr();
 
        pthread_mutex_init(&surface_queue->lock, NULL);
-       pthread_cond_init(&surface_queue->free_cond, NULL);
-       pthread_cond_init(&surface_queue->dirty_cond, NULL);
+
+       pthread_condattr_init(&free_attr);
+       pthread_condattr_setclock(&free_attr, CLOCK_MONOTONIC);
+       pthread_cond_init(&surface_queue->free_cond, &free_attr);
+       pthread_condattr_destroy(&free_attr);
+
+       pthread_condattr_init(&dirty_attr);
+       pthread_condattr_setclock(&dirty_attr, CLOCK_MONOTONIC);
+       pthread_cond_init(&surface_queue->dirty_cond, &dirty_attr);
+       pthread_condattr_destroy(&dirty_attr);
 
        surface_queue->queue_size = queue_size;
        surface_queue->width = width;
        surface_queue->height = height;
        surface_queue->format = format;
+       surface_queue->flags = flags;
        surface_queue->impl = impl;
        surface_queue->impl_data = data;
        surface_queue->modes = TBM_SURFACE_QUEUE_MODE_NONE;
@@ -1267,14 +1283,8 @@ tbm_surface_queue_dequeue(tbm_surface_queue_h
        if (_queue_is_empty(&surface_queue->free_queue)) {
                if (surface_queue->impl && surface_queue->impl->need_attach)
                        surface_queue->impl->need_attach(surface_queue);
-
-               if (!_tbm_surface_queue_is_valid(surface_queue)) {
-                       TBM_ERR("surface_queue:%p is invalid", surface_queue);
-                       _tbm_set_last_result(TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
-                       pthread_mutex_unlock(&surface_queue->lock);
-                       _tbm_surf_queue_mutex_unlock();
-                       return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
-               }
+               else
+                       _tbm_surface_queue_need_attach(surface_queue);
        }
 
        if (surface_queue->impl && surface_queue->impl->dequeue)
@@ -1307,6 +1317,82 @@ tbm_surface_queue_dequeue(tbm_surface_queue_h
        return TBM_SURFACE_QUEUE_ERROR_NONE;
 }
 
+tbm_surface_queue_error_e
+tbm_surface_queue_can_dequeue_wait_timeout(tbm_surface_queue_h surface_queue, int ms_timeout)
+{
+       int ret;
+       struct timespec tp;
+
+       _tbm_surf_queue_mutex_lock();
+       _tbm_set_last_result(TBM_ERROR_NONE);
+
+       TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
+                                                                         TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
+
+       _tbm_surf_queue_mutex_unlock();
+
+       _notify_emit(surface_queue, &surface_queue->can_dequeue_noti);
+
+       _tbm_surf_queue_mutex_lock();
+
+       TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
+                                                                         TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
+
+       pthread_mutex_lock(&surface_queue->lock);
+
+       TBM_TRACE_SURFACE_QUEUE("tbm_surface_queue(%p)\n", surface_queue);
+
+       if (_queue_is_empty(&surface_queue->free_queue)) {
+               if (surface_queue->impl && surface_queue->impl->need_attach)
+                       surface_queue->impl->need_attach(surface_queue);
+               else
+                       _tbm_surface_queue_need_attach(surface_queue);
+       }
+
+       if (!_queue_is_empty(&surface_queue->free_queue)) {
+               pthread_mutex_unlock(&surface_queue->lock);
+               _tbm_surf_queue_mutex_unlock();
+               return TBM_SURFACE_QUEUE_ERROR_NONE;
+       }
+
+       _tbm_surf_queue_mutex_unlock();
+
+       while (1) {
+               clock_gettime(CLOCK_MONOTONIC, &tp);
+
+               if (ms_timeout > 1000)
+                       tp.tv_sec += ms_timeout / 1000;
+
+               tp.tv_nsec += (ms_timeout % 1000) * 1000000;
+
+               if (tp.tv_nsec > 1000000000L) {
+                       tp.tv_sec++;
+                       tp.tv_nsec -= 1000000000L;
+               }
+
+               ret = pthread_cond_timedwait(&surface_queue->free_cond, &surface_queue->lock, &tp);
+               if (ret) {
+                       if (ret == ETIMEDOUT) {
+                               TBM_ERR("surface_queue:%p can dequeue wait timeout", surface_queue);
+                               pthread_mutex_unlock(&surface_queue->lock);
+                               return TBM_SURFACE_QUEUE_ERROR_TIMEOUT;
+                       } else {
+                               TBM_INFO("surface_queue:%p timedwait error retry wait", surface_queue);
+                       }
+               } else {
+                       if (surface_queue->impl && surface_queue->impl->need_attach)
+                               surface_queue->impl->need_attach(surface_queue);
+                       else
+                               _tbm_surface_queue_need_attach(surface_queue);
+
+                       if (!_queue_is_empty(&surface_queue->free_queue)) {
+                               pthread_mutex_unlock(&surface_queue->lock);
+                               return TBM_SURFACE_QUEUE_ERROR_NONE;
+                       }
+               }
+       }
+}
+
 int
 tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
 {
@@ -1330,13 +1416,8 @@ tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
        if (_queue_is_empty(&surface_queue->free_queue)) {
                if (surface_queue->impl && surface_queue->impl->need_attach)
                        surface_queue->impl->need_attach(surface_queue);
-
-               if (!_tbm_surface_queue_is_valid(surface_queue)) {
-                       TBM_ERR("surface_queue:%p is invalid", surface_queue);
-                       pthread_mutex_unlock(&surface_queue->lock);
-                       _tbm_surf_queue_mutex_unlock();
-                       return 0;
-               }
+               else
+                       _tbm_surface_queue_need_attach(surface_queue);
        }
 
        if (!_queue_is_empty(&surface_queue->free_queue)) {
@@ -1347,9 +1428,19 @@ tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
 
        if (wait) {
                _tbm_surf_queue_mutex_unlock();
-               pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
-               pthread_mutex_unlock(&surface_queue->lock);
-               return 1;
+               while (1) {
+                       pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
+
+                       if (surface_queue->impl && surface_queue->impl->need_attach)
+                               surface_queue->impl->need_attach(surface_queue);
+                       else
+                               _tbm_surface_queue_need_attach(surface_queue);
+
+                       if (!_queue_is_empty(&surface_queue->free_queue)) {
+                               pthread_mutex_unlock(&surface_queue->lock);
+                               return 1;
+                       }
+               }
        }
 
        pthread_mutex_unlock(&surface_queue->lock);
@@ -1834,6 +1925,7 @@ tbm_surface_queue_error_e
 tbm_surface_queue_free_flush(tbm_surface_queue_h surface_queue)
 {
        queue_node *node = NULL;
+       int is_guarantee_cycle = 0;
 
        _tbm_surf_queue_mutex_lock();
        _tbm_set_last_result(TBM_ERROR_NONE);
@@ -1861,9 +1953,15 @@ tbm_surface_queue_free_flush(tbm_surface_queue_h surface_queue)
        /* Reset queue */
        _queue_init(&surface_queue->free_queue);
 
+       if (surface_queue->modes & TBM_SURFACE_QUEUE_MODE_GUARANTEE_CYCLE)
+               is_guarantee_cycle = 1;
+
        pthread_mutex_unlock(&surface_queue->lock);
        _tbm_surf_queue_mutex_unlock();
 
+       if (is_guarantee_cycle)
+               _notify_emit(surface_queue, &surface_queue->reset_noti);
+
        return TBM_SURFACE_QUEUE_ERROR_NONE;
 }
 
@@ -1955,6 +2053,37 @@ tbm_surface_queue_get_surfaces(tbm_surface_queue_h surface_queue,
 }
 
 tbm_surface_queue_error_e
+tbm_surface_queue_get_acquirable_surfaces(tbm_surface_queue_h surface_queue,
+                       tbm_surface_h *surfaces, int *num)
+{
+       queue_node *node = NULL;
+
+       _tbm_surf_queue_mutex_lock();
+
+       *num = 0;
+
+       TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
+                              TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
+       TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(num != NULL,
+                              TBM_ERROR_INVALID_PARAMETER);
+
+       pthread_mutex_lock(&surface_queue->lock);
+
+       LIST_FOR_EACH_ENTRY(node, &surface_queue->dirty_queue.head, item_link) {
+               if (surfaces)
+                       surfaces[*num] = node->surface;
+
+               *num = *num + 1;
+       }
+
+       pthread_mutex_unlock(&surface_queue->lock);
+
+       _tbm_surf_queue_mutex_unlock();
+
+       return TBM_SURFACE_QUEUE_ERROR_NONE;
+}
+
+tbm_surface_queue_error_e
 tbm_surface_queue_get_trace_surface_num(
                        tbm_surface_queue_h surface_queue, tbm_surface_queue_trace trace, int *num)
 {
@@ -1997,54 +2126,11 @@ tbm_surface_queue_get_trace_surface_num(
        return TBM_SURFACE_QUEUE_ERROR_NONE;
 }
 
-typedef struct {
-       int flags;
-} tbm_queue_default;
-
-static void
-__tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
-{
-       free(surface_queue->impl_data);
-}
-
-static void
-__tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
-{
-       tbm_queue_default *data = (tbm_queue_default *)surface_queue->impl_data;
-       tbm_surface_h surface;
-
-       if (surface_queue->queue_size == surface_queue->num_attached)
-               return;
-
-       if (surface_queue->alloc_cb) {
-               pthread_mutex_unlock(&surface_queue->lock);
-               _tbm_surf_queue_mutex_unlock();
-               surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
-               _tbm_surf_queue_mutex_lock();
-               pthread_mutex_lock(&surface_queue->lock);
-
-               /* silent return */
-               if (!surface)
-                       return;
-
-               tbm_surface_internal_ref(surface);
-       } else {
-               surface = tbm_surface_internal_create_with_flags(surface_queue->width,
-                               surface_queue->height,
-                               surface_queue->format,
-                               data->flags);
-               TBM_RETURN_IF_FAIL(surface != NULL);
-       }
-
-       _tbm_surface_queue_attach(surface_queue, surface);
-       tbm_surface_internal_unref(surface);
-}
-
 static const tbm_surface_queue_interface tbm_queue_default_impl = {
        NULL,                           /*__tbm_queue_default_init*/
        NULL,                           /*__tbm_queue_default_reset*/
-       __tbm_queue_default_destroy,
-       __tbm_queue_default_need_attach,
+       NULL,                           /*__tbm_queue_default_destroy*/
+       NULL,                           /*__tbm_queue_default_need_attach*/
        NULL,                           /*__tbm_queue_default_enqueue*/
        NULL,                           /*__tbm_queue_default_release*/
        NULL,                           /*__tbm_queue_default_dequeue*/
@@ -2075,21 +2161,10 @@ tbm_surface_queue_create(int queue_size, int width,
 
        TBM_TRACE_SURFACE_QUEUE("tbm_surface_queue(%p)\n", surface_queue);
 
-       tbm_queue_default *data = (tbm_queue_default *) calloc(1,
-                                 sizeof(tbm_queue_default));
-       if (data == NULL) {
-               TBM_ERR("cannot allocate the tbm_queue_default.\n");
-               _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
-               free(surface_queue);
-               _tbm_surf_queue_mutex_unlock();
-               return NULL;
-       }
-
-       data->flags = flags;
        _tbm_surface_queue_init(surface_queue,
                                queue_size,
-                               width, height, format,
-                               &tbm_queue_default_impl, data);
+                               width, height, format, flags,
+                               &tbm_queue_default_impl, NULL);
 
        _tbm_surf_queue_mutex_unlock();
 
@@ -2097,7 +2172,6 @@ tbm_surface_queue_create(int queue_size, int width,
 }
 
 typedef struct {
-       int flags;
        queue dequeue_list;
 } tbm_queue_sequence;
 
@@ -2127,39 +2201,6 @@ __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
 }
 
 static void
-__tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
-{
-       tbm_queue_sequence *data = (tbm_queue_sequence *)surface_queue->impl_data;
-       tbm_surface_h surface;
-
-       if (surface_queue->queue_size == surface_queue->num_attached)
-               return;
-
-       if (surface_queue->alloc_cb) {
-               pthread_mutex_unlock(&surface_queue->lock);
-               _tbm_surf_queue_mutex_unlock();
-               surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
-               _tbm_surf_queue_mutex_lock();
-               pthread_mutex_lock(&surface_queue->lock);
-
-               /* silent return */
-               if (!surface)
-                       return;
-
-               tbm_surface_internal_ref(surface);
-       } else {
-               surface = tbm_surface_internal_create_with_flags(surface_queue->width,
-                               surface_queue->height,
-                               surface_queue->format,
-                               data->flags);
-               TBM_RETURN_IF_FAIL(surface != NULL);
-       }
-
-       _tbm_surface_queue_attach(surface_queue, surface);
-       tbm_surface_internal_unref(surface);
-}
-
-static void
 __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue,
                             queue_node *node)
 {
@@ -2211,7 +2252,7 @@ static const tbm_surface_queue_interface tbm_queue_sequence_impl = {
        __tbm_queue_sequence_init,
        __tbm_queue_sequence_reset,
        __tbm_queue_sequence_destroy,
-       __tbm_queue_sequence_need_attach,
+       NULL,
        __tbm_queue_sequence_enqueue,
        __tbm_queue_sequence_release,
        __tbm_queue_sequence_dequeue,
@@ -2252,10 +2293,9 @@ tbm_surface_queue_sequence_create(int queue_size, int width,
                return NULL;
        }
 
-       data->flags = flags;
        _tbm_surface_queue_init(surface_queue,
                                queue_size,
-                               width, height, format,
+                               width, height, format, flags,
                                &tbm_queue_sequence_impl, data);
 
        _tbm_surf_queue_mutex_unlock();