ethumb: cleanup API.
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 28 Nov 2011 23:24:32 +0000 (23:24 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 28 Nov 2011 23:24:32 +0000 (23:24 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ethumb@65660 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/Ethumb.c
src/lib/Ethumb.h
src/lib/client/Ethumb_Client.c
src/lib/client/Ethumb_Client.h
src/lib/ethumb_private.h

index c510fdc..ecabe9c 100644 (file)
@@ -787,6 +787,7 @@ ethumb_file_set(Ethumb *e, const char *path, const char *key)
      }
 
    path = _ethumb_build_absolute_path(path, buf);
+   eina_stringshare_replace(&e->src_hash, NULL);
    eina_stringshare_replace(&e->src_path, path);
    eina_stringshare_replace(&e->src_key, key);
 
@@ -949,8 +950,6 @@ static void
 _ethumb_file_generate_path(Ethumb *e)
 {
    char buf[PATH_MAX];
-   char *fullname;
-   const char *hash;
    const char *thumb_dir, *category;
    const char *ext;
    int fdo_format;
@@ -987,10 +986,15 @@ _ethumb_file_generate_path(Ethumb *e)
    else
      ext = "eet";
 
-   fullname = ecore_file_realpath(e->src_path);
-   hash = _ethumb_generate_hash(fullname);
-   snprintf(buf, sizeof(buf), "%s/%s/%s.%s", thumb_dir, category, hash, ext);
-   free(fullname);
+   if (!e->src_hash)
+     {
+       char *fullname;
+
+       fullname = ecore_file_realpath(e->src_path);
+       e->src_hash = _ethumb_generate_hash(fullname);
+       free(fullname);
+     }
+   snprintf(buf, sizeof(buf), "%s/%s/%s.%s", thumb_dir, category, e->src_hash, ext);
    DBG("ethumb=%p, path=%s", e, buf);
    eina_stringshare_replace(&e->thumb_path, buf);
    if (e->format == ETHUMB_THUMB_EET)
@@ -1003,7 +1007,6 @@ _ethumb_file_generate_path(Ethumb *e)
 
    eina_stringshare_del(thumb_dir);
    eina_stringshare_del(category);
-   eina_stringshare_del(hash);
 }
 
 EAPI void
@@ -1012,6 +1015,7 @@ ethumb_file_free(Ethumb *e)
    EINA_SAFETY_ON_NULL_RETURN(e);
    DBG("ethumb=%p", e);
 
+   eina_stringshare_replace(&e->src_hash, NULL);
    eina_stringshare_replace(&e->src_path, NULL);
    eina_stringshare_replace(&e->src_key, NULL);
    eina_stringshare_replace(&e->thumb_path, NULL);
@@ -1050,6 +1054,32 @@ ethumb_thumb_path_get(Ethumb *e, const char **path, const char **key)
    if (key) *key = e->thumb_key;
 }
 
+EAPI void
+ethumb_thumb_hash(Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+   if (!e->src_hash)
+     {
+        char *fullname;
+
+        fullname = ecore_file_realpath(e->src_path);
+        e->src_hash = _ethumb_generate_hash(fullname);
+        free(fullname);
+     }
+}
+
+EAPI void
+ethumb_thumb_hash_copy(Ethumb *dst, const Ethumb *src)
+{
+   EINA_SAFETY_ON_NULL_RETURN(dst);
+   EINA_SAFETY_ON_NULL_RETURN(src);
+
+   if (src == dst) return ;
+
+   eina_stringshare_del(dst->src_hash);
+   dst->src_hash = eina_stringshare_ref(src->src_hash);
+}
+
 void
 ethumb_calculate_aspect_from_ratio(Ethumb *e, float ia, int *w, int *h)
 {
@@ -1602,6 +1632,7 @@ ethumb_dup(const Ethumb *e)
 
    r->thumb_dir = eina_stringshare_ref(e->thumb_dir);
    r->category = eina_stringshare_ref(e->category);
+   r->src_hash = eina_stringshare_ref(e->src_hash);
    r->src_path = eina_stringshare_ref(e->src_path);
    r->src_key = eina_stringshare_ref(e->src_key);
    r->thumb_path = eina_stringshare_ref(e->thumb_path);
@@ -1710,8 +1741,6 @@ ethumb_key_cmp(const void *key1, __UNUSED__ int key1_length,
 
    CMP_PARAM(thumb_dir);
    CMP_PARAM(category);
-   CMP_PARAM(thumb_dir);
-   CMP_PARAM(category);
    CMP_PARAM(tw);
    CMP_PARAM(th);
    CMP_PARAM(format);
index dc7b133..96e7d07 100644 (file)
@@ -98,6 +98,8 @@ EAPI const char  *ethumb_thumb_category_get(const Ethumb *e) EINA_WARN_UNUSED_RE
 
 EAPI void         ethumb_thumb_path_set(Ethumb *e, const char *path, const char *key) EINA_ARG_NONNULL(1);
 EAPI void         ethumb_thumb_path_get(Ethumb *e, const char **path, const char **key) EINA_ARG_NONNULL(1);
+EAPI void         ethumb_thumb_hash(Ethumb *e) EINA_ARG_NONNULL(1);
+EAPI void         ethumb_thumb_hash_copy(Ethumb *dst, const Ethumb *src) EINA_ARG_NONNULL(1, 2);
 
 typedef enum _Ethumb_Thumb_FDO_Size
 {
index a5c01c9..b9d001c 100644 (file)
@@ -168,24 +168,23 @@ struct _ethumb_pending_gen
 };
 
 typedef struct _Ethumb_Async_Exists Ethumb_Async_Exists;
-typedef struct _Ethumb_Async_Exists_Cb Ethumb_Async_Exists_Cb;
 
 struct _Ethumb_Async_Exists
 {
-   Ethumb *dup;
-   Ethumb_Client *source;
+   const char *path;
 
-   Eina_List *callbacks;
+   Ethumb *dup; /* We will work on that one to prevent race and lock */
 
+   Eina_List *callbacks;
    Ecore_Thread *thread;
-   EINA_REFCOUNT;
-
-   Eina_Bool exists : 1;
-   Eina_Bool cancel : 1;
 };
 
-struct _Ethumb_Async_Exists_Cb
+struct _Ethumb_Exists
 {
+   Ethumb_Async_Exists *parent;
+   Ethumb_Client *client;
+   Ethumb *dup; /* We don't want to loose parameters so keep them around */
+
    Ethumb_Client_Thumb_Exists_Cb exists_cb;
    const void *data;
 };
@@ -347,22 +346,16 @@ _ethumb_async_delete(void *data)
 {
    Ethumb_Async_Exists *async = data;
 
-   ethumb_free(async->dup);
+   assert(async->callbacks == NULL);
+   assert(async->thread == NULL);
 
-   EINA_REFCOUNT_UNREF(async->source)
-     _ethumb_client_free(async->source);
+   ethumb_free(async->dup);
+   eina_stringshare_del(async->path);
 
    free(async);
 }
 
 static void
-_ethumb_async_cancel(Ethumb_Async_Exists *async)
-{
-   async->cancel = EINA_TRUE;
-   ecore_thread_cancel(async->thread);
-}
-
-static void
 _ethumb_client_name_owner_changed(void *data, DBusMessage *msg)
 {
    DBusError err;
@@ -599,28 +592,37 @@ _ethumb_client_exists_heavy(void *data, Ecore_Thread *thread __UNUSED__)
 {
    Ethumb_Async_Exists *async = data;
 
-   async->exists = ethumb_exists(async->dup);
+   ethumb_thumb_hash(async->dup);
 }
 
 static void
 _ethumb_client_exists_end(void *data, Ecore_Thread *thread __UNUSED__)
 {
    Ethumb_Async_Exists *async = data;
-   Ethumb_Async_Exists_Cb *cb;
-   Ethumb *tmp = async->source->ethumb;
-
-   async->source->ethumb = async->dup;
+   Ethumb_Exists *cb;
 
    EINA_LIST_FREE(async->callbacks, cb)
      {
-       cb->exists_cb(async->source, (Ethumb_Exists*) async, async->exists, (void*) cb->data);
-       free(cb);
+        Ethumb *tmp;
+
+        ethumb_thumb_hash_copy(cb->dup, async->dup);
+        tmp = cb->client->ethumb;
+        cb->client->ethumb = cb->dup;
+
+        cb->exists_cb(cb->client, cb,
+                      ethumb_exists(cb->client->ethumb),
+                      (void*) cb->data);
+
+        cb->client->ethumb = tmp;
+        EINA_REFCOUNT_UNREF(cb->client)
+          _ethumb_client_free(cb->client);
+        ethumb_free(cb->dup);
+        free(cb);
      }
 
-   async->source->ethumb = tmp;
    async->thread = NULL;
 
-   eina_hash_del(_exists_request, async->dup, async);
+   eina_hash_del(_exists_request, async->path, async);
 }
 
 /**
@@ -666,11 +668,7 @@ ethumb_client_init(void)
    ethumb_init();
    e_dbus_init();
 
-   _exists_request = eina_hash_new(ethumb_length,
-                                   ethumb_key_cmp,
-                                   ethumb_hash,
-                                   _ethumb_async_delete,
-                                   3);
+   _exists_request = eina_hash_stringshared_new(_ethumb_async_delete);
 
    return ++_initcount;
 }
@@ -699,6 +697,8 @@ ethumb_client_shutdown(void)
      return _initcount;
 
    /* should find a non racy solution to closing all pending exists request */
+   eina_hash_free(_exists_request);
+   _exists_request = NULL;
 
    e_dbus_shutdown();
    ethumb_shutdown();
@@ -2162,57 +2162,81 @@ ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const cha
 EAPI Ethumb_Exists *
 ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data)
 {
-   Ethumb_Async_Exists_Cb *cb;
-   Ethumb_Async_Exists *async;
+   const char *path = NULL;
+   Ethumb_Async_Exists *async = NULL;
+   Ethumb_Exists *cb = NULL;
    Ecore_Thread *t;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);
 
-   cb = malloc(sizeof (Ethumb_Async_Exists_Cb));
-   if (!cb)
+   ethumb_file_get(client->ethumb, &path, NULL);
+   if (!path) goto on_error;
+
+   async = eina_hash_find(_exists_request, path);
+   if (!async)
      {
-        exists_cb(client, NULL, EINA_FALSE, (void*) data);
-        return NULL;
-     }
+        async = malloc(sizeof (Ethumb_Async_Exists));
+        if (!async) goto on_error;
 
-   cb->exists_cb = exists_cb;
-   cb->data = data;
+        async->path = eina_stringshare_ref(path);
+        async->callbacks = NULL;
+        async->dup = ethumb_dup(client->ethumb);
+
+        if (!async->dup) goto on_error;
+
+        cb = malloc(sizeof (Ethumb_Exists));
+        if (!cb) goto on_error;
+
+        EINA_REFCOUNT_REF(client);
+        cb->client = client;
+        cb->dup = ethumb_dup(client->ethumb);
+        cb->exists_cb = exists_cb;
+        cb->data = data;
+        cb->parent = async;
 
-   async = eina_hash_find(_exists_request, client->ethumb);
-   if (async)
-     {
-        EINA_REFCOUNT_REF(async);
         async->callbacks = eina_list_append(async->callbacks, cb);
-        return (Ethumb_Exists*) async;
+
+        /* spawn a thread here */
+        t = ecore_thread_run(_ethumb_client_exists_heavy,
+                             _ethumb_client_exists_end,
+                             _ethumb_client_exists_end,
+                             async);
+        if (!t) return NULL;
+        async->thread = t;
+
+        eina_hash_direct_add(_exists_request, async->path, async);
+
+        return cb;
      }
 
-   async = malloc(sizeof (Ethumb_Async_Exists));
-   if (!async)
+   cb = malloc(sizeof (Ethumb_Exists));
+   if (!cb)
      {
-        free(cb);
-        exists_cb(client, NULL, EINA_FALSE, (void*) data);
-        return NULL;
+        async = NULL;
+        goto on_error;
      }
 
-   async->dup = ethumb_dup(client->ethumb);
-   async->source = client;
-   EINA_REFCOUNT_REF(async->source);
-   async->exists = EINA_FALSE;
-   async->cancel = EINA_FALSE;
+   EINA_REFCOUNT_REF(client);
+   cb->client = client;
+   cb->dup = ethumb_dup(client->ethumb);
+   cb->exists_cb = exists_cb;
+   cb->data = data;
+   cb->parent = async;
 
-   async->callbacks = eina_list_append(NULL, cb);
+   async->callbacks = eina_list_append(async->callbacks, cb);
 
-   EINA_REFCOUNT_INIT(async);
-   t = ecore_thread_run(_ethumb_client_exists_heavy,
-                       _ethumb_client_exists_end,
-                       _ethumb_client_exists_end,
-                       async);
-   if (!t) return NULL;
+   return cb;
 
-   async->thread = t;
-   eina_hash_direct_add(_exists_request, async->dup, async);
+ on_error:
+   exists_cb(client, NULL, EINA_FALSE, (void*) data);
 
-   return (Ethumb_Exists*) async;
+   if (async)
+     {
+        eina_stringshare_del(async->path);
+        if (async->dup) ethumb_free(async->dup);
+        free(async);
+     }
+   return NULL;
 }
 
 /**
@@ -2221,22 +2245,18 @@ ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb
  * @param exists the request to cancel.
  */
 EAPI void
-ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data)
+ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists)
 {
-   Ethumb_Async_Exists_Cb *cb;
-   Ethumb_Async_Exists *async = (Ethumb_Async_Exists*) exists;
-   Eina_List *l;
+   Ethumb_Async_Exists *async = exists->parent;
 
-   EINA_LIST_FOREACH(async->callbacks, l, cb)
-     if (cb->exists_cb == exists_cb && cb->data == data)
-       {
-          async->callbacks = eina_list_remove_list(async->callbacks, l);
-         free(cb);
-          break;
-       }
+   async->callbacks = eina_list_remove(async->callbacks, exists);
+   if (eina_list_count(async->callbacks) <= 0)
+     ecore_thread_cancel(async->thread);
 
-   EINA_REFCOUNT_UNREF(async)
-     _ethumb_async_cancel(async);
+   ethumb_free(exists->dup);
+   EINA_REFCOUNT_UNREF(exists->client)
+     _ethumb_client_free(exists->client);
+   free(exists);
 }
 
 /**
@@ -2248,11 +2268,11 @@ ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists, Ethumb_Client_Thumb_Exi
 EAPI Eina_Bool
 ethumb_client_thumb_exists_check(Ethumb_Exists *exists)
 {
-   Ethumb_Async_Exists *async = (Ethumb_Async_Exists*) exists;
+   Ethumb_Async_Exists *async = exists->parent;
 
    if (!async) return EINA_TRUE;
 
-   if (async->callbacks || async->cancel) return EINA_FALSE;
+   if (async->callbacks) return EINA_FALSE;
 
    return ecore_thread_check(async->thread);
 }
index 6087277..e105693 100644 (file)
@@ -195,7 +195,7 @@ EAPI void ethumb_client_file_get(Ethumb_Client *client, const char **path, const
 EAPI void ethumb_client_file_free(Ethumb_Client *client);
 
 EAPI Ethumb_Exists *ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data);
-EAPI void ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data);
+EAPI void ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists);
 EAPI Eina_Bool ethumb_client_thumb_exists_check(Ethumb_Exists *exists);
 EAPI int  ethumb_client_generate(Ethumb_Client *client, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data);
 EAPI void ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Generate_Cancel_Cb cancel_cb, const void *data, Eina_Free_Cb free_data);
index 873b979..25f2cd3 100644 (file)
@@ -24,6 +24,7 @@ struct _Ethumb
    float crop_x, crop_y;
    int quality;
    int compress;
+   const char *src_hash;
    const char *src_path;
    const char *src_key;
    const char *thumb_path;