run image loader in separate thread
authorVladimir Nadvornik <nadvornik@suse.cz>
Sat, 30 Aug 2008 20:15:47 +0000 (20:15 +0000)
committerVladimir Nadvornik <nadvornik@suse.cz>
Sat, 30 Aug 2008 20:15:47 +0000 (20:15 +0000)
this feature is disabled by default for now, it must be enabled by
configure --enable-threads

configure.in
src/Makefile.am
src/image-load.c
src/image-load.h
src/main.c

index 02ca947..3a3afa4 100644 (file)
@@ -167,21 +167,6 @@ AM_CONDITIONAL(MS_LIB_AVAILABLE, test x$ms_librarian = xyes)
 AM_CONDITIONAL(HAVE_WINDRES, test "x$WINDRES" != "x:")
 AC_SUBST(WINDRES)
 
-have_libpthread=no
-AC_CHECK_LIB([pthread], [main],
-  [AC_CHECK_HEADER([pthread.h],
-     have_libpthread=yes,
-     have_libpthread=no)],
-  [AC_MSG_ERROR([Can't find the POSIX thread libraries])], [-lpthread])
-if test "x${have_libpthread}" = "xyes"; then
-        LIBPTHREAD='-lpthread'
-        AC_DEFINE(HAVE_LIBPTHREAD, 1, [Define if pthread is available])
-else
-  AC_MSG_WARN([POSIX thread header not installed])
-fi
-AC_MSG_CHECKING(for libpthread)
-AC_MSG_RESULT([${have_libpthread}])
-
 dnl reasonable guesses for where stuff is installed
 if test "x$prefix" = "xNONE"; then
   prefix="/usr/local"
@@ -189,7 +174,26 @@ else
   prefix=$prefix
 fi
 
+AM_PATH_GLIB_2_0(2.4.0,,AC_MSG_ERROR(GLIB >= 2.4.0 not installed.))
 AM_PATH_GTK_2_0(2.4.0,,AC_MSG_ERROR(GTK+ >= 2.4.0 not installed.))
+
+have_gthread="no"
+AC_ARG_ENABLE([threads],
+  AC_HELP_STRING([--enable-threads], [enable thread support]),
+[
+if test "x${enableval}" = "xyes"; then
+  PKG_CHECK_MODULES(GTHREAD, [gthread-2.0], have_gthread="yes", [AC_MSG_WARN("No thread support in glib")])
+fi
+], )
+
+
+if test "x$have_gthread" != "xno"; then
+        AC_DEFINE(HAVE_GTHREAD, 1, Define if you have gthread library)
+        GLIB_CFLAGS="$GTHREAD_CFLAGS"
+        GLIB_LIBS="$GTHREAD_LIBS"
+fi
+
+
 AC_PATH_PROGS(GDK_PIXBUF_CSOURCE, "gdk-pixbuf-csource")
 AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
 
@@ -376,7 +380,7 @@ Flags:
   CXXFLAGS:      $CXXFLAGS
   Gtk:           $GTK_CFLAGS
   Glib:          $GLIB_CFLAGS
-  Thread:        $LIBPTHREAD
+  Thread:        $GTHREAD_LIBS
   Others:       $LCMS_LIBS $EXIV2_LIBS
 
 Localization:
index 8a76c3e..ae9e644 100644 (file)
@@ -123,6 +123,7 @@ geeqie_SOURCES = \
        filefilter.h    \
        gq-marshal.c    \
        gq-marshal.h    \
+       gq-marshal.list \
        format_canon.c  \
        format_canon.h  \
        format_fuji.c   \
index db1bce9..7d2eeaa 100644 (file)
@@ -85,6 +85,10 @@ static void image_loader_init (GTypeInstance *instance, gpointer g_class)
        il->requested_width = 0;
        il->requested_height = 0;
        il->shrunk = FALSE;
+
+#ifdef HAVE_GTHREAD
+       il->data_mutex = g_mutex_new();
+#endif
        DEBUG_1("new image loader %p, bufsize=%u idle_loop=%u", il, il->read_buffer_size, il->idle_read_loop_count);
 }
 
@@ -167,6 +171,9 @@ static void image_loader_finalize(GObject *object)
 
        if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf);
        file_data_unref(il->fd);
+#ifdef HAVE_GTHREAD
+       g_mutex_free(il->data_mutex);
+#endif
 }
 
 void image_loader_free(ImageLoader *il)
@@ -207,8 +214,10 @@ static gint image_loader_emit_area_ready_cb(gpointer data)
        ImageLoaderAreaParam *par = data;
        ImageLoader *il = par->il;
        g_signal_emit(il, signals[SIGNAL_AREA_READY], 0, par->x, par->y, par->w, par->h);
+       g_mutex_lock(il->data_mutex);
        il->area_param_list = g_list_remove(il->area_param_list, par);
        g_free(par);
+       g_mutex_unlock(il->data_mutex);
        
        return FALSE;
 }
@@ -230,7 +239,7 @@ static gint image_loader_emit_error_cb(gpointer data)
 static gint image_loader_emit_percent_cb(gpointer data)
 {
        ImageLoader *il = data;
-       g_signal_emit(il, signals[SIGNAL_PERCENT], 0, (gdouble)il->bytes_read / il->bytes_total);
+       g_signal_emit(il, signals[SIGNAL_PERCENT], 0, image_loader_get_percent(il));
        return FALSE;
 }
 
@@ -262,7 +271,10 @@ static void image_loader_emit_area_ready(ImageLoader *il, guint x, guint y, guin
        par->w = w;
        par->h = h;
        
+       g_mutex_lock(il->data_mutex);
        il->area_param_list = g_list_prepend(il->area_param_list, par);
+       g_mutex_unlock(il->data_mutex);
+       
        g_idle_add_full(G_PRIORITY_HIGH, image_loader_emit_area_ready_cb, par, NULL);
 }
 
@@ -272,16 +284,27 @@ static void image_loader_emit_area_ready(ImageLoader *il, guint x, guint y, guin
 static void image_loader_sync_pixbuf(ImageLoader *il)
 {
        GdkPixbuf *pb;
-
-       if (!il->loader) return;
+       
+       g_mutex_lock(il->data_mutex);
+       
+       if (!il->loader) 
+               {
+               g_mutex_unlock(il->data_mutex);
+               return;
+               }
 
        pb = gdk_pixbuf_loader_get_pixbuf(il->loader);
 
-       if (pb == il->pixbuf) return;
+       if (pb == il->pixbuf)
+               {
+               g_mutex_unlock(il->data_mutex);
+               return;
+               }
 
        if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf);
        il->pixbuf = pb;
        if (il->pixbuf) gdk_pixbuf_ref(il->pixbuf);
+       g_mutex_unlock(il->data_mutex);
 }
 
 static void image_loader_area_updated_cb(GdkPixbufLoader *loader,
@@ -290,10 +313,10 @@ static void image_loader_area_updated_cb(GdkPixbufLoader *loader,
 {
        ImageLoader *il = data;
 
-       if (!il->pixbuf)
+       if (!image_loader_get_pixbuf(il))
                {
                image_loader_sync_pixbuf(il);
-               if (!il->pixbuf)
+               if (!image_loader_get_pixbuf(il))
                        {
                        log_printf("critical: area_ready signal with NULL pixbuf (out of mem?)\n");
                        }
@@ -336,7 +359,13 @@ static void image_loader_size_cb(GdkPixbufLoader *loader,
        gint scale = FALSE;
        gint n;
 
-       if (il->requested_width < 1 || il->requested_height < 1) return;
+       g_mutex_lock(il->data_mutex);
+       if (il->requested_width < 1 || il->requested_height < 1) 
+               {
+               g_mutex_unlock(il->data_mutex);
+               return;
+               }
+       g_mutex_unlock(il->data_mutex);
 
        format = gdk_pixbuf_loader_get_format(loader);
        if (!format) return;
@@ -352,6 +381,8 @@ static void image_loader_size_cb(GdkPixbufLoader *loader,
 
        if (!scale) return;
 
+       g_mutex_lock(il->data_mutex);
+
        if (width > il->requested_width || height > il->requested_height)
                {
                gint nw, nh;
@@ -372,6 +403,8 @@ static void image_loader_size_cb(GdkPixbufLoader *loader,
                gdk_pixbuf_loader_set_size(loader, nw, nh);
                il->shrunk = TRUE;
                }
+       g_mutex_unlock(il->data_mutex);
+
 }
 
 static void image_loader_stop_loader(ImageLoader *il)
@@ -392,7 +425,10 @@ static void image_loader_stop_loader(ImageLoader *il)
 
 static void image_loader_setup_loader(ImageLoader *il)
 {
+       g_mutex_lock(il->data_mutex);
        il->loader = gdk_pixbuf_loader_new();
+       g_mutex_unlock(il->data_mutex);
+
        g_signal_connect(G_OBJECT(il->loader), "area_updated",
                         G_CALLBACK(image_loader_area_updated_cb), il);
        g_signal_connect(G_OBJECT(il->loader), "size_prepared",
@@ -606,6 +642,11 @@ static void image_loader_stop(ImageLoader *il)
                il->idle_id = -1;
                }
                
+       if (il->thread)
+               {
+               il->stopping = TRUE;
+               g_thread_join(il->thread);
+               }
 
        image_loader_stop_loader(il);
        image_loader_stop_source(il);
@@ -646,6 +687,36 @@ gint image_loader_start_idle(ImageLoader *il)
        return ret;
 }
 
+/**************************************************************************************/
+/* execution via thread */
+
+gpointer image_loader_thread_run(gpointer data)
+{
+       ImageLoader *il = data;
+       gint cont = image_loader_begin(il);
+       
+       while (cont && !il->done && !il->stopping)
+               {
+               cont = image_loader_continue(il);
+               }
+       return NULL;
+}
+
+gint image_loader_start_thread(ImageLoader *il)
+{
+       if (!il) return FALSE;
+
+       if (!il->fd) return FALSE;
+
+       if (!image_loader_setup_source(il)) return FALSE;
+
+       il->thread = g_thread_create(image_loader_thread_run, il, TRUE, NULL);
+       if (!il->thread) return FALSE;
+               
+       return TRUE;
+}
+
+
 /**************************************************************************************/
 /* public interface */
 
@@ -656,16 +727,24 @@ gint image_loader_start(ImageLoader *il)
 
        if (!il->fd) return FALSE;
 
+#ifdef HAVE_GTHREAD
+       return image_loader_start_thread(il);
+#else
        return image_loader_start_idle(il);
+#endif
 }
 
 
 /* don't forget to gdk_pixbuf_ref() it if you want to use it after image_loader_free() */
 GdkPixbuf *image_loader_get_pixbuf(ImageLoader *il)
 {
+       GdkPixbuf *ret;
        if (!il) return NULL;
-
-       return il->pixbuf;
+       
+       g_mutex_lock(il->data_mutex);
+       ret = il->pixbuf;
+       g_mutex_unlock(il->data_mutex);
+       return ret;
 }
 
 gchar *image_loader_get_format(ImageLoader *il)
@@ -693,53 +772,82 @@ void image_loader_set_requested_size(ImageLoader *il, gint width, gint height)
 {
        if (!il) return;
 
+       g_mutex_lock(il->data_mutex);
        il->requested_width = width;
        il->requested_height = height;
+       g_mutex_unlock(il->data_mutex);
 }
 
 void image_loader_set_buffer_size(ImageLoader *il, guint count)
 {
        if (!il) return;
 
+       g_mutex_lock(il->data_mutex);
        il->idle_read_loop_count = count ? count : 1;
+       g_mutex_unlock(il->data_mutex);
 }
 
 void image_loader_set_priority(ImageLoader *il, gint priority)
 {
        if (!il) return;
 
+       g_mutex_lock(il->data_mutex);
        il->idle_priority = priority;
+       g_mutex_unlock(il->data_mutex);
 }
 
 
 gdouble image_loader_get_percent(ImageLoader *il)
 {
-       if (!il || il->bytes_total == 0) return 0.0;
-
-       return (gdouble)il->bytes_read / il->bytes_total;
+       gdouble ret;
+       if (!il) return 0.0;
+       
+       g_mutex_lock(il->data_mutex);
+       if (il->bytes_total == 0) 
+               {
+               ret = 0.0;
+               }
+       else
+               {
+               ret = (gdouble)il->bytes_read / il->bytes_total;
+               }
+       g_mutex_unlock(il->data_mutex);
+       return ret;
 }
 
 gint image_loader_get_is_done(ImageLoader *il)
 {
+       gint ret;
        if (!il) return FALSE;
 
-       return il->done;
+       g_mutex_lock(il->data_mutex);
+       ret = il->done;
+       g_mutex_unlock(il->data_mutex);
+
+       return ret;
 }
 
 FileData *image_loader_get_fd(ImageLoader *il)
 {
+       FileData *ret;
        if (!il) return NULL;
 
-       return il->fd;
-       
+       g_mutex_lock(il->data_mutex);
+       ret = il->fd;
+       g_mutex_unlock(il->data_mutex);
+
+       return ret;
 }
 
 gint image_loader_get_shrunk(ImageLoader *il)
 {
+       gint ret;
        if (!il) return FALSE;
 
-       return il->shrunk;
-       
+       g_mutex_lock(il->data_mutex);
+       ret = il->shrunk;
+       g_mutex_unlock(il->data_mutex);
+       return ret;
 }
 
 
index e09e94b..3b6fb76 100644 (file)
@@ -45,6 +45,10 @@ struct _ImageLoader
 
        gint idle_done_id;
        GList *area_param_list;
+       
+       GThread *thread;
+       GMutex *data_mutex;
+       gint stopping;
 
        guchar *mapped_file;
        gint read_buffer_size;
index 91f5e0a..fed20ee 100644 (file)
@@ -669,6 +669,10 @@ gint main(gint argc, gchar *argv[])
        gchar *bufl;
        CollectionData *cd = NULL;
 
+#ifdef HAVE_GTHREAD
+       g_thread_init (NULL);
+#endif
+       
        /* init execution time counter (debug only) */
        init_exec_time();